python - 根据模型中的值创建 URL

标签 python django

我想创建一个博客页面,它运行得很好,但我想更改特定博客文章的 URL。目前特定博客文章的 URL 是 myurl.com/blog/pk ,但我希望它是 myurl.com/blog/category/title 。我怎样才能做到这一点?如果您愿意,也欢迎对代码进行任何形式的批评。

模型.py

from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=20)

class Post(models.Model):
    title = models.SlugField(max_length = 250, null = True, blank = True)
    body = models.TextField()
    created_on = models.DateTimeField(null=True)
    last_modified = models.DateTimeField(null=True)
    categories = models.ManyToManyField('Category', related_name='posts')

class Comment(models.Model):
    author = models.CharField(max_length=60)
    body = models.TextField()
    created_on = models.DateTimeField(auto_now_add=True)
    post = models.ForeignKey('Post', on_delete=models.CASCADE)

Views.py

from django.shortcuts import render
from .models import Post
from .models import Comment
from .forms import CommentForm
from django.http import HttpResponse


def blog_index(request):
    posts = Post.objects.all().order_by('-created_on')
    context = {
        "posts": posts,
    }
    return render(request, "blog_index.html", context)


def blog_category(request, category):
    posts = Post.objects.filter(
        categories__name__contains=category
    ).order_by(
        '-created_on'
    )
    if not posts:
        return HttpResponse(status=404)

    context = {
        "category": category,
        "posts": posts
    }
    return render(request, "blog_category.html", context)


def blog_detail(request, pk):
    post = Post.objects.get(pk=pk)

    form = CommentForm()
    if request.method == 'POST':
        form = CommentForm(request.POST)
        if form.is_valid():
            comment = Comment(
                author=form.cleaned_data["author"],
                body=form.cleaned_data["body"],
                post=post
            )
            comment.save()

    comments = Comment.objects.filter(post=post)
    context = {
        "post": post,
        "comments": comments,
        "form": form,
    }
    return render(request, "blog_detail.html", context)

应用程序 urls.py

from django.urls import path
from . import views

urlpatterns = [
    path("", views.blog_index, name="blog_index"),
    path("<int:pk>/", views.blog_detail, name="blog_detail"),
    path("<category>/", views.blog_category, name="blog_category"),
]

项目网址

path('blog/', include('blog.urls')),

最佳答案

我非常确信您不想想要使用标题。标题通常可以包含空格 ()、标点符号 (~!#.? 等) 和特殊字符。 URL 不能包含大部分字符。人们确实可以转义这些字符,但 URL 看起来很难看,如下所示:

myurl.com/some%20title%20containing%20spaces

现在这不是很可读。

但是,您可以使用带有 SlugField [Django-doc]slugSlugField 是一个 CharField,但它会进行一些清理以避免丑陋的 URL。例如,'some title contains space' 将转换为 some-title-containing-spaces

您可以将 SlugField 添加到您的 CategoryModel,如下所示:

from django.utils.text import <b>slugify</b>

class Category(models.Model):
    name = models.CharField(max_length=20)
    <b>slug = models.SlugField(unique=True, blank=True)</b>

    def save(self, *args, **kwargs):
        <b>self.slug = slugify(self.name)</b>
        super().save(*args, **kwargs)

urlpatterns中,我们可以将slug指定为:

# app/urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('', views.blog_index, name='blog_index'),
    path('<int:pk>/', views.blog_detail, name='blog_detail'),
    path('category/<b><slug:category_slug></b>/', views.blog_category, name='blog_category'),
]

然后我们可以在 View 中过滤 slug:

from django.shortcuts import get_list_or_404
from .models import Post

def blog_category(request, category_slug):
    posts = get_list_or_404(Post.objects.filter(
        <b>categories__slug=category_slug</b>
    ).order_by(
        '-created_on'
    ))

    context = {
        'category': category,
        'posts': posts
    }
    return render(request, 'blog_category.html', context)

生成独特的slugs

有时可能会发生另一个Category对象已经存在slug的情况,我们可以使用脚本生成一个唯一的slug,例如:

from django.utils.text import slugify
from itertools import count

class Category(models.Model):
    name = models.CharField(max_length=20)
    <b>slug = models.SlugField(unique=True, blank=True)</b>

    def save(self, *args, **kwargs):
        for i in count():
            slug = slugify('{}{}'.format(self.title, i or ''))
            if not Category.objects.filter(slug=slug).exists():
                break
        self.slug = slug
        super().save(*args, **kwargs)

关于python - 根据模型中的值创建 URL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56317508/

相关文章:

python - 如何在显示文本的同时在 Python 2.6.6 中播放音频?

python - 什么时候应该从ABC继承?

Django按计数排序

python - Django 1.9 批量创建新用户未正确散列密码

python - 如何将 ET.dump() xml 字符串从 Django View 传递到模板 -- python django ElementTree

python - 如何在Python中替换列表中的列表

python - 在 Python 中比较 float 和 int

python - 使用 Python 层时,Caffe blob 中的 `num` 和 `count` 参数有什么区别?

django - 在保存到缓存之前先压缩Python对象

Django REST Framework - 405 METHOD NOT ALLOWED using SimpleRouter