2012-10-23 17 views
23

Sto ancora cercando di capire il modo corretto per convalidare un oggetto modello Django usando un validatore personalizzato a livello di modello. So che la convalida viene solitamente eseguita all'interno di una forma o di un modello. Tuttavia, voglio garantire l'integrità dei miei dati a livello di modello se sto interagendo con l'ORM nella shell Python. Ecco il mio approccio attuale:Modo corretto per convalidare gli oggetti del modello Django?

from django.db import models 
from django.core import validators 
from django.core exceptions import ValidationError 


def validate_gender(value): 
    """ Custom validator """ 
    if not value in ('m', 'f', 'M', 'F'): 
     raise ValidationError(u'%s is not a valid value for gender.' % value) 


class Person(models.Model): 
    name = models.CharField(max_length=128) 
    age = models.IntegerField() 
    gender = models.CharField(maxlength=1, validators=[validate_gender]) 

    def save(self, *args, **kwargs): 
     """ Override Person's save """ 
     self.full_clean(exclude=None) 
     super(Person, self).save(*args, **kwargs) 

Ecco le mie domande:

  1. Devo creare una funzione di validazione personalizzata, designare come un validatore, e quindi sovrascrivere della persona save() funzionano come I' hai fatto sopra? (A proposito, so che potrei convalidare le mie scelte di genere usando l'opzione di campo 'scelte' ma ho creato 'validate_gender' a scopo illustrativo).

  2. Se davvero voglia di garantire l'integrità dei dati, dovrei non solo scrivere unit test Django per i test a livello di modello, ma anche test di unità equivalenti a livello di database utilizzando Python/psycopg? Ho notato che i test delle unità Django, che aumentano ValidationErrors, testano solo la comprensione del modello dello schema del database utilizzando una copia del database. Anche se dovessi usare South per le migrazioni, tutti i vincoli a livello di database sono limitati a ciò che Django può capire e tradurre in un vincolo di Postgres. Se ho bisogno di un vincolo personalizzato che Django non può replicare, potrei potenzialmente inserire dati nel mio database che violano tale vincolo se sto interagendo con il database direttamente tramite il terminale psql.

Grazie!

+0

Non sono sicuro di come la domanda 1 sia diversa dalle precedenti domande su questo argomento. Si noti che non impedisce ancora l'inserimento di dati non validi utilizzando l'ORM. Si consideri 'Person.objects.update (gender = 'a')'. – Alasdair

+1

Sei corretto tranne che nella mia precedente domanda non ho incluso una funzione di validazione personalizzata come ho fatto qui. Per quanto riguarda la tua altra osservazione su. Aggiornamento, credo che ora ho un ulteriore problema che aggiunge alla mia confusione.Sto davvero lottando per capire qual è il modo giusto per farlo. Mentre i documenti di Django sono piuttosto buoni, IMHO, sono lunghi su frammenti e "mani che salutano", ma su esempi completi che potrebbero aiutare un "newb" come me a capire il modo corretto per risolvere questo problema. Sfortunatamente, lavoro da solo e non ho sviluppatori più esperti con cui discutere. – William

risposta

16

Ho avuto un malinteso analogo all'ORM quando ho iniziato con Django.

1) No, non inserire self.full_clean() all'interno di save. In entrambi i

A) utilizzare un ModelForm (che farà sì che lo stesso si verifichi convalida - nota: ModelForm.is_valid() non chiamerà Model.full_clean esplicitamente, ma si esibirà esattamente gli stessi controlli come Model.full_clean). Esempio:

class PersonForm(forms.ModelForm): 
    class Meta: 
     model = Person 

def add_person(request): 
    if request.method == 'POST': 
     form = PersonForm(request.POST, request.FILES) 
     if form.is_valid(): # Performs your validation, including ``validate_gender`` 
      person = form.save() 
      return redirect('some-other-view') 
    else: 
     form = PersonForm() 
     # ... return response with ``form`` in the context for rendering in a template 

Si noti inoltre, le forme non sono per l'uso solo in vista che le rendono nei modelli - sono grandi per qualsiasi tipo di utilizzo, tra cui un'API, ecc Dopo aver eseguito form.is_valid() e ottenere gli errori, avrai form.errors che è un dizionario che contiene tutti gli errori nel modulo, inclusa una chiave chiamata '__all__' che conterrà errori non di campo.

B) Utilizzare semplicemente model_instance.full_clean() nella vista (o altro livello di applicazione logico), invece di utilizzare un modulo, ma i moduli sono un'astrazione piacevole per questo.

2) Non ho davvero una soluzione, ma non ho mai incontrato un problema simile, anche in progetti di grandi dimensioni (il progetto attuale con cui lavoro la mia azienda ha 146 tabelle) e non lo faccio sospetto che anche nel tuo caso sarà una preoccupazione.

+2

Stai dicendo che dovrei usare un modulo o un modello per convalidare i miei modelli di dati anche se non sto effettivamente presentando l'oggetto modello in un modulo reale a un utente? Grazie. – William

+1

@RobertF. - è corretto. La classe 'ModelForm' è un'astrazione decente per la validazione del modello, sia che si aggiorni o crei istanze, anche quando non si intende visualizzare il modulo in un modello. – orokusaki

+1

Hai detto a A) fai questo, e qual è l'opzione B? – rgenito

Problemi correlati