2015-11-22 1 views
0

La plupart des questions à ce sujet semblent être axées sur la réduction des tables m2m. Je suis curieux de savoir comment afficher les champs de la table intermédiaire dans une (ou deux) formes combinées.Django: Affichage des champs des tables intermédiaires dans les formulaires

L'idée est que j'ai beaucoup de ressources et de nombreux repas. Différents repas peuvent avoir la même ressource, mais en quantités différentes. Dire: Burrito a x lb de boeuf, mais les fajitas ont y.

Je veux créer un formulaire pour éditer le repas Burrito afin que je puisse voir/éditer/créer: Le nom du repas, les ressources dans le repas, et la quantité associée à la ressource dans ce repas. Mon code actuel affiche un formulaire avec tous, mais les montants associés aux ressources via la table m2m

J'ai deux modèles reliés par une table intermédiaire:

class Resource(models.Model): 
    name = models.CharField(max_length=200) 
    unit = models.ForeignKey(Unit) 
    units_per_pack = models.PositiveSmallIntegerField() 
    packs_per_case = models.PositiveSmallIntegerField() 
    allergens = models.ManyToManyField(Allergen, blank=True) 

class Meal(models.Model): 
    name = models.CharField(max_length=200) 
    resources=models.ManyToManyField(Resource,through='MealResourceRelationship') 
    recipe = models.TextField(default='') 

class MealResourceRelationship(models.Model): 
    resource = models.ForeignKey(Resource) 
    meal = models.ForeignKey(Meal) 
    units_per_person = models.DecimalField(max_digits=19,decimal_places=2) 

J'essaie d'utiliser un ModelForm simple vu ci-dessous:

class MealForm(forms.ModelForm): 
    class Meta: 
    model = Meal 
    fields = '__all__' 

avec ce point de vue:

def meal_edit(request, pk=None, template_name='foodstuffs/meal_edit.html'): 
    if id: 
     meal = get_object_or_404(Meal, pk=pk) 
    else: 
     meal = Meal() 
    if request.POST: 
     form = MealForm(request.POST,instance=meal) 
     if form.is_valid(): 
      meal_mod = form.save(commit=False) 
      meal_mod.save() 

      # remove existing resources                                          
      meal_mod.resources.clear() 
      for resource in form.cleaned_data.get('resources'): 
       meal_resource_rel = MealResourceRelationship(meal=meal_mod, 
                  resource=resource, 
                  units_per_person=1) 
       meal_resource_rel.save() 
      # messages.add_message(request, messages.SUCCESS, _('Meal correctly saved.'))                              
      # If the save was successful, redirect to another page                                   
      redirect_url = reverse('meal_list') 
      return HttpResponseRedirect(redirect_url) 
    else: 
     form = MealForm(instance=meal) 

    args = {} 
    args.update(csrf(request)) 
    args['form'] = form 
    args['meal'] = meal 
    return render_to_response(template_name, args) 

Tous Des idées? Je vous remercie!

Répondre

0

Basé sur la solution qui offre Django (peu de formes complètement personnalisées), je pense qu'il est plus facile de regarder ce problème en deux parties:

  1. Comment fournir un formulaire pour tous les MealResourceRelationships qui sont liée à un repas
  2. donnée Comment afficher la forme du numéro 1 à côté de la forme pour le repas se

la réponse au numéro 1 réside dans Formsets, qui permettent plusieurs instances d'un formulaire à rendre ensemble. Pour votre cas spécifique, où vous souhaitez que ces instances soient liées à un objet parent (un repas), vous êtes intéressé par Inline Formsets, qui vous permet de rendre plusieurs instances d'un formulaire lié par une clé étrangère. Voir ce post pour voir comment utiliser les formsets en ligne w/m2m à travers les relations.

Pour la partie 2) vous avez juste besoin de rendre à la fois le formulaire original et le formset inline à la même page. Voir ce post pour un exemple.

Sur la base de ce que vous pouvez mettre à jour votre point de vue comme suit:

def meal_edit(request, pk=None, template_name='foodstuffs/meal_edit.html'): 
    # ADDED: Created an inline formset factory for the meal resource relationship 
    MealResourceFormset = forms.inlineformset_factory(Meal, Meal.resources.through, exclude=[]) 

    if id: 
     meal = get_object_or_404(Meal, pk=pk) 
    else: 
     meal = Meal() 

    if request.POST: 
     form = MealForm(request.POST, instance=meal) 
     if form.is_valid(): 
      meal_mod = form.save(commit=False) 
      meal_mod.save() 

      # remove existing resources                
      meal_mod.resources.clear() 
      for resource in form.cleaned_data.get('resources'): 
       meal_resource_rel = MealResourceRelationship(meal=meal_mod, 
                 resource=resource, 
                 units_per_person=1) 
       meal_resource_rel.save() 
      # messages.add_message(request, messages.SUCCESS, _('Meal correctly saved.'))    
      # If the save was successful, redirect to another page         
      redirect_url = reverse('meal_list') 
      return HttpResponseRedirect(redirect_url) 
    else: 
     # ADDED/EDITED: create both the meal form and resource formsets 
     meal_form = MealForm(instance=meal) 
     resource_formset = MealResourceFormset(instance=meal)               

    args = {} 
    args.update(csrf(request)) 
    args['form'] = meal_form 
    # ADDED: pass through resource_formset to template 
    args['formset'] = resource_formset 
    args['meal'] = meal 
    return render_to_response(template_name, args) 

Vous devrez également mettre à jour votre modèle pour rendre le formset, et mettre à jour MealForm ne pas rendre le domaine des ressources (puisque vous rendre via le formset). Vous pouvez personnaliser chaque partie en modifiant les formulaires pour chacun d'entre eux.

J'espère que cela vous aidera en tant que starter et bonne chance avec votre projet!