2015-10-29 2 views
7

Ich habe zwei verwandte Instanzen, die immer zusammen erstellt werden sollten. Ich möchte dies tun, ohne Signale zu verwenden oder die save() Methode des Modells zu überschreiben.Django 1.8 benutzerdefinierter Manager und .create() -Methode wird nicht von .update_or_create() verwendet

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)   

Ich habe eine benutzerdefinierte CarManager erstellt, die models.Manager.create überschreibt(), um die Schaffung von CarProfile, um sicherzustellen, wenn ein Auto angelegt:

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 

Als ich Car.objects.create(make='Audi', model='R8') nennen, ein neues Auto Instanz und sein entsprechendes CarProfile wird wie erwartet erstellt. Wenn ich jedoch versuche, ein neues Auto mit Car.objects.update_or_create(make='Audi', model='R8') oder Car.objects.get_or_create(make='Audi', model='R8') zu erstellen, wird in beiden Fällen eine Car-Instanz erstellt, aber kein entsprechendes CarProfile erstellt.

Warum nicht update_or_create und get_or_create produziert das erwartete CarProfile Beispiel, wenn ich dieses Verhalten in den benutzerdefinierten create() method angegeben habe?

Es scheint, dass diese beiden Methoden die create() Klasse von QuerySet statt meiner benutzerdefinierten aufrufen.

Antwort

3

Djangos Manager Klasse ist eigentlich eine QuerySet, die reconstituted in eine Manager wurde. Was ist, wenn Sie create auf einem QuerySet implementieren und dann einen Manager daraus bauen?

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 

Dann wird die Car ist:

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

Ich habe bemerkt, wie ein Manager wirklich von 'BaseManager.from_queryset (QuerySet)' vererbt wird. Ich kann falsch liegen, aber es scheint, ['from_queryset'] (https://goo.gl/1L0x8N) und [' _get_queryset_methods'] (https://goo.gl/uEssIf) eine Ad-hoc-Klasse für Manager zu erstellen Unterklasse, die über beliebige Methoden in 'QuerySet' kopiert, die nicht in 'BaseManager' definiert sind. Meine 'CarManager'-Klasse unterklassifiziert dann diese Ad-hoc-Klasse, so dass ich verwirrt bin, warum 'create' das' QuerySet' nicht nur für' update_and_create' und 'get_or_create' überschreibt. – lajitong

+1

Auch @Nathan Villaescusa, danke für Ihre Antwort. Ich habe am Ende ein benutzerdefiniertes "CarQuerySet" erstellt und eine Instanz davon in "get_queryset" von "CarManager" (ich habe andere Manager-Methoden dort) zurückgegeben. 'update_and_create' und' get_or_create' haben jetzt das korrekte Verhalten. Aber ich frage mich immer noch, warum meine vorherige Implementierung nicht funktioniert hat. – lajitong

2

Der eigentliche Grund, dass create überschrieben ist in diesem Fall nicht funktioniert, weil Sie außer Kraft setzen müssen, um sowohl die update_and_create und die get_or_create Methoden sowie create zu beeinflussen ihr Verhalten.

Verwandte Themen