博客五部曲之一 - 简单博客
1428 浏览 5 years, 11 months
29 SlugField
版权声明: 转载请注明出处 http://www.codingsoho.com/目前的URL里使用的是id,但是不利于分享,这一掌将会讲解用SlugField去优化URL
class Post(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField(unique=True)
因为slug是unique,那么我们必须删除当前的database,否则新生成的slug字段会相互冲突。
删除db.sqlite3以及所有的migrations文件,原media也删除掉,随便不影响后面的功能。
一般来说slug支持自动生成,这儿我们用到了pre_save信号,它能够让我们在数据存储到数据库之前做一些处理。
from django.db.models.signals import pre_save
from django.utils.text import slugify
def create_slug(instance, new_slug=None):
slug = slugify(instance.title)
if new_slug is not None:
slug = new_slug
qs = Post.objects.filter(slug=slug).order_by("-id")
exists = qs.exists()
if exists:
new_slug = "%s-%s" % (slug, qs.first().id)
return create_slug(instance, new_slug=new_slug)
return slug
def pre_save_post_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = create_slug(instance)
pre_save.connect(pre_save_post_receiver, sender=Post)
这儿有个问题是生成的slug可能是重复的,我们采用递归的方式来生成新的slug
当创建一个新的实例时,pre_save过程中,id还没有生成,所有我们可以用一个折中的办法就是用前一个相同slug的实例ID
比如我们创建实例名字为new post,那么对应的slug为new-post (ID=1),再创建一个,名字为new-post-1,反复创建,名字分别为new-post-1-2, new-post-1-2-3 ….
最后修改详情视图的访问URL从ID改到slug
class Post(models.Model):
def get_absolute_url(self):
return reverse("posts:detail", kwargs={"slug":self.slug})
并修改post_detail, post_delete和post_update函数,将实例获取方式从ID改到slug,和ID一样,slug也是唯一的。
def post_detail(request, slug=None):
instance = get_object_or_404(Post, slug=slug)
context = {
"title" : instance.title,
"instance" : instance
}
return render(request, "post_detail.html",context)
更新URL映射方式
urlpatterns = [
url(r'^$', views.post_list, name="list"),
url(r'^create/', views.post_create),
url(r'^(?P<slug>[\w-]+$)', views.post_detail, name="detail"),
url(r'^(?P<slug>[\w-]+)/edit$', views.post_update, name="update"),
url(r'^(?P<slug>[\w-]+)/delete$', views.post_delete, name="delete"),
]