在Django模型中添加slug字段
什么是Django中的SlugField
它是一种生成有效URL的方法,一般使用已经获得的数据。例如,使用一篇文章的标题来生成一个URL。让我们假设我们的博客有一篇文章,标题为’The Django book by Geeksforgeeks’,主键id=2。我们可以用以下方式来引用这个帖子
www.geeksforgeeks.org/posts/2.
或者,我们可以引用标题,如
www.geeksforgeeks.org/posts/The Django book by Geeksforgeeks.
但问题是空格在URL中是无效的,需要用%20代替,这很难看,使之成为以下内容
www.geeksforgeeks.org/posts/The%20Django%20book%20by%20geeksforgeeks
但这并不能解决有意义的URL。另一个选项可以是
www.geeksforgeeks.org/posts/the-django-book-by-geeksforgeeks
因此,现在的标题是the-django-book-by-geeksforgeeks。所有的字母都是小写的,空格则由连字符–取代。
假设我们的博客文章模型看起来与此类似。
STATUS_CHOICES = (
('draft', 'Draft'),
('published', 'Published'),
)
class Post(models.Model):
title = models.CharField(max_length = 250)
slug = models.SlugField(max_length = 250, null = True, blank = True)
text = models.TextField()
published_at = models.DateTimeField(auto_now_add = True)
updated = models.DateTimeField(auto_now = True)
status = models.CharField(max_length = 10, choices = STATUS_CHOICES,
default ='draft')
class Meta:
ordering = ('-published_at', )
def __str__(self):
return self.title
将Slugify加入到我们的项目中:
现在我们需要找到一种方法,将标题自动转换为蛞蝓。我们希望这个脚本在每次创建Post模型的新实例时被触发。为了这个目的,我们将使用信号。
注意:在保存settings.py文件的同一目录下添加新文件util.py。
import string, random
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.utils.text import slugify
def random_string_generator(size = 10, chars = string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
def unique_slug_generator(instance, new_slug = None):
if new_slug is not None:
slug = new_slug
else:
slug = slugify(instance.title)
Klass = instance.__class__
max_length = Klass._meta.get_field('slug').max_length
slug = slug[:max_length]
qs_exists = Klass.objects.filter(slug = slug).exists()
if qs_exists:
new_slug = "{slug}-{randstr}".format(
slug = slug[:max_length-5], randstr = random_string_generator(size = 4))
return unique_slug_generator(instance, new_slug = new_slug)
return slug
Django中的信号:
在很多情况下,当一个模型的实例发生修改时,我们需要执行一些动作。Django为我们提供了一种优雅的方式来处理这些情况。信号是允许将事件与动作联系起来的实用工具。我们可以开发一个函数,当一个信号调用它时,它就会运行。
在post应用程序的models.py文件中,在定义了Post Model的地方,在同一个文件中添加这个。
@receiver(pre_save, sender=Post)
def pre_save_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
pre_save_receiver函数应该被单独放在Post模型之外。
注意:在urls.py中用path(‘post/’, detail)编辑detail路径。在views.py中编辑detail函数,用
def detail(request, slug):
q = Post.objects.filter(slug__iexact = slug)
if q.exists():
q = q.first()
else:
return HttpResponse('<h1>Post Not Found</h1>')
context = {
'post': q
}
return render(request, 'posts/details.html', context)
最后一步是在HTML文件<a href=”/posts/{{ a.slug }}” class=”btn btn-primary”>视图</a>
中添加链接。现在我们准备去127.0.0.1:8000/posts/title-you-have-added,它将向你展示details.html的页面。