如何在 Django 中创建 slug?
- 2025-04-15 09:19:00
- admin 原创
- 22
问题描述:
SlugField
我正在尝试在 Django 中创建一个。
我创建了这个简单的模型:
from django.db import models
class Test(models.Model):
q = models.CharField(max_length=30)
s = models.SlugField()
然后我这样做:
>>> from mysite.books.models import Test
>>> t=Test(q="aa a a a", s="b b b b")
>>> t.s
'b b b b'
>>> t.save()
>>> t.s
'b b b b'
我期待着b-b-b-b
。
解决方案 1:
您将需要使用slugify函数。
>>> from django.template.defaultfilters import slugify
>>> slugify("b b b b")
u'b-b-b-b'
>>>
您可以slugify
通过重写save
方法自动调用:
class Test(models.Model):
q = models.CharField(max_length=30)
s = models.SlugField()
def save(self, *args, **kwargs):
self.s = slugify(self.q)
super(Test, self).save(*args, **kwargs)
请注意,上述操作会导致您的 URL 在q
编辑字段时发生变化,从而导致链接失效。建议您在创建新对象时只生成一次 slug:
class Test(models.Model):
q = models.CharField(max_length=30)
s = models.SlugField()
def save(self, *args, **kwargs):
if not self.id:
# Newly created object, so set slug
self.s = slugify(self.q)
super(Test, self).save(*args, **kwargs)
解决方案 2:
存在一些 UTF-8 字符的极端情况
例子:
>>> from django.template.defaultfilters import slugify
>>> slugify(u"test ąęśćółń")
u'test-aescon' # there is no "l"
这个问题可以用Unidecode来解决
>>> from unidecode import unidecode
>>> from django.template.defaultfilters import slugify
>>> slugify(unidecode(u"test ąęśćółń"))
u'test-aescoln'
解决方案 3:
对Thepeer 的回答进行一点修正:要覆盖save()
模型类中的函数,最好向其添加参数:
from django.utils.text import slugify
def save(self, *args, **kwargs):
if not self.id:
self.s = slugify(self.q)
super(test, self).save(*args, **kwargs)
否则,test.objects.create(q="blah blah blah")
将导致force_insert
错误(意外参数)。
解决方案 4:
ModelAdmin
如果您使用管理界面添加模型的新项目,则可以在您的模型中设置admin.py
并利用prepopulated_fields
它自动输入 slug:
class ClientAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('name',)}
admin.site.register(Client, ClientAdmin)
在这里,当用户在管理表单中输入字段的值时name
,slug
将自动填充正确的 slugified name
。
解决方案 5:
在大多数情况下,slug 不应该改变,因此您实际上只想在第一次保存时计算它:
class Test(models.Model):
q = models.CharField(max_length=30)
s = models.SlugField(editable=False) # hide from admin
def save(self):
if not self.id:
self.s = slugify(self.q)
super(Test, self).save()
解决方案 6:
如果您不想将 slugfield 设置为不可编辑,那么我认为您需要将 Null 和 Blank 属性设置为 False。否则,您在管理控制台中尝试保存时会出错。
因此,对上述示例的修改将是:
class test(models.Model):
q = models.CharField(max_length=30)
s = models.SlugField(null=True, blank=True) # Allow blank submission in admin.
def save(self):
if not self.id:
self.s = slugify(self.q)
super(test, self).save()
解决方案 7:
prepopulated_fields
在您的管理类中使用:
class ArticleAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("title",)}
admin.site.register(Article, ArticleAdmin)
解决方案 8:
我正在使用 Django 1.7
像这样在模型中创建一个 SlugField:
slug = models.SlugField()
然后在admin.py
定义prepopulated_fields
;
class ArticleAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("title",)}
解决方案 9:
您可以查看文档,SlugField
以更具描述性的方式了解更多信息。
解决方案 10:
您可以使用SlugField()slug
创建字段并使用slugify()对字段值进行 slugify,然后在每次添加和更改对象时将 slugify 的字段值保存为覆盖的save()中的字段值,如下所示:name
`nameslug
Product`
# "models.py"
from django.utils.text import slugify
class Product(models.Model):
name = models.CharField(max_length=20)
slug = models.SlugField()
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super().save(*args, **kwargs)
并且,您可以通过在 URL 中使用in addition 来防止链接断开,如下所示:id
`slug`
# ↓ "slug" ↓
http://myshop.com/product/orange-juice/id
# "id" ↑
因此,urlid
除了需要slug
in之外还需要其他内容urls.py
,如下所示:
# "urls.py"
urlpatterns = [
path( # ↓ "slug" ↓
'product/<slug:slug>/<int:id>/',
views.get_product, # ↑ "id" ↑
name="get_product"
)
]
然后,您应该只治疗id
不治疗slug
,get_product()
如下views.py
所示:
# "views.py"
def get_product(request, id=None, slug=None):
product_obj = None
if id:
product_obj = Product.objects.get(id=id)
return HttpResponse(product_obj)
解决方案 11:
在某些情况下,slugify 单独使用不够。我正在使用另一种技术来处理 slug。我认为这应该可以覆盖大多数情况。
首先在您的应用程序目录中创建一个 slug.py 文件,并将以下代码复制到其中。
slug.py
import re
from django.template.defaultfilters import slugify
def unique_slugify(instance, value, slug_field_name='slug', queryset=None,
slug_separator='-'):
"""
Calculates and stores a unique slug of ``value`` for an instance.
``slug_field_name`` should be a string matching the name of the field to
store the slug in (and the field to check against for uniqueness).
``queryset`` usually doesn't need to be explicitly provided - it'll default
to using the ``.all()`` queryset from the model's default manager.
"""
slug_field = instance._meta.get_field(slug_field_name)
slug = getattr(instance, slug_field.attname)
slug_len = slug_field.max_length
# Sort out the initial slug, limiting its length if necessary.
slug = slugify(value)
if slug_len:
slug = slug[:slug_len]
slug = _slug_strip(slug, slug_separator)
original_slug = slug
# Create the queryset if one wasn't explicitly provided and exclude the
# current instance from the queryset.
if queryset is None:
queryset = instance.__class__._default_manager.all()
if instance.pk:
queryset = queryset.exclude(pk=instance.pk)
# Find a unique slug. If one matches, at '-2' to the end and try again
# (then '-3', etc).
next = 2
while not slug or queryset.filter(**{slug_field_name: slug}):
slug = original_slug
end = '%s%s' % (slug_separator, next)
if slug_len and len(slug) + len(end) > slug_len:
slug = slug[:slug_len-len(end)]
slug = _slug_strip(slug, slug_separator)
slug = '%s%s' % (slug, end)
next += 1
setattr(instance, slug_field.attname, slug)
def _slug_strip(value, separator='-'):
"""
Cleans up a slug by removing slug separator characters that occur at the
beginning or end of a slug.
If an alternate separator is used, it will also replace any instances of
the default '-' separator with the new separator.
"""
separator = separator or ''
if separator == '-' or not separator:
re_sep = '-'
else:
re_sep = '(?:-|%s)' % re.escape(separator)
# Remove multiple instances and if an alternate separator is provided,
# replace the default '-' separator.
if separator != re_sep:
value = re.sub('%s+' % re_sep, separator, value)
# Remove separator from the beginning and end of the slug.
if separator:
if separator != '-':
re_sep = re.escape(separator)
value = re.sub(r'^%s+|%s+$' % (re_sep, re_sep), '', value)
return value
然后在 models.py 文件中导入 unique_slugify。然后在 save() 方法中使用它。
模型.py
from django.db import models
from yourapp.slug import unique_slugify # Change "yourapp" with your app name
class Test(models.Model):
q = models.CharField(max_length=30)
s = models.SlugField()
def save(self, **kwargs):
slug = '%s' % (self.q)
unique_slugify(self, slug)
super(Test, self).save()
扫码咨询,免费领取项目管理大礼包!