首页 > 解决方案 > 从 int:pk 更改为 Slug

问题描述

在完成我的博客项目后,我找到了一种方法,从写博客的 id 到写一个函数来添加帖子标题成为一个 slug。

因此,我目前正在尝试将所有帖子详细信息切换为 slug,但是在完成所有操作后,我收到了一个页面错误 404,它并不能准确地表明我的代码有什么问题。

我的问题是,当我从将 url 从 int:id 更改为 slug 时,我还应该寻找什么来更改以避免页面错误 404?

在每个页面详细信息的 URL 中,我得到 int:id 不是帖子的标题和错误 404

我已经评论了添加 slug 功能:这是 models.py :

class Post(models.Model):
    designer = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    likes = models.ManyToManyField(
        User, related_name='liked')
    slug = models.SlugField(blank=True, null=True, max_length=120)

     def save(self, *args, **kwargs):
         if not self.slug:
             self.slug = slugify(self.title)
         super(Post, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse("score:post-detail", kwargs={'slug': self.slug})

这是views.py

class PostDetailView(DetailView):
    model = Post
    template_name = "post_detail.html"

    def get_context_data(self, *args, **kwargs):
        context = super(PostDetailView, self).get_context_data()
        stuff = get_object_or_404(Post, id=self.kwargs['slug'])  <- Error is coming here
        total_likes = stuff.total_likes()
        liked = False
        if stuff.likes.filter(id=self.request.user.id).exists():
            liked = True
        context["total_likes"] = total_likes
        context["liked"] = liked
        return context


def LikeView(request):
    post = get_object_or_404(Post, id=request.POST.get('id'))
    liked = False
    if post.likes.filter(id=request.user.id).exists():
        post.likes.remove(request.user)
        liked = False
    else:
        post.likes.add(request.user)
        liked = True

    context = {
        'total_likes': post.total_likes,
        'liked': liked,
        'post': post
    }

    if request.is_ajax:
        html = render_to_string('like_section.html', context, request=request)
        return JsonResponse({'form': html})

这是网址

urlpatterns = [
    path('', PostListView.as_view(), name='score'),
    path('<slug:slug>/', PostDetailView.as_view(), name='post-detail'),
    path('new/', PostCreateView.as_view(), name='post-create'),
    path('user/<str:username>', UserPostListView.as_view(), name='user-posts'),
    path('<slug:slug>/update/', PostUpdateView.as_view(), name='post-update'),
    path('<slug:slug>/delete/', PostDeleteView.as_view(), name='post-delete')

标签: django

解决方案


首先,蛞蝓有问题。如果您发布两个标题相同的帖子会怎样?因为它们会以同样的方式被压制,你会失去出版物的独特性。我建议您在 stackoverflow 模型上作弊,该模型结合了 id 和 slugified 标题,就像您的浏览器中显示的那样。

其次,您的路径令人困惑最好使用诸如详细信息/“pk”或问题/“pk”/“slug”之类的值作为前缀

我认为错误来自网址,而这个:

stuff = get_object_or_404(Post, id=self.kwargs['slug'])

将其替换为:

stuff = get_object_or_404(Post, slug=self.kwargs['slug'])

或更好:

stuff = self.get_object()

最后,如果您在添加这样的网址后决定遵循我的建议,例如:

path('details/<int:pk>-<slug:sl>', views.PostDetailView.as_view())

您将不得不覆盖 DetailView 的 get_object() 方法

    def get_object(self, queryset=None):
        pk = self.kwargs.get('pk')
        slug = self.kwargs.get('slug')
        stuff = get_object_or_404(Post, id=pk,slug=slug)
        return stuff

而不是像这样对url的常量部分进行后缀:

 path('<slug:slug>/update/', PostUpdateView.as_view(), name='post-update'),
 path('<slug:slug>/delete/', PostDeleteView.as_view(), name='post-delete')

这样做会帮助 django 区分你的 url

 path('update/<slug:slug>', PostUpdateView.as_view(), name='post- 
  update'),
 path('delete/<slug:slug>/', PostDeleteView.as_view(), name='post- 
 delete')

并且还要避免将 url 开头的参数作为:

path('<slug:slug>/', PostDetailView.as_view(), name='post-detail'),

改为这样做

path('posts/<slug:slug>/', PostDetailView.as_view(), name='post-detail'),

希望它会有所帮助:)


推荐阅读