用pre_save()填充django字段?

Der*_*rek 46 python database django triggers model

class TodoList(models.Model):
    title = models.CharField(maxlength=100)
    slug = models.SlugField(maxlength=100)
    def save(self):
        self.slug = title
        super(TodoList, self).save()
Run Code Online (Sandbox Code Playgroud)

我假设上面是如何在将标题插入表TodoList时如何创建和存储slug,如果没有,请纠正我!

无论如何,我一直在研究pre_save()作为另一种方法,但无法弄清楚它是如何工作的.你如何用pre_save()做到这一点?

是这样的

def pre_save(self):
     self.slug = title
Run Code Online (Sandbox Code Playgroud)

我猜不是.这样做的代码是什么?

谢谢!

Ber*_*ant 73

你很可能指的是django的pre_save信号.你可以设置这样的东西:

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

@receiver(pre_save)
def my_callback(sender, instance, *args, **kwargs):
    instance.slug = slugify(instance.title)
Run Code Online (Sandbox Code Playgroud)

如果你没有在装饰器中包含sender参数@receiver(pre_save, sender=MyModel),那么将为所有模型调用回调.

您可以将代码放在应用程序执行期间解析的任何文件中,这models.py是一个很好的地方.

  • 更好?它基本上是一样的...如果你想改变一个现有的应用程序的功能,信号是肯定的首选方式... (10认同)
  • @Derek:只需覆盖`save()`.它更简单,更容易预测. (9认同)
  • 在QuerySets上使用update方法时,@ simon-steinberger pre_save被_not_调用 - [Django docs](https://docs.djangoproject.com/en/1.10/ref/models/querysets/#update)说"最后,意识到update()在SQL级别进行更新,因此不会在模型上调用任何save()方法,也不会发出pre_save或post_save信号(这是调用Model.save()的结果) ". (6认同)
  • 惊人的。这个答案应该包含在 Django 文档中。文档中确实没有关于使用“信号”的示例。 (3认同)

小智 24

@receiver(pre_save, sender=TodoList)
def my_callback(sender, instance, *args, **kwargs):
    instance.slug = slugify(instance.title)
Run Code Online (Sandbox Code Playgroud)


Eya*_* Ch 13

你可以使用django signals.pre_save:

from django.db.models.signals import post_save, post_delete, pre_save

class TodoList(models.Model):
    @staticmethod
    def pre_save(sender, instance, **kwargs):
        #do anything you want

pre_save.connect(TodoList.pre_save, TodoList, dispatch_uid="sightera.yourpackage.models.TodoList") 
Run Code Online (Sandbox Code Playgroud)

  • 无论出于何种原因,接受的解决方案对我来说不起作用。但是,这个干净而优雅的解决方案做到了。 (2认同)

Mar*_*ers 12

pre_save()信号挂钩确实是一个伟大的地方,把手slugification了大量的模型。诀窍是知道哪些模型需要生成 slug,哪些字段应该是 slug 值的基础。

我为此使用了一个类装饰器,它可以让我标记用于自动生成的模型,以及它基于什么字段:

from django.db import models
from django.dispatch import receiver
from django.utils.text import slugify

def autoslug(fieldname):
    def decorator(model):
        # some sanity checks first
        assert hasattr(model, fieldname), f"Model has no field {fieldname!r}"
        assert hasattr(model, "slug"), "Model is missing a slug field"

        @receiver(models.signals.pre_save, sender=model, weak=False)
        def generate_slug(sender, instance, *args, raw=False, **kwargs):
            if not raw and not instance.slug:
                source = getattr(instance, fieldname)
                slug = slugify(source)
                if slug:  # not all strings result in a slug value
                    instance.slug = slug
        return model
    return decorator
Run Code Online (Sandbox Code Playgroud)

这只会为特定模型注册一个信号处理程序,并允许您使用每个模型来改变源字段:

@autoslug("name")
class NamedModel(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField()

@autoslug("title")
class TitledModel(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField()
Run Code Online (Sandbox Code Playgroud)

请注意,不会尝试生成唯一的slug 值。这将需要检查事务中的完整性异常,或者在足够大的池中使用 slug 中的随机值来避免发生冲突。完整性异常检查只能在save()方法中完成,不能在信号钩子中完成。