Search code examples
djangodjango-modelsdjango-viewsdjango-testingdjango-users

Why is the page I am testing returning a 301 response instead of a 200 response?


I am writing tests for class-based views in the django project I am writing as part of a course. Currently, I am stuck trying trying to test a view that directs to an edit page that requires a user to be logged in. The item being edited must also have been created by that user in the first place, of course.

In the test itself, I instantiate a model and a user, and then log the user in, before trying to get the edit page. I expect the response to have a status code of 200, but it keeps coming back as a 301. Code below:

urls.py - path for the edit page:

path('edit/<slug:slug>/', views.EditBulletin.as_view(), name='edit'),

models.py - the model being instantiated:

class Bulletin(models.Model):
    title = models.CharField(max_length=40, unique=True)
    slug = models.SlugField(max_length=40, unique=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE, 
                               related_name='bulletins')
    content = models.TextField()
    link = models.URLField()
    created_on = models.DateTimeField(auto_now_add=True)
    status = models.IntegerField(choices=STATUS, default=0)
    likes = models.ManyToManyField(User, related_name='bulletin_likes')
    edited = models.BooleanField(default=False)
    updated_on = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-created_on']

    def __str__(self):
        return self.title

    def number_of_likes(self):
        return self.likes.count()

views.py - the get method in the view for the edit page:

class EditBulletin(View):
    def get(self, request, slug, *args, **kwargs):
        queryset = Bulletin.objects.filter(status=1)
        bulletin = get_object_or_404(queryset, slug=slug, author=request.user)

        bulletin_form = BulletinForm(instance=bulletin)

        return render(
            request,
            'edit_bulletin.html',
            {
                'bulletin_form': bulletin_form,
                'bulletin': bulletin,
                'original_url_query': request.GET.get('query'),
            },
        )

test_views.py - the setUpClass method and the edit page test (both within class TestViews(TestCase):):

@classmethod
def setUpClass(cls):
    cls.user_1 = User.objects.create_user(username='test_user',
                                          password='test')

def test_get_edit_bulletin_page(self):
    bulletin_title = 'New Bulletin'
    title_slug = slugify(bulletin_title)

    self.client.login(username=self.user_1.username,
                      password=self.user_1.password)

    bulletin = Bulletin.objects.create(title=bulletin_title,
                                       slug=title_slug,
                                       author=self.user_1,
                                       content='This is a test bulletin.',
                                       link='https://www.google.ie/',
                                       edited=False)

    response = self.client.get(f'/edit/{bulletin.slug}')

    self.assertEqual(response.status_code, 200)
    self.assertTemplateUsed(response, 'edit_bulletin.html')

I tried using self.client.force_login, and it didn't work, but I'm not sure if I was using it correctly.

I also tried unsuccessfully to initialise the many-to-many "likes" field during the instantiation of the Bulletin object, because I know that in the admin panel, I can't approve a Bulletin without providing a value for "likes", i.e. a user who has liked it. Again though, I'm not sure if I was doing it properly.

I'm confused as to why a 301 is being returned. I know that if you enter an edit url corresponding to a bulletin that you did not create, it shows a 404 page. Or, at least, with DEBUG set to True, it displays an error page.

Finally, just in case it isn't already obvious, I should add that I'm a newbie. So if there's anything really stupid jumping out at you above, please be gentle!


Solution

  • When you create your user you are setting the password via a text string. However, this password is hashed before it is stored in user.password

    When you then try and login with user.password, which is the stored, hashed password, the password provided is hashed again before comparison. This will fail and may be causing the redirect.

    Try

    self.client.login(username=self.user_1.username,
                          password="test")