You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django类视图测试:编辑页返回301而非200的问题排查

Django编辑页视图测试返回301状态码问题排查

问题说明

在课程项目中为Django类视图编写测试,编辑页要求用户登录且待编辑内容为该用户创建。测试时已实例化模型和用户,登录后请求编辑页,预期响应状态码200,但始终返回301。

相关代码

urls.py - 编辑页路径

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

models.py - Bulletin模型

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 - EditBulletin视图get方法

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 - 测试代码

@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')

已尝试的操作

  • 使用self.client.force_login,未解决问题
  • 尝试初始化Bulletin的likes多对多字段,未解决问题

问题原因及修复方案

1. URL末尾缺少斜杠导致301重定向

urls.py中编辑页路径末尾带有斜杠('edit/<slug:slug>/'),但测试中请求的URL是'/edit/{bulletin.slug}',末尾无斜杠。Django默认开启APPEND_SLASH设置,会自动将无斜杠的URL重定向到带斜杠的版本,因此返回301。

修复:请求URL添加末尾斜杠:

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

2. 登录密码错误

User.objects.create_user会自动哈希存储密码,self.user_1.password是哈希后的字符串,而非明文的'test'。测试中用哈希值登录会失败,导致用户未真正登录。

修复:登录时直接使用明文密码:

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

3. Bulletin状态不匹配导致404

视图中查询集是Bulletin.objects.filter(status=1),但模型中status默认值为0,测试创建的Bulletin未指定status,因此不符合查询条件,即使URL正确也会返回404。

修复:创建Bulletin时指定status为1:

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,
                                   status=1)

修复后的完整测试代码

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='test')

    # 创建status为1的Bulletin
    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,
                                       status=1)

    # 请求带末尾斜杠的URL
    response = self.client.get(f'/edit/{bulletin.slug}/')

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

内容的提问来源于stack exchange,提问作者ClubShrimp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 04:07:02