自强学堂
自强学堂:学习、分享、让你更强!
Django 教程HTMLCSSJAVASCRIPTJQUERYSQLPHPBOOTSTRAPANGULARXML
 

Django 开发内容管理系统(第三天)

内容管理系统开发(第三天)

2.9 修复文章slug的 Bug

我们再来回顾一下以前的设计,每篇文章都有一个slug,这样当我们写文章的时候,slug重复会出现问题,我们可以修改成不允许重复:

class Article(models.Model):
    ...
    slug = models.CharField('网址', max_length=200, unique=True)

我们接着看,不要同步更改到数据库,我们加入了 unique = True, 不允许有同样值的记录存在,同时也删除了 db_index=True, 因为当 unique=True的时候会自动创索引。但是这样做不是很好,有时候我们不想输入一些文章的 slug,或者太多文章了没注意写成了一样的了呢?这样的设计是有问题的。

下面是我在 StackOverflow 上回答的一个问题,大家注意一下网址:

http://stackoverflow.com/questions/30295171/django-listfield-with-add-and-remove/30295614#30295614

大家很容易发现,网址为:

域名,类别,编号,问题标题 这四部分组成,提问的人可以写同样的标题,但是不会出问题,关键就是 编号 不同


我们就采用这种编号的格式,默认地,Django会为每一个 Model 建一个名称为 id 的主键(详情):

class Article(models.Model):
    # id 这个是默认有的,也可以自己定义一个其它的主键来覆盖它
    #id = models.AutoField(primary_key=True)
    ...

我们就利用默认的 id 字段,下面来修改以前的文件,来采用新的,更合理的网址形式。

minicms/urls.py

    url(r'^news/(?P<pk>\d+)/(?P<article_slug>[^/]+)/$', 'news.views.article_detail', name='article'),

pk 是Primary Key 主键的意思,这里等价于 id,但是 id 是 Python 中的一个内置函数,所以我更喜欢用 pk


news/views.py

def article_detail(request, pk, article_slug):
    article = Article.objects.get(pk=pk)
    return render(request, 'news/article.html', {'article': article})

我们不使用 article_slug 就可以获取到网址了,是不是,的确是这样的,那 article_slug 有什么用呢?

想一想一篇文章的网址你很可能会修改它,当你再次修改的时候,可能搜索引擎已经收录了,或者其它人已经收藏到了书签中,这样,原来的网址和新的网址都是可以访问网站的!

搜索引擎会发现你多个网址对应到不同的内容,这样不是很好,怎么办呢,当我们发现,访问用的article_slug 和现在的article_slug不一样的时候,重定向(301)跳转到新的网址

再次修改 new/views.py 来实现这个功能

...
from django.shortcuts import redirect
...

def article_detail(request, pk, article_slug):
    article = Article.objects.get(pk=pk)

    if article_slug != article.slug:
        return redirect(article, permanent=True)

    return render(request, 'news/article.html', {'article': article})

django.shortcuts.redirect 是一个比较方便的函数(详情):

1. 传递一个网址的时候,跳转到网址:redirect('http://www.ziqiangxuetang.com') 跳转到自强学堂首页

Django 1.7 版本开始可以接收相对路径:redirect('/django/') 跳转到 Django 教程栏目 下

2. 传递一个 Model object 的时候,自动调用object的 get_absolute_url 函数获取网址,上面就是一个这样的例子。


news/models.py

class Article(models.Model):
    ...
    def get_absolute_url(self):
        return reverse('article', args=(self.pk, self.slug))
    ....

更行了上面的更改之后我们修复了之前的bug,自己再访问网站试试吧!

QQ20150730-1@2x.png

至此代码:zip 下载    github地址

今天就写到这里吧,有能力的同学可以尝试把这些内容写一个单元测试。

服务承诺:2017年03月11日到12日出现了网站不可访问,不少同学发来了邮件关心,感谢大家对自强堂Django教程的支持与厚爱。自强学堂不会关闭,我向大家承诺,我依然会坚持每天答疑,看邮件回复邮件,服务器费用已经缴纳三年,后期会努力提高服务稳定性。我也还至少会再坚持做三年,直到2020年03月12日,我愿意坚持做这件事,是因为我认为这很有意义,2015年劳动节开始写这个教程的时候,我没有想到如今,每天会有5000人来自强学堂看Django教程,我希望能帮助到更多的人。—— 2017年03月12日于北京深夜 涂伟忠