Django SlugField用法示例

在开发web系统中,关于内容url链接,有时候我们常常希望可以自定义,而不是看起来没有任何含义的id来表示,这时候Django提供给我们的SlugField就能排上用场了。

slug 实际的含义是标称, 单位的意思。在 django 中,slug 指有效 URL 的一部分,能使 URL 更加清晰易懂。比如有这样一篇文章,标题是”我是中国人”,它的 URL 地址是/posts/wo-shi-zhong-guo-ren,后面这一部分便是 slug

Django内置slugify

为了便于自动生成slugDjango甚至帮我们内置了该扩展,但是使用过程中会发现,并不适合国人,它对于汉语的支持很不友好,生成不了中文对应的slug

1
2
3
4
5
>>> from django.template.defaultfilters import slugify
>>> slugify('hello world')
'hello-world'
>>> slugify('我是中国人')
''

可以看到中文生成不了对应的slug了。

django-uuslug

django-uuslug 是一个很方便的将中文转化成拼音 slug 的插件。通过使用 django-uuslug,可以确保 slug 是唯一的,并且都是 unicode 编码的。

安装

1
pip install django-uuslug

测试

1
2
3
4
5
>>> from uuslug import slugify
>>> slugify('hello world')
'hello-world'
>>> slugify('我是中国人')
'wo-shi-zhong-guo-ren'

项目应用

定义模型

网上大部分的做法是一步写死,直接自动生成slug,且禁止编辑。我们自己项目中有时候想让slug显得更有意义,所以有时候需要自己编辑slug,不主动设定slug时候才自动生成slug。

网上做法
1
2
3
4
5
6
7
8
9
10
11
12
13
from django.db import models

from uuslug import slugify
from django.template.defaultfilters import slugify


class Post(models.Model):
title = models.CharField(verbose_name="文章标题", max_length=50)
slug = models.SlugField(editable=False)

def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
代码优化

将slug设为可编辑可为空,保存时判断用户没有填写slug我们在生成slug,这样显得更人性化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from django.db import models

from uuslug import slugify
from django.template.defaultfilters import slugify


class Post(models.Model):
title = models.CharField(verbose_name="文章标题", max_length=50)
slug = models.SlugField(verbose_name="别名", max_length=50, null=True, blank=True)

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

定义视图

使用CBV模式写了简单两个视图,一个列表页,一个详情页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import json

from django.shortcuts import HttpResponse
from django.http import JsonResponse
from django.views import View

from . import models


class PostView(View):
"""文章列表视图"""

def get(self, request):
# 获取所有文章
posts = models.Post.objects.all()
data = []
for post in posts:
data.append({
'title': post.title,
'slug': post.slug
})
# 两种返回方式皆可以
# return HttpResponse(json.dumps(data, ensure_ascii=False))
return JsonResponse({"data": data}, json_dumps_params={"ensure_ascii": False})


class PostDetailView(View):
"""文章详情视图"""

def get(self, request, slug):
# 查询指定slug对应的文章
post_obj = models.Post.objects.filter(slug=slug).get()
data = {
'title': post_obj.title,
'slug': post_obj.slug
}
return JsonResponse({"data": data}, json_dumps_params={"ensure_ascii": False})

添加数据

我们在django-admin中添加了两条测试数据,一条自己编辑slug的文章,一条自动生成slug的文章

设置路由

路由我们这里肯定也要相对应的设置两条,分别对应列表页和详情页。

1
2
3
4
# 列表页
path('post/', views.PostView.as_view()),
# 详情页
path('post/<slug:slug>/', views.PostDetailView.as_view())

访问测试

启动该Django程序。

访问列表页

访问详情页

至此,我们的slug从定义到使用全部说完了,更多高阶用法去官方文档翻翻看吧。