【问题标题】:Django 1.8 custom manager and .create() method is not used by .update_or_create().update_or_create() 不使用 Django 1.8 自定义管理器和 .create() 方法
【发布时间】:2016-01-29 03:44:48
【问题描述】:

我有两个应该始终一起创建的相关实例。 我想在不使用信号或覆盖模型的save() 方法的情况下执行此操作

class Car(models.Mode):
    make = models.CharField(max_length=32)
    model = models.CharField(max_length=32)

    class Meta:
        unique_together = ('make', 'model',)

    objects = CarManager()

class CarProfile(models.Model):
    car = models.OneToOneField(Car)
    last_checkup = models.DateTimeField(blank=True, null=True)        

我创建了一个自定义 CarManager,它覆盖了 models.Manager.create() 以确保在创建 Car 时创建 CarProfile:

class CarManager(models.Manager):
    def create(self, **kwargs):
        with transaction.atomic():
            car = self.model(**kwargs)
            car.save(force_insert=True)
            CarProfile.objects.create(car=car)
        return car

当我调用Car.objects.create(make='Audi', model='R8') 时,会按预期创建一个新的 Car 实例及其对应的 CarProfile。然而,当我尝试使用Car.objects.update_or_create(make='Audi', model='R8')Car.objects.get_or_create(make='Audi', model='R8') 创建一辆新车时,在这两种情况下都会创建一个 Car 实例,但没有创建相应的 CarProfile。

当我在自定义 create() method 中指定该行为时,为什么 update_or_createget_or_create 不生成预期的 CarProfile 实例?

这两种方法似乎都是从QuerySet 类调用create() 而不是我自定义的。

【问题讨论】:

    标签: django django-models django-1.8


    【解决方案1】:

    Django 的Manager 类实际上是一个QuerySet,它已经将reconstituted 变成了Manager。如果您在QuerySet 上实现create,然后从中构建Manager 会怎样?

    class CarQuerySet(models.QuerySet):
    
        def create(self, **kwargs):
            with transaction.atomic():
                car = self.model(**kwargs)
                car.save(force_insert=True)
                CarProfile.objects.create(car=car)
            return car
    

    那么Car就是:

    class Car(models.Mode):
        make = models.CharField(max_length=32)
        model = models.CharField(max_length=32)
    
        class Meta:
            unique_together = ('make', 'model',)
    
        objects = CarQuerySet.as_manager()
    

    【讨论】:

    • 我注意到经理是如何真正从BaseManager.from_queryset(QuerySet) 继承而来的。我可能错了,但似乎from_queryset_get_queryset_methods 为Manager 创建了一个临时类以复制QuerySet 中未在BaseManager 中定义的任何方法。我的CarManager 类然后是那个临时类的子类,所以我很困惑为什么create 没有覆盖QuerySet 中的一个,仅适用于update_and_createget_or_create
    • 另外,@Nathan Villaescusa,感谢您的回复。我最终创建了一个自定义CarQuerySet 并在CarManagerget_queryset 中返回它的一个实例(我在那里有其他管理器方法)。 update_and_createget_or_create 现在有正确的行为。但我仍然想知道为什么我之前的实现不起作用。
    【解决方案2】:

    在这种情况下,覆盖create 不起作用的实际原因是您需要同时覆盖update_and_createget_or_create 方法以及create 以影响它们的行为。

    【讨论】:

    • 为什么不覆盖save,因为这似乎是它们的共同点。
    【解决方案3】:

    只是想澄清一下这个问题已在 Django v1.8a1 中得到解决。所以现在get_or_createupdate_or_create 都会按预期调用管理器create 方法。

    https://github.com/django/django/commit/0dce44e16be2d4850120cd333380ab9171c5964a

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-25
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      • 2019-06-17
      • 2013-05-04
      相关资源
      最近更新 更多