2010-11-09 18 views
10

Tengo dos modelos relacionados por una clave externa:de entrada de forma libre para ForeignKey campo en un Django ModelForm

# models.py  
class TestSource(models.Model): 
    name  = models.CharField(max_length=100) 

class TestModel(models.Model): 
    name  = models.CharField(max_length=100) 
    attribution = models.ForeignKey(TestSource, null=True) 

Por defecto, un Django ModelForm presentará como un <select> con <option> s; sin embargo, preferiría que esta función fuera una entrada de forma libre, <input type="text"/>, y detrás de escena obtener o crear el objeto TestSource necesario y luego relacionarlo con el objeto TestModel.

he tratado de definir un ModelForm costumbre y Campo de lograr esto:

# forms.py 
class TestField(forms.TextInput): 
    def to_python(self, value): 
    return TestSource.objects.get_or_create(name=value) 

class TestForm(ModelForm): 
    class Meta: 
    model=TestModel 
    widgets = { 
     'attribution' : TestField(attrs={'maxlength':'100'}), 
    } 

Por desgracia, me estoy haciendo: invalid literal for int() with base 10: 'test3' cuando se trata de comprobar is_valid en el formulario enviado. ¿Dónde estoy equivocado? ¿Es su y más fácil forma de lograr esto?

Respuesta

11

Algo como esto debería funcionar:

class TestForm(ModelForm): 
    attribution = forms.CharField(max_length=100) 

    def save(self, commit=True): 
     attribution_name = self.cleaned_data['attribution'] 
     attribution = TestSource.objects.get_or_create(name=attribution_name)[0] # returns (instance, <created?-boolean>) 
     self.instance.attribution = attribution 

     return super(TestForm, self).save(commit) 

    class Meta: 
    model=TestModel 
    exclude = ('attribution') 
+0

Esto ayuda mucho. Pero todavía tengo algunos problemas, ¿se requerirá algún código no estándar en la vista? Mina explota en is_valid() marca todavía: no se puede asignar "u'myString '": "TestModel.attribution" debe ser una instancia de "TestSource". – brown145

+1

@ brown145: Creo que debe excluir la atribución, de lo contrario, intentará validarla. Ver mi respuesta actualizada. – sdolan

1

Aquí hay algunos problemas.

En primer lugar, ha definido un campo, no un widget, por lo que no puede usarlo en el diccionario widgets. Tendrá que anular la declaración de campo en el nivel superior del formulario.

En segundo lugar get_or_create devuelve dos valores: el objeto recuperado o creado, y un booleano para mostrar si fue creado o no. Realmente solo desea devolver el primero de esos valores desde su método to_python.

No estoy seguro si alguno de ellos causó su error real sin embargo. Para asegurarnos, debe publicar el rastreo real.

0

TestForm.attribution espera valor int - clave para el modelo TestSource.

Tal vez esta versión del modelo será más conveniente para usted:

class TestSource(models.Model): 
    name = models.CharField(max_length=100, primary_key=True) 
Cuestiones relacionadas