📜  在 Django 模型中添加 slug 字段

📅  最后修改于: 2022-05-13 01:55:01.830000             🧑  作者: Mango

在 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