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!
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")