如何在Django中创建子弹?


218

我正在尝试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

Answers:


413

您将需要使用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)

请注意,以上内容将导致您在修改q字段时更改您的URL ,这可能会导致链接断开。创建新对象时最好只生成一次子弹:

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)

4
害羞有特殊的模特类型吗?为什么不仅仅将CharFields塞进去?
2009年

23
SlugFields默认情况下设置db_index = True,并且默认情况下还使用具有验证正则表达式的表单字段来要求有效的子项(如果在ModelForm或admin中表示)。如果愿意,可以使用CharField手动执行这些操作,这只会使代码的意图不太清楚。另外,如果您希望在admin中基于JS的自动预填充,请不要忘记prepopulate_fields ModelAdmin设置。
卡尔·迈尔

4
正如Dingle在下面的回答中所述,您需要替换def save(self):def save(self, *args, **kwargs):,以避免在编写诸如之类的东西时引发错误test.objects.create(q="blah blah blah")
利亚姆

6
请注意,此代码将更新每次保存的段。您的网址将会更改,“酷URI不会更改” w3.org/Provider/Style/URI.html
dzen 2011年

18
slugify()也可以在中找到django.utils.text.slugify,不清楚何时添加。
mrmagooey

112

有一些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'

7
utf-8现在可以通过slugify(在Django 1.8.5中)正确处理了
Rick Westera

作为@RickWestera说,这现在被slugify处理,但如果由于某种原因你不想使用slugify从django.utils.encoding检查iri_to_uri:docs.djangoproject.com/en/2.0/ref/unicode/...
Erwol

64

对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错误(意外参数)。


2
在同行的回答中还需要增加一点非常小的事情:我将在最后一行做最后一句话return super(test, self).save(*args, **kwargs)。我认为此方法将返回None,并且我不知道有任何计划来更改该方法,但是返回该超类的方法在将来某个时候发生更改时所做的操作也没有害处。
邓肯·帕克斯

从django.utils.text添加,此解决方案需要slugify导入
Routhinator '15

1
@Routhinator做到了
JonasGröger'16

派出一些探针来询问这是否仍然是这样做的首选方法。
sytech '18

29

如果您使用的管理界面增加模型的新项目,你可以建立一个ModelAdmin在你admin.py和利用prepopulated_fields自动进入蛞蝓的:

class ClientAdmin(admin.ModelAdmin):
    prepopulated_fields = {'slug': ('name',)}

admin.site.register(Client, ClientAdmin)

在这里,当用户在admin表单中为该name字段输入值时,slug将使用正确的slugified自动填充name


slugname领域都有翻译。我该如何翻译?因为我尝试添加'slug_en':('name_en',)并得到以下错误:我的模型中不存在该属性。
patricia'7

22

在大多数情况下,该条块不应更改,因此您实际上只想在首次保存时进行计算:

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

使用prepopulated_fields在您的管理类:

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

admin.site.register(Article, ArticleAdmin)

1
你能解释一下吗?管理员如何影响项目?
布莱斯

5

如果您不想将slugfield设置为“不可编辑”,那么我相信您希望将Null和Blank属性设置为False。否则,尝试保存到Admin时会收到错误消息。

因此,对上述示例的修改如下:

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()


4

我正在使用Django 1.7

像这样在模型中创建一个SlugField:

slug = models.SlugField()

然后在admin.py定义prepopulated_fields;

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

正是我想要的
Nick

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.