Django中漂亮且SEO友好的URLs

14

我目前正在编写一个Web博客,学习 Django。我需要一个视图来显示单个博客文章,我的第一次尝试是创建以下URL:

myblog.com/blog/view/1

这个代码段使用博客ID来识别指定的博客文章。

现在,如果你浏览许多博客/网站,你会发现他们在URL中使用博客文章标题,这是因为这样更容易被搜索引擎收录,从而更容易被找到。它可能看起来像这样。

myblog.com/blog/view/a-python-backup-script

我该如何在django中实现这个功能?

附加问题: 很多网站还包括文章的月份和年份。我猜这也与SEO有关,但具体有什么用处呢?

5个回答

27
在你的博客模型中添加一个“slug”字段。
from django.template.defaultfilters import slugify

Class Blog(models.Model):
    title = models.CharField(max_length=40)
    slug = models.SlugField(_('slug'), max_length=60, blank=True)

    #Then override models save method:
    def save(self, *args, **kwargs):
        if not self.id:
            #Only set the slug when the object is created.
            self.slug = slugify(self.title) #Or whatever you want the slug to use
        super(Blog, self).save(*args, **kwargs)

在你的 urls.py 文件中:

(r'^blog/view/(?P<slug>[-\w]+)/$', 'app.views.blog_view'),

在 views.py 中

def blog_view(request, slug):
    blog = Blog.objects.get(slug=slug)
    #Then do whatever you want

编辑:我在保存方法中添加了一个检查,因为您希望slug在对象创建时创建。它不应该每次都保存。


2
如果两篇博客文章标题相同怎么办? - Peter Wood
just add the ID too - Jota

8

确保您的模型实际上有一个slug字段:

class BlogPost(models.Model):
    slug = models.SlugField(unique=True)

并且您有一个视图:

from django.shortcuts import get_object_or_404
def blog_detail(request, slug):
    ...
    post = get_object_or_404(BlogPost, slug=slug)
    ...
    render(request, "blog/blog_post.detail.html", { 'blog_post' : post })

然后在您的urls.py中,您可以指定一个slug:

url(r'^(?P<slug>[-w]+)/$', 'blog.views.blog_detail', {}, name="blog_detail"),

第一个参数是正则表达式,当匹配成功时,将运行blog_detail视图,并将来自正则表达式的匹配slug组传递给视图(视图将渲染并返回模板)。
关于您提出的最后一点:我发现在URL中加入日期不仅可能对SEO有好处,而且使我能够轻松地一眼看出博客文章是否为新文章。此外,在Django中,很容易使用这种方法与基于日期的通用视图结合使用,这将减少您需要编写的样板视图代码量。以下是示例:
url(r'(?P<year>d{4})/(?P<month>[a-z]{3})/(?P<day>w{1,2})/(?P<slug>[-w]+)/$', 
        'django.views.generic.date_based.object_detail', 
        { template_name = "blog/detail.html", ... }, 
        name="blog_detail"),

2

这种类似的方法与使用数字 id 字段的 url 兼容。

在 models.py 中添加一个 slug 字段 和一个保存定义

from django.template.defaultfilters import slugify

slug = models.SlugField(default='no-slug', max_length=60, blank=True)

def save(self, *args, **kwargs):
    #save a slug if there is no slug or when it's 'no-slug' (the default slug)
    if not self.slug or self.slug == 'no-slug':
        self.slug = slugify(self.name)
    super(Project, self).save(*args, **kwargs)

在urls.py中添加第二个url模式:
#original:
url(r'^(?P<id>\d+)/$', 'project.views.view', name='view_url'),
#new pattern added under original:
url(r'^(?P<id>\d+)-(?P<slug>[-\w\d]+)/$', 'project.views.view', name='view_url'),

在views.py中让slug通过

def view(request, mid=None, slug=None):

接下来,您需要做的就是编辑 models.py 文件并使用此 URL 模式:

def get_absolute_url(self):
    return reverse('view_url', args=[self.id, self.slug])

2

或者,如果您正在使用基于类的视图,您可以做的最基本的事情是:

from django.views.generic import DetailView
from models import Blog

class BlogView(DetailView):
    model = Blog
    template_name = "blog/blog_detail.html"

然后,URL 大致如下:

from views import BlogView

url(r'^(?P<slug>[-w]+)/$', BlogView._as_view(), name="blog_detail"),

请注意,Django的通用DetailView需要pk或slug。因此,在这种情况下,使用slug与使用pk没有区别。

0

Django-autoslug非常适合这个目的,并且有很多有用的选项。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接