2010-07-19 2 views
6

Я собрал форму для сохранения рецепта. Он использует форму и встроенный набор форм. У меня есть пользователи с текстовыми файлами, содержащими рецепты, и они хотели бы вырезать и вставить данные, чтобы сделать запись проще. Я разработал, как заполнить часть формы после обработки исходного ввода текста, но я не могу понять, как заполнить встроенный набор форм.Исходные данные для встроенных форм Django

Похоже, что решение почти прописано здесь: http://code.djangoproject.com/ticket/12213, но я не могу собрать все вместе.

Мои модели:

#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 

Форма рецепт создается с помощью ModelForm:

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

И соответствующий код в представлении (звонки разобрать форму входа будут удалены):

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

С FormSet() пустым, как указано выше, я могу успешно запустить страницу. Я попробовал несколько способов накормить formset количества, unit_of_measure и ингредиенты я идентифицированный в то числе:

  • ввод исходных данных, но это не работает для встроенного FormSets
  • проходящего словарь, но генерирует управление ошибки формы
  • играл с INIT, но я немного из моей глубины там

Любые предложения с благодарностью.

ответ

19

Мое первое предложение было бы взять простой выход: сохранить Recipe и RecipeIngredient с, а затем использовать полученный Recipe как экземпляр при создании FormSet. Возможно, вы захотите добавить в свои рецепты «проверенное» логическое поле, чтобы указать, были ли эти формы затем одобрены пользователем.

Однако, если вы не хотите идти по этому пути, по какой-либо причине, вы должны быть в состоянии заполнить ваши FormSets как это:

Мы предполагаем, что вы разобраны текстовые данные в рецептурные ингредиенты и есть список словарей, как эта:

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

цифры в «ингредиенте» и поле «единиц» являются значением первичного ключа для соответствующих компонентов и узлов объектов измерения. Я предполагаю, что вы уже сформулировали какой-то способ сопоставления текста с ингредиентами в вашей базе данных или создания новых.

Вы можете сделать:

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

Это устанавливает initial свойства каждого вида в formset к словарю из вашего recipe_ingredients списка. Кажется, это работает для меня с точки зрения отображения набора форм, но я еще не попытался сохранить.

+0

Большой совет Арам, большое вам спасибо. Я попробую варианты сегодня. Мне особенно нравится иметь простой вариант ... – Sinidex

+0

Использование zip определенно работает, и я могу подтвердить, что сохранение формы в обычной моде также работает. Мне все еще нужно построить соответствующий синтаксический анализ соответствующим ингредиентам и единицам измерения объекта, как вы указали, но я думаю, что это должно быть управляемым. Отличное решение. – Sinidex

+1

Да, да и да. Это отличное решение! Мне было трудно добраться до этого. Сначала я изучал, как создавать каждую форму в наборе. Затем реализована начальная * * работа, на основе формы (не formet). В zip мы доверяем. – Flowpoke

0

Я не мог сделать Арам Дулян код работает на этом

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

Видимо что-то изменилось на Джанго 1.8, что я не могу итерацию cached_property

формы - django.utils.functional. объект cached_property на 0x7efda9ef9080

Я получил эту ошибку

почтовый аргумент # 1 должен поддерживать итерационный

Но я все-таки взять словарь и назначить его непосредственно к моему formset, и она работала, я взял пример отсюда:

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

от django.forms импорта formset_factory из myapp.forms импорта 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)}, 
]) 

Мой код по присвойте набор форм к шаблону

return self.render_to_response(
self.get_context_data(form=form, inputvalue_numeric_formset=my_formset(initial=formset_dict) 
Смежные вопросы