在 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 。所有字母都小写,空格用连字符 - 代替。
假设我们的 Blog Post 模型与此类似。
Python3
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
Python3
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
Python3
@receiver(pre_save, sender=Post)
def pre_save_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
Python3
def detail(request, slug):
q = Post.objects.filter(slug__iexact = slug)
if q.exists():
q = q.first()
else:
return HttpResponse('Post Not Found
')
context = {
'post': q
}
return render(request, 'posts/details.html', context)
将 Slugify 添加到我们的项目中:
现在我们需要找到一种将标题自动转换为 slug 的方法。我们希望每次创建Post模型的新实例时触发此脚本。为此,我们将使用信号。
注意:在保存 settings.py 文件的同一目录中添加新文件 util.py。
Python3
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 文件中,将其添加到同一文件中:
Python3
@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('posts/', detail) 编辑详细路径。在views.py 中编辑详细函数
Python3
def detail(request, slug):
q = Post.objects.filter(slug__iexact = slug)
if q.exists():
q = q.first()
else:
return HttpResponse('Post Not Found
')
context = {
'post': q
}
return render(request, 'posts/details.html', context)
最后一步是在 HTML 文件 View 中添加链接。现在我们准备好去127.0.0.1:8000/posts/title-you-have-added ,它会显示页面details.html 。