2015-10-29 4 views
7

У меня есть два связанных экземпляра, которые всегда должны создаваться вместе. Я бы хотел сделать это без использования сигналов или переопределить метод модели save().Пользовательский менеджер Django 1.8 и метод .create() не используются .update_or_create()

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(), чтобы обеспечить создание 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') новый экземпляр автомобиля и его соответствующий CarProfile создается, как ожидалось. Однако, когда я пытаюсь создать новый автомобиль с использованием Car.objects.update_or_create(make='Audi', model='R8') или Car.objects.get_or_create(make='Audi', model='R8'), в обоих случаях создается экземпляр Car, но соответствующий CarProfile не создается.

Почему не update_or_create и get_or_create производят ожидаемый CarProfile случай, когда я указал, что поведение в обычае create() method?

Кажется, что оба этих метода вызывают create() от класса QuerySet вместо моего обычного.

ответ

3

Django's Manager класс на самом деле QuerySet, который был reconstituted в Manager. Что делать, если вы реализуете create на QuerySet, а затем постройте 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() 
+0

Я заметил, как менеджер действительно унаследован от 'BaseManager.from_queryset (QuerySet)'. Возможно, я ошибаюсь, но кажется ['from_queryset'] (https://goo.gl/1L0x8N) и [' _get_queryset_methods'] (https://goo.gl/uEssIf) создает специальный класс для Менеджера для подкласс, который копирует любые методы из 'QuerySet', не определенные в' BaseManager'. Мой класс 'CarManager' затем подклассифицирует этот ad-hoc-класс, поэтому я смущен тем, что' create' не переопределяет значение в QuerySet только для 'update_and_create' и' get_or_create'. – lajitong

+1

Кроме того, @Nathan Villaescusa, спасибо за ваш ответ. Я закончил создание пользовательского «CarQuerySet» и вернул экземпляр его в 'get_queryset'' CarManager' (у меня есть другие методы менеджера). 'update_and_create' и' get_or_create' теперь имеют правильное поведение. Но мне все еще интересно, почему моя предыдущая реализация не сработала. – lajitong

2

Фактическая причина того, что переопределение create не работает в данном случае, потому что вы должны переопределить как update_and_create и get_or_create методы, а также create повлиять их поведение.