2012-04-12 10 views
2

Ich versuche, ModelForms in Django zu verwenden, um Inhalt zu meiner Datenbank hinzuzufügen, die ein ManyToManyField enthält. Hier ist der relevante Teil meines Modell:Django: ManyToManyField, Objekt hinzufügen, wenn es noch nicht existiert

class Category(models.Model): 
    name = models.CharField(max_length=100) 
    description = models.TextField() 

    def __unicode__(self): 
     return self.name 

class Recipe(models.Model): 
    title = models.CharField(max_length=100) 
    body = models.TextField() 
    user = models.ForeignKey(User) 
    image = models.ImageField(upload_to='images/recipethumbs/', null = True, blank=True) 
    ingredients = models.ManyToManyField(Ingredient, through="IngredientMap") 
    categories = models.ManyToManyField(Category) 
    citation = models.CharField(max_length=200) 

    def __unicode__(self): 

Standardmäßig werden die ManyToManyFields durch eine Multiple-Choice-Auswahl vertreten. Dadurch können Benutzer aus bereits vorhandenen Feldern im Kategorieobjekt auswählen. Ich möchte dies ändern, damit Benutzer entweder Kategorien auswählen können, wenn sie derzeit vorhanden sind, oder neue hinzufügen, wenn dies nicht der Fall ist. Dies würde scheinbar geschehen, indem das Widget zu einem TextInput geändert wird.

class RecipeForm(ModelForm): 
    class Meta: 
     model = Recipe 
     widgets = { 
      'categories': TextInput(attrs={'size': 40,}), 
      'ingredients': Textarea, 
     } 

Aber wenn ein Benutzer eine Kategorie geht, die derzeit nicht in der Tabelle Kategorien vorhanden ist, dann klagt Django, dass ich „um eine Liste der Werte eingeben“ muß. Wie kann ich das Formular zu hinzufügen eine neue Kategorie, wenn es nicht bereits existiert?

Meine Lösung in einem benutzerdefinierten .save() als Ilvar vorgeschlagen: manuell

categories = re.findall(r'\w+[\w\s]+', self.cleaned_data.get('categories')) #returns an array 

     if commit: 
      m.save() 

     # You can only assign m2m if the Recipe object has been saved. 
     for category in categories: 
      try: 
       category_in_db = Category.objects.get(name=category) 
      except: 
       category_in_db = None 
      if category_in_db: 
       m.categories.add(category_in_db) 
      else: 
       m.categories.create(name=category) 

     return m 
+0

Wie auf der Erde erwarten Sie, dass Django in dieser Situation wissen, was mit Daten von einer Texteingabe zu tun ist? Ihr Kategoriemodell verfügt über ein erforderliches Beschreibungsfeld für einen Start, sodass dieses Problem sogar mit einem benutzerdefinierten Widget nicht lösbar ist. – Greg

+1

Ich erwarte nicht, dass es weiß, was damit zu tun ist. Ich würde es gerne erzählen, wenn ich eine Idee hätte, wie ... – bento

Antwort

1

Sie müssen exclude m2m-Feld aus dem Formular und fügen Sie ein CharField selbst Klasse bilden. Überschreiben Sie dann __init__, um dieses Feld in initial und save zu setzen. In save können Sie tun, was Sie wollen, um den Text in cleaned_data. Ich denke, in Ihrem Fall wird es durch Kommas geteilt werden, get_or_creating eine Kategorie für jeden Wert, und Zuordnung von Kategorie Liste zu dem Feld in Objekt nach dem Speichern des Elternformulars und vor dem Zurückgeben des Ergebnisses. Vielleicht fügen Sie auch einige autocomplete hinzu, um auf der Clientseite zu vermeiden.

+0

Ah, ich verstehe. Das macht Sinn. Danke ilvar. – bento

Verwandte Themen