Validatie van Django-modelvelden

Waar moet de validatie van modelveldenin django naartoe gaan?

Ik zou ten minste twee mogelijke keuzes kunnen noemen: in de overbelaste .save()-methode van het model of in de .to_python()-methode van de subklasse models.Field (natuurlijk moet je daarvoor aangepaste velden schrijven).

Mogelijke gebruiksscenario’s:

  • wanneer het absoluut noodzakelijk is om ervoor te zorgen dat er geen lege string in de database wordt geschreven (blank=Onwaar zoekwoordargument werkt hier niet, het is alleen voor formuliervalidatie)
  • wanneer het nodig is om ervoor te zorgen dat het trefwoordargument “keuzes” wordt gerespecteerd op db-niveau en niet alleen in de beheerdersinterface (een soort emulatie van een enum-gegevenstype)

Er is ook een attribuut op klasseniveau empty_strings_allowedin de modellen. De definitie van veldbasisklassen en afgeleide klassen overschrijven dit graag, maar het lijkt geen effect te hebben op het databaseniveau, wat betekent Ik kan nog steeds een model maken met velden met lege tekenreeksen en het in de database opslaan. Wat ik wil vermijden (ja, het is nodig).

Mogelijke implementaties zijn

op veldniveau:

class CustomField(models.CharField):
    __metaclass__ = models.SubfieldBase
    def to_python(self, value):
        if not value:
            raise IntegrityError(_('Empty string not allowed'))
        return models.CharField.to_python(self, value)

op modelniveau:

class MyModel(models.Model)
    FIELD1_CHOICES = ['foo', 'bar', 'baz']
    field1 = models.CharField(max_length=255, 
               choices=[(item,item) for item in FIELD1_CHOICES])
    def save(self, force_insert=False, force_update=False):
        if self.field1 not in MyModel.FIELD1_CHOICES:
            raise IntegrityError(_('Invalid value of field1'))
        # this can, of course, be made more generic
        models.Model.save(self, force_insert, force_update)

Misschien mis ik iets en kan dit makkelijker (en schoner)?


Antwoord 1, autoriteit 100%

Django heeft een modelvalidatie-systeem in plaats sinds versie 1.2.

In opmerkingen zegt sebpiq: “Ok, nu is er een plaats om modelvalidatie te plaatsen … behalve dat het alleen wordt uitgevoerd bij gebruik van een ModelForm! Dus de vraag blijft, wanneer het nodig is om ervoor te zorgen dat de validatie wordt gerespecteerd op de db-niveau, wat moet je doen? Waar moet je full_clean bellen?”

Het is niet mogelijk via validatie op Python-niveau om ervoor te zorgen dat validatie wordt gerespecteerd op db-niveau. De dichtstbijzijnde is waarschijnlijk om full_cleanaan te roepen in een overschreven save-methode. Dit wordt niet standaard gedaan, omdat het betekent dat iedereen die deze opslagmethode aanroept, nu beter voorbereid kan zijn om ValidationErrorop te vangen en af ​​te handelen.

Maar zelfs als u dit doet, kan iemand modelinstanties nog steeds bulksgewijs bijwerken met queryset.update(), waardoor deze validatie wordt omzeild. Django kan op geen enkele manier een redelijk efficiënte queryset.update()implementeren die nog steeds validatie op Python-niveau kan uitvoeren op elk bijgewerkt object.

De enige manier om integriteit op db-niveau echt te garanderen, is door beperkingen op db-niveau; elke validatie die u uitvoert via de ORM vereist dat de schrijver van app-code weet wanneer validatie wordt afgedwongen (en validatiefouten afhandelt).

Dit is de reden waarom modelvalidatie standaard alleen wordt afgedwongen in ModelForm– omdat er in een ModelForm al een voor de hand liggende manier is om een ​​ValidationErroraf te handelen.


Antwoord 2, autoriteit 9%

Ik denk dat je dit wilt ->

from django.db.models.signals import pre_save
def validate_model(sender, **kwargs):
    if 'raw' in kwargs and not kwargs['raw']:
        kwargs['instance'].full_clean()
pre_save.connect(validate_model, dispatch_uid='validate_models')

(Gekopieerd van http://djangosnippets.org/snippets/2319/)


Antwoord 3, autoriteit 4%

Het belangrijkste probleem hiervoor is dat de validatie op modellen moet plaatsvinden. Dit wordt al geruime tijd besproken in django (zoekformulier modelbewuste validatie op de dev-mailinglijst). Het leidt tot duplicatie of dingen die aan validatie ontsnappen voordat ze de db raken.

Hoewel dat de koffer niet raakt, heeft Malcolm’s “poor man’s model validatie-oplossing”is waarschijnlijk de schoonste oplossing om herhaling te voorkomen.


Antwoord 4

Als ik u “duidelijk” begrijp, moet u de functie get_db_prep_save overschrijven in plaats van to_python

Other episodes