Django - 重写Model.create()方法?

时间:2010-02-21 23:39:05

标签: django django-models django-forms

Django docs仅列出覆盖save()delete()的示例。但是,我想为我的模型定义一些额外的处理,只有在创建它们时。对于熟悉Rails的人来说,它等同于创建:before_create过滤器。这可能吗?

6 个答案:

答案 0 :(得分:132)

覆盖__init__()会导致在实例化对象的python表示时执行代码。我不知道rails,但是:before_created过滤器听起来像是在数据库中创建对象时要执行的代码。如果要在数据库中创建新对象时执行代码,则应覆盖save(),检查对象是否具有pk属性。代码看起来像这样:

def save(self, *args, **kwargs):
    if not self.pk:
        # This code only happens if the objects is
        # not in the database yet. Otherwise it would
        # have pk
    super(MyModel, self).save(*args, **kwargs)

答案 1 :(得分:21)

如何创建post_save信号的示例(来自http://djangosnippets.org/snippets/500/

from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    """Create a matching profile whenever a user object is created."""
    if created: 
        profile, new = UserProfile.objects.get_or_create(user=instance)

这是一个深思熟虑的讨论,是否最好使用信号或自定义保存方法https://web.archive.org/web/20120815022107/http://www.martin-geber.com/thought/2007/10/29/django-signals-vs-custom-save-method/

在我看来,使用这个任务的信号更健壮,更容易阅读但更长。

答案 2 :(得分:5)

要按字面意思回答问题,模型管理器中的create方法是在Django中创建新对象的标准方法。要覆盖,请执行类似

的操作
from django.db import models

class MyModelManager(models.Manager):
    def create(self, **obj_data):
        # Do some extra stuff here on the submitted data before saving...
        # For example...
        obj_data['my_field'] = my_computed_value(obj_data['my_other_field'])

        # Now call the super method which does the actual creation
        return super().create(**obj_data) # Python 3 syntax!!

class MyModel(models.model):
    # An example model
    my_field = models.CharField(max_length=250)
    my_other_field = models.CharField(max_length=250)

    objects = MyModelManager()

在此示例中,我将覆盖Manager的方法create方法,以便在实际创建实例之前执行一些额外的处理。

注意:代码

my_new_instance = MyModel.objects.create(my_field='my_field value')

将执行此修改后的create方法,但代码类似

my_new_unsaved_instance = MyModel(my_field='my_field value')

不会。

答案 3 :(得分:3)

覆盖__init__()将允许您在实例化模型时执行代码。不要忘记给父母的__init__()打电话。

答案 4 :(得分:3)

您可以使用自定义管理器覆盖create方法,也可以在模型类上添加classmethod。 https://docs.djangoproject.com/en/1.11/ref/models/instances/#creating-objects

答案 5 :(得分:1)

首选答案是正确的,但是如果您的模型是从UUIDModel派生的,则无法判断对象是否正在创建的测试。 pk字段将已经有一个值。

在这种情况下,您可以这样做:

already_created = MyModel.objects.filter(pk=self.pk).exists()