2010-12-14 15 views
108

Ich bin nur neugierig, ob jemand weiß, ob es einen guten Grund gibt, warum Djangos Orm 'full_clean' nicht auf einem Modell aufruft, es sei denn, es wird als Teil eines Modellformulars gespeichert.Warum ruft djangos model.save() full_clean() nicht auf?

Beachten Sie, dass full_clean() nicht automatisch aufgerufen wird, wenn Sie die save() -Methode Ihres Modells aufrufen. Sie müssen es manuell aufrufen, wenn Sie eine einstufige Modellüberprüfung für Ihre eigenen manuell erstellten Modelle durchführen möchten. django's full clean doc

(HINWEIS: Angebot für Django aktualisiert 1.6 ... vorherige django docs sowie einen Vorbehalt über ModelForms hatte.)

Gibt es gute Gründe, warum Menschen dieses Verhalten nicht wünschen würde? Ich würde denken, wenn Sie sich die Zeit nehmen würden, einem Modell eine Validierung hinzuzufügen, möchten Sie, dass diese Validierung jedes Mal ausgeführt wird, wenn das Modell gespeichert wird.

Ich weiß, wie man alles richtig funktioniert, ich suche nur nach einer Erklärung.

+6

Vielen Dank für diese Frage, es hat mich davon abgehalten, meinen Kopf gegen die Wand viel mehr Zeit zu schlagen. Ich habe ein Mixin erstellt, das anderen helfen könnte. Schauen Sie sich das Wesentliche an: https://gist.github.com/glarrain/5448253 – glarrain

+0

Und ich benutze endlich das Signal, um den 'pre_save' Haken zu fangen und' full_clean' an allen gefangenen Modellen. –

Antwort

44

AFAIK, das ist wegen der Abwärtskompatibilität. Es gibt auch Probleme mit ModelForms mit ausgeschlossenen Bereichen, Modelle mit Standardwerten, pre_save (Signale) usw.

Quellen Sie in Interessent könnte:

+2

Der hilfreichste Auszug (IMHO) aus der zweiten Referenz: "Entwicklung einer" automatischen "Validierungsoption, die einfach ist genug, um tatsächlich nützlich und robust genug zu sein, um alle Randfälle zu behandeln ist - wenn es sogar möglich ist - - weit mehr als erreicht werden kann auf dem 1.2 Zeitrahmen.Daher für jetzt, Django hat keine solche Sache, und wird es nicht in 1.2.Wenn Sie denken, dass Sie es für 1.3 arbeiten können, Ihr Am besten ist es, einen Vorschlag zu erarbeiten, der mindestens einen Beispielcode von enthält, zusammen mit einer Erklärung, wie Sie es einfach und robust halten. " – Josh

+1

Versuchen Sie dies: https://github.com/danielgatis/django-smart-save – danielgatis

18

Aus Gründen der Kompatibilität ist das automatische Löschen beim Speichern im Djangokernel nicht aktiviert.

Wenn wir ein neues Projekt starten und möchten, dass die Standardmethode save auf Model automatisch bereinigt wird, können wir das folgende Signal verwenden, um vor jedem Speichern des Modells zu bereinigen.

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

@receiver(pre_save) 
def pre_save_handler(sender, instance, *args, **kwargs): 
    instance.full_clean() 
+0

Warum ist das besser (oder schlechter) als die Save-Methode auf einigen BaseModel überschreiben (die alle anderen erben werden), zuerst full_clean aufzurufen, dann ruf super() an? –

+0

@J__ Offensichtlich gilt diese Methode für alle Modelle, nicht für eine bestimmte, so dass Sie einmal schreiben und überall verwenden können. Wenn Sie ein BaseModel überschreiben, müssen Sie für jedes Modell schreiben. –

+0

Jedoch schließt das Signal die Möglichkeit aus, später eine Ausnahme zu haben. Ich sehe nicht, warum ich eine Ausnahme machen müsste, aber es ist ein Nachteil. –

0

Statt ein Stück Code einzufügen, die einen Empfänger erklärt, können wir eine App als INSTALLED_APPS Abschnitt in settings.py

INSTALLED_APPS = [ 
    # ... 
    'django_fullclean', 
    # your apps here, 
] 

Davor verwenden, können Sie django-fullclean mit PyPI installieren müssen:

pip install django-fullclean 
+8

Warum würden Sie 'pip' installieren einige app mit 4 Zeilen Code darin (überprüfen Sie den [Quellcode] (https://github.com/fish-ball/django-fullclean/blob/master/django_fullclean/__init__.py)) anstatt diese Zeilen selbst zu schreiben? –

6

Der einfachste Weg, um die full_clean Methode aufzurufen, ist nur save Methode in Ihnen zu überschreiben r model:

def save(self, *args, **kwargs): 
    self.full_clean() 
    return super(YourModel, self).save(*args, **kwargs) 
+0

Warum ist das besser (oder schlechter) als ein Signal? –

+0

@J__ siehe Antwort http://StackOverflow.com/a/171703/6077223 –

+1

Ich sehe zwei Probleme mit diesem Ansatz 1) im Falle von ModelForms full_clean() würde zweimal aufgerufen werden: durch das Formular und durch das Speichern 2) Wenn Das Formular schließt einige Felder aus, sie würden dennoch durch das Speichern bestätigt. – mehmet

1

Wenn Sie ein Modell, das Sie sicherstellen wollen, mindestens eine FK-Beziehung hat, und Sie wollen nicht null=False verwenden, da das erfordert ein Standard-FK Einstellung (der Datenmüll würde) , der beste Weg, den ich gefunden habe, ist benutzerdefinierte .clean() und .save() Methoden hinzufügen. .clean() löst den Validierungsfehler aus, und .save() ruft das Clean auf. Auf diese Weise wird die Integrität sowohl von Formularen als auch von anderem Aufrufcode, der Befehlszeile und Tests erzwungen. Ohne dies gibt es (AFAICT) keine Möglichkeit, einen Test zu schreiben, der sicherstellt, dass ein Modell eine FK-Relation zu einem speziell gewählten (nicht standardmäßigen) anderen Modell hat.

class Payer(models.Model): 

    name = models.CharField(blank=True, max_length=100) 
    # Nullable, but will enforce FK in clean/save: 
    payer_group = models.ForeignKey(PayerGroup, null=True, blank=True,) 

    def clean(self): 
     # Ensure every Payer is in a PayerGroup (but only via forms) 
     if not self.payer_group: 
      raise ValidationError(
       {'payer_group': 'Each Payer must belong to a PayerGroup.'}) 

    def save(self, *args, **kwargs): 
     self.full_clean() 
     return super().save(*args, **kwargs) 

    def __str__(self): 
     return self.name 
Verwandte Themen