有没有一种简单的方法可以从CharField填充SlugField?

43
class Foo(models.Model):
    title = models.CharField(max_length=20)
    slug = models.SlugField()

是否有内置的方式可以使slug字段根据标题自动填充?无论是在管理界面内还是外部。

8个回答

74

对于Django 1.0及以上版本的管理员,您需要使用

prepopulated_fields = {'slug': ('title',), }

在您的admin.py中,prepopulated_fields字典中的键是您想要填充的字段,值是您想要连接的字段元组。

在admin之外,您可以在视图中使用slugify函数。在模板中,您可以使用|slugify过滤器。

还有这个包会自动处理这个问题:https://pypi.python.org/pypi/django-autoslug


https://docs.djangoproject.com/en/dev/ref/models/fields/#slugfield https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.prepopulated_fields - Wtower

8

我想为您提供一份完整且最新的答案,包含需要注意的地方:

1. 在Django管理界面中自动填充表单

如果您只关心在管理员界面中添加和更新数据,您可以简单地使用prepopulated_fields属性。

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

admin.site.register(Article, ArticleAdmin)

2. 在模板中自动填充自定义表单

如果您使用表单构建了自己的服务器渲染界面,您可以通过使用 |slugify 模板过滤器或在保存表单(is_valid)时使用 slugify 工具来自动填充字段。

3. 使用django-autoslug在模型级别自动填充slugfields

上述解决方案仅在通过这些接口(管理界面或自定义表单)操作数据时才会自动填充slugfield(或任何字段)。如果您有API、管理命令或其他任何也能操作数据的功能,您需要转到模型级别。

django-autoslug 提供了 AutoSlugField 字段,它扩展了 SlugField 并允许您设置应该整洁地进行 slugify 的字段:

class Article(Model):
    title = CharField(max_length=200)
    slug = AutoSlugField(populate_from='title')

4. 通过重载 save() 方法在模型级别自动填充 slug 字段

最后一种选项是自己实现,需要重载默认的 save() 方法:

该字段使用 pre_save 和 post_save 信号来实现其功能,请查看本答案底部的提示文本。

class Article(Model):
    title = CharField(max_length=200)
    slug = SlugField()

    def save(self, *args, **kwargs):
        self.slug = slugify(self.title)
        super().save(*args, **kwargs)

注意:批量更新将绕过您的代码(包括信号)

这是Django初学者常犯的一个误解。首先,您应该知道pre_save和post_save信号与save()方法直接相关。其次,在Django中执行批量更新的不同方式都规避了save()方法,以操作SQL层来实现高性能。这意味着对于以上解决方案3或4中使用的示例模型:

  • Article.objects.all().update(title='New post') 将不会更新任何文章的slug字段
  • 在Article模型上使用bulk_createbulk_update不会更新任何文章的slug字段。
  • 由于未调用save()方法,将不会发出任何pre_save或post_save信号

如果要进行批量更新并仍然利用代码级别的约束条件,则唯一的解决方案是逐个迭代对象并调用其save()方法,这比SQL级别的批量操作效率要低得多。当然,您可以在数据库中使用触发器,但那是完全不同的话题。


1
选项4中的“Job”是什么? - Kovy Jacob
@KovyJacob 被别人修复了。 - Andreas Bergström

6

在管理员之外,可以查看这个django片段。将其放入.save()中,它将与通过编程创建的对象一起使用。如其他人所说,在管理员内部使用prepopulated_fields


我同意,但要注意批量插入... save() 方法不是直接调用的。 - FlogFR

3

针对1.0之前的版本:

slug = models.SlugField(prepopulate_from=('title',))

应该可以正常工作

对于1.0版本,请使用camflan的方法


2
prepopulated_fields = {'slug': ('title',), }

我认为这会对你有所帮助。 - Epsilon36170
1
即使对你来说很简单,你也应该尽量解释代码的意图。 - bitoiu

2

我想知道这种方法是否适用于批量插入?我不确定:/ - FlogFR
2
你需要为批量操作制定一个解决方案,你可以查看这个线程获取一些见解:http://stackoverflow.com/questions/23744795/django-emulate-database-trigger-behavior-on-bulk-insert-update-delete - carefulweb

1

使用内置的Django slugify在模型级别自动填充slug字段:

models.py

from django.db import models


class Place:
    name = models.CharField(max_length=50)
    slug_name = models.SlugField(max_length=50)

signals.py

from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.template.defaultfilters import slugify as django_slugify

from v1 import models


@receiver(pre_save, sender=models.Place)
def validate_slug_name(sender, instance: models.Place, **kwargs):
    instance.slug_name = django_slugify(instance.name)

致谢:https://github.com/justinmayer/django-autoslug/blob/9e3992296544a4fd7417a833a9866112021daa82/autoslug/utils.py#L18


(此内容为致谢,感谢原作者提供技术支持)

0

autoslug在过去对我来说表现得非常好。虽然我从未尝试过在管理应用程序中使用它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接