2009-10-12 5 views
11

En un formulario personalizado, ¿cómo valida uno la singularidad de un campo de modelo (es decir, tiene unique=True establecido)?¿Cómo validar/limpiar() un campo único = True sin usar un ModelForm?

sé que ModelForm de Django realiza automáticamente una función validate_unique() que se llama en el método de la BaseModelForm clean() - por lo que, cuando se utiliza ModelForm, esto será manejado correctamente (como lo es en la administración).

Sin embargo, estoy creando mi propia forma de cero y se preguntan cómo puedo ir sobre el manejo de este mismo? Creo que mi mayor escollo es saber qué objeto está unido a la forma cuando se está limpiando los datos ...

Algunos código:

class UserProfile(CreatedModifiedModel): 
    user   = models.ForeignKey(User, unique=True) 
    display_name = models.CharField('Display Name',max_length=30, 
         blank=True,unique=True) 

class EditUserProfileForm(forms.Form): 
    display_name = forms.CharField(required=False,max_length=30) 

    # "notifications" are created from a different model, not the UserProfile 
    notifications = forms.MultipleChoiceField(
         label="Email Notifications", 
         required=False, 
         widget=forms.CheckboxSelectMultiple,) 

    def clean_display_name(self): 
     # how do I run my own validate_unique() on this form? 
     # how do I know which UserProfile object I am working with? 

    # more code follows, including the __init__ which sets up the notifications 
+1

¿Hay alguna razón por la que está haciendo un formulario personalizado en lugar de un ModelForm? – tghw

+0

actualicé el código para mostrar el campo de "notificaciones" que necesito, que proviene de una aplicación diferente pero que se maneja en el mismo EditUserProfileForm ... espero que tenga sentido. No creo que pueda hacer un ModelForm a partir de múltiples fuentes de modelos ... – thornomad

Respuesta

15

validación único es difícil de conseguir toda la razón, por lo que lo haría recomendar el uso de un ModelForm de todos modos:

class EditUserProfileForm(forms.ModelForm): 
    # "notifications" are created from a different model, not the UserProfile 
    notifications = forms.MultipleChoiceField(
         label="Email Notifications", 
         required=False, 
         widget=forms.CheckboxSelectMultiple,) 

    class Meta: 
     model = UserProfile 
     fields = ('display_name',) 

Hacer una forma de múltiples modelos no es fácil, pero en este caso sólo se puede agregar el campo notifications en el ModelForm y sacarla de .cleaned_data como de costumbre:

# view 
if request.method == 'POST': 
    form = EditUserProfileForm(request.POST, instance=user_profile) 
    if form.is_valid(): 
     user_profile = form.save() 
     notifications = form.cleaned_data['notifications'] 
     # Do something with notifications. 

Así es como yo lo haría, pero si ya estás en la validación única ti mismo, siempre se puede hacer algo como:

def clean_display_name(self): 
    display_name = self.cleaned_data['display_name'] 
    if UserProfile.objects.filter(display_name=display_name).count() > 0: 
     raise ValidationError('This display name is already in use.') 
    return display_name 

Hay dos problemas que veo aquí. Primero, puede encontrarse con problemas de concurrencia, donde dos personas envían el mismo nombre, ambos pasan controles únicos, pero luego uno obtiene un error de DB. El otro problema es que no puede editar un perfil de usuario porque no tiene una ID para excluir de la búsqueda. Habría que almacenarlo en la __init__ y luego usarlo en la limpieza:

def __init__(self, *args, **kwargs): 
    ... 
    if 'instance' in kwargs: 
     self.id = kwargs['instance'].id 
    ... 

def clean_display_name(self): 
    display_name = self.cleaned_data['display_name'] 
    qs = UserProfile.objects.filter(display_name=display_name) 
    if self.id: 
     qs = qs.exclude(pk=self.id) 
    if qs.count() > 0: 
     raise ValidationError('This display name is already in use.') 
    return display_name 

Pero en ese momento sólo está duplicando la lógica en ModelForms.

+1

Hola, gracias por eso. No estaba seguro acerca de agregar campos a un ModelForm que no se corresponden con el modelo ... Pero intentaré esto para empezar. Si tengo problemas informaré. – thornomad

+0

tghw gracias hermano, gran respuesta – PyDroid

Cuestiones relacionadas