2010-07-19 5 views
6

J'ai créé un formulaire pour enregistrer une recette. Il utilise une forme et un formset en ligne. J'ai des utilisateurs avec des fichiers texte contenant des recettes et ils aimeraient couper et coller les données pour faciliter l'entrée. J'ai calculé comment peupler la partie de formulaire après avoir traité l'entrée de texte brut mais je n'arrive pas à comprendre comment peupler le formset en ligne.Données initiales pour les ensembles de formulaires en ligne Django

Il me semble que la solution est presque épelée ici: http://code.djangoproject.com/ticket/12213 mais je ne peux pas tout à fait mettre les pièces ensemble.

Mes modèles:

#models.py 

from django.db import models 

class Ingredient(models.Model): 
    title = models.CharField(max_length=100, unique=True) 

    class Meta: 
     ordering = ['title'] 

    def __unicode__(self): 
     return self.title 

    def get_absolute_url(self): 
     return self.id 

class Recipe(models.Model): 
    title = models.CharField(max_length=255) 
    description = models.TextField(blank=True) 
    directions = models.TextField() 

    class Meta: 
     ordering = ['title'] 

    def __unicode__(self): 
     return self.id 

    def get_absolute_url(self): 
     return "/recipes/%s/" % self.id 

class UnitOfMeasure(models.Model): 
    title = models.CharField(max_length=10, unique=True) 

    class Meta: 
     ordering = ['title'] 

    def __unicode__(self): 
     return self.title 

    def get_absolute_url(self): 
     return self.id 

class RecipeIngredient(models.Model): 
    quantity = models.DecimalField(max_digits=5, decimal_places=3) 
    unit_of_measure = models.ForeignKey(UnitOfMeasure) 
    ingredient = models.ForeignKey(Ingredient) 
    recipe = models.ForeignKey(Recipe) 

    def __unicode__(self): 
     return self.id 

La forme de recette est créée en utilisant un ModelForm:

class AddRecipeForm(ModelForm): 
    class Meta: 
     model = Recipe 
     extra = 0 

Et le code correspondant dans la vue (appels pour analyser les entrées utilisées sous forme sont supprimés):

def raw_text(request): 
    if request.method == 'POST': 

    ...  

     form_data = {'title': title, 
        'description': description, 
        'directions': directions, 
        } 

     form = AddRecipeForm(form_data) 

     #the count variable represents the number of RecipeIngredients 
     FormSet = inlineformset_factory(Recipe, RecipeIngredient, 
         extra=count, can_delete=False) 
     formset = FormSet() 

     return render_to_response('recipes/form_recipe.html', { 
       'form': form, 
       'formset': formset, 
       }) 

    else: 
     pass 

    return render_to_response('recipes/form_raw_text.html', {}) 

Avec le formulaire vide() vide comme ci-dessus, je peux lancer la page avec succès. J'ai essayé quelques façons de nourrir la formset la quantité, unit_of_measure et ingrédients que j'ai identifiés, notamment:

  • définition des données initiales, mais cela ne fonctionne pas pour formsets inline
  • passant un dictionnaire, mais qui génère la gestion forme des erreurs
  • joué avec mais je initialisation suis un peu hors de ma profondeur il

Toutes les suggestions très appréciées.

Répondre

19

Ma première suggestion serait de prendre la voie simple de sortir: enregistrer les Recipe et RecipeIngredient s, puis utilisez le Recipe résultant comme par exemple lors de la FormSet. Vous pouvez ajouter un champ booléen "révisé" à vos recettes pour indiquer si les formsets ont ensuite été approuvés par l'utilisateur.

Cependant, si vous ne voulez pas aller dans cette voie pour une raison quelconque, vous devriez être en mesure de remplir vos formsets comme ceci:

Nous supposons que vous avez analysé les données textuelles dans les ingrédients de la recette et une liste de dictionnaires comme celui-ci:

recipe_ingredients = [ 
    { 
     'ingredient': 2, 
     'quantity': 7, 
     'unit': 1 
    }, 
    { 
     'ingredient': 3, 
     'quantity': 5, 
     'unit': 2 
    }, 
] 

les chiffres dans les champs « ingrédient » et « unité » sont les valeurs clés primaires pour les ingrédients respectifs et les unités d'objets de mesure. Je suppose que vous avez déjà formulé un moyen de faire correspondre le texte aux ingrédients de votre base de données, ou en créer de nouveaux.

Vous pouvez alors faire:

RecipeFormset = inlineformset_factory(
    Recipe, 
    RecipeIngredient, 
    extra=len(recipe_ingredients), 
    can_delete=False) 
formset = RecipeFormset() 

for subform, data in zip(formset.forms, recipe_ingredients): 
    subform.initial = data 

return render_to_response('recipes/form_recipe.html', { 
    'form': form, 
    'formset': formset, 
    }) 

Ceci définit la propriété initial de chaque formulaire dans le formset à un dictionnaire de votre liste recipe_ingredients. Cela semble fonctionner pour moi en termes d'affichage du formset, mais je n'ai pas encore essayé de l'enregistrer.

+0

Bon conseil Aram, merci beaucoup. Je vais essayer les options aujourd'hui. J'aime particulièrement avoir une option facile ... – Sinidex

+0

Utiliser zip fonctionne vraiment et je peux confirmer que la sauvegarde du formulaire fonctionne aussi bien. J'ai encore besoin de construire en faisant correspondre le texte analysé avec les ingrédients et les unités de mesure pertinents, comme vous l'avez souligné, mais je pense que cela devrait être gérable. Excellente solution – Sinidex

+1

Oui oui et oui. C'est une excellente solution! J'ai eu du mal à y parvenir. Je cherchais d'abord à construire chaque forme de l'ensemble. Puis réalisé initial * does * travail, sur une base de formulaire (pas formset). Dans zip nous faisons confiance ™ – Flowpoke

0

Je ne pouvais pas faire Aram Code Dulyan fonctionne sur ce

for subform, data in zip(formset.forms, recipe_ingredients): 
    subform.initial = data 

Apparemment, quelque chose a changé sur django 1.8 que je ne peux pas itérer un cached_property

formes - django.utils.functional. objet cached_property à 0x7efda9ef9080

J'ai eu cette erreur

argument zip # 1 doit prendre en charge l'itération

Mais je prends toujours le dictionnaire et l'attribuer directement à mon formset et cela a fonctionné, je pris l'exemple d'ici:

https://docs.djangoproject.com/en/dev/topics/forms/formsets/#understanding-the-managementform

de django.forms importer formset_factory de myapp.forms importer ArticleForm

ArticleFormSet = formset_factory(ArticleForm, can_order=True) 
formset = ArticleFormSet(initial=[ 
    {'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)}, 
    {'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)}, 
]) 

Mon code sur assigner formset au modèle

return self.render_to_response(
self.get_context_data(form=form, inputvalue_numeric_formset=my_formset(initial=formset_dict) 
Questions connexes