2010-11-09 14 views
10

J'ai deux modèles liés par une clé étrangère:entrée-forme libre pour ForeignKey le terrain sur 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) 

Par défaut, un ModelForm django présentera cela comme un <select> avec <option> s; Cependant, je préférerais que cette fonction en tant qu'entrée de forme libre, <input type="text"/>, et en coulisse obtienne ou crée l'objet TestSource nécessaire, puis le relie à l'objet TestModel.

J'ai essayé de définir un ModelForm personnalisé et sur le terrain pour y parvenir:

# 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'}), 
    } 

Malheureusement, je reçois: invalid literal for int() with base 10: 'test3' en essayant de vérifier is_valid sur le formulaire soumis. Où vais-je mal? Est-ce leur moyen et plus facile d'accomplir cela?

Répondre

11

Quelque chose comme cela devrait fonctionner:

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

Cela aide beaucoup. Mais j'ai encore quelques problèmes, un code non standard serait-il nécessaire dans la vue? La mienne explose sur is_valid() check still: Impossible d'assigner "u'myString '": "TestModel.attribution" doit être une instance de "TestSource". – brown145

+1

@ brown145: Je pense que vous devez exclure l'attribution sinon il va essayer de le valider. Voir ma réponse mise à jour. – sdolan

1

Il y a quelques problèmes ici. Premièrement, vous avez défini un champ, pas un widget, donc vous ne pouvez pas l'utiliser dans le dictionnaire widgets. Vous devrez remplacer la déclaration de champ au niveau supérieur du formulaire.

Deuxièmement get_or_create renvoie deux valeurs: l'objet récupéré ou créé et un booléen pour indiquer s'il a été créé ou non. Vous voulez simplement renvoyer la première de ces valeurs à partir de votre méthode to_python.

Je ne suis pas sûr si l'un de ceux causé votre erreur réelle si. Vous devez poster le retraçage réel pour que nous soyons sûrs.

0

TestForm.attribution attend la valeur int - pour le modèle TestSource.

Peut-être que cette version du modèle sera plus pratique pour vous:

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