Исходные данные для встроенных форм Django - PullRequest
7 голосов
/ 19 июля 2010

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

Кажется, что решение здесь почти прописано: 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 (), как указано выше, я могу успешно запустить страницу.Я пробовал несколько способов подачи в форму набора количества, unit_of_measure и ингредиентов, которые я определил, в том числе:

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

Любые предложения приветствуются.

Ответы [ 2 ]

20 голосов
/ 19 июля 2010

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

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

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

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 каждой формы в наборе форм в словарь из вашего списка recipe_ingredients. Кажется, это работает для меня с точки зрения отображения набора форм, но я еще не пробовал сохранять.

1 голос
/ 30 января 2016

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

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

Очевидно, что в django 1.8 что-то изменилось, и я не могу перебрать cached_property

формы - объект django.utils.functional.cached_property по адресу 0x7efda9ef9080

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

zip-аргумент # 1 должен поддерживать итерацию

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

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)
...