【问题标题】:How to save inline formset user field in Django using views如何使用视图在 Django 中保存内联表单集用户字段
【发布时间】:2017-03-21 13:33:43
【问题描述】:

我一直在使用这篇很棒的帖子 http://kevindias.com/writing/django-class-based-views-multiple-inline-formsets/ 来设置我的网站。我想知道如何将用户字段自动保存到视图中的内联表单集(我使用块引用来更改原始内容)。中的 RecipeForm(另见下文了解上下文)

self.object = form.save(commit=False)
self.object.owner = self.request.user
self.object.save()

自动保存很好,但不是

ingredient_form.owner= self.request.user

我知道 Django 建议使用 BaseInlineFormSet,但出于许多不同的原因,大多数人建议将用户字段保存在 views.py 而不是表单或模型中。我将不胜感激任何建议或答案。这是完整的代码:

models.py

from django.db import models


class Recipe(models.Model):
    owner = models.ForeignKey(User)
    title = models.CharField(max_length=255)
    description = models.TextField()


class Ingredient(models.Model):
    owner = models.ForeignKey(User)
    recipe = models.ForeignKey(Recipe)
    description = models.CharField(max_length=255)


class Instruction(models.Model):
    recipe = models.ForeignKey(Recipe)
    number = models.PositiveSmallIntegerField()
    description = models.TextField()

forms.py

from django.forms import ModelForm
from django.forms.models import inlineformset_factory 
from .models import Recipe, Ingredient, Instruction


class RecipeForm(ModelForm):
    class Meta:
        model = Recipe
    IngredientFormSet = inlineformset_factory(Recipe, Ingredient)
    InstructionFormSet = inlineformset_factory(Recipe, Instruction)

views.py

from django.http import HttpResponseRedirect
from django.views.generic import CreateView  
from .forms import IngredientFormSet, InstructionFormSet, RecipeForm
from .models import Recipe


class RecipeCreateView(CreateView):
    template_name = 'recipe_add.html'
    model = Recipe
    form_class = RecipeForm
    success_url = 'success/'

    def get(self, request, *args, **kwargs):
        """
        Handles GET requests and instantiates blank versions of the form
        and its inline formsets.
        """
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        ingredient_form = IngredientFormSet()
        instruction_form = InstructionFormSet()
        return self.render_to_response(
            self.get_context_data(form=form,
                                  ingredient_form=ingredient_form,
                                  instruction_form=instruction_form))

    def post(self, request, *args, **kwargs):
        """
        Handles POST requests, instantiating a form instance and its inline
        formsets with the passed POST variables and then checking them for
        validity.
        """
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        ingredient_form = IngredientFormSet(self.request.POST)
        instruction_form = InstructionFormSet(self.request.POST)
        if (form.is_valid() and ingredient_form.is_valid() and
            instruction_form.is_valid()):
            return self.form_valid(form, ingredient_form, instruction_form)
        else:
            return self.form_invalid(form, ingredient_form, instruction_form)

    def form_valid(self, form, ingredient_form, instruction_form):
        """
        Called if all forms are valid. Creates a Recipe instance along with
        associated Ingredients and Instructions and then redirects to a
        success page.
        """
        self.object = form.save(commit=False)
        self.object.owner = self.request.user
        self.object.save()
        ingredient_form.instance = self.object
        ingredient_form.owner= self.request.user
        ingredient_form.save()
        instruction_form.instance = self.object
        instruction_form.save()
        return HttpResponseRedirect(self.get_success_url())

    def form_invalid(self, form, ingredient_form, instruction_form):
        """
        Called if a form is invalid. Re-renders the context data with the
        data-filled forms and errors.
        """
        return self.render_to_response(
            self.get_context_data(form=form,
                                  ingredient_form=ingredient_form,
                                  instruction_form=instruction_form))

【问题讨论】:

    标签: python django django-views overriding inline-formset


    【解决方案1】:

    我做了一些更多的研究,按照如何添加custom formset saving 的指南,解决方案看起来有些复杂,但如上所述针对BaseInlineFormset 进行了修改。我意识到为每个模型制作 ModelForms 然后在视图中链接它们会更简单,因为在添加新配方视图中一次只需要一个子表单并且可以重用 ModelForm 代码。

    这是运行良好的新代码!如果您需要更多信息,请随时联系。

    forms.py

    from django.forms import ModelForm
    from .models import Recipe, Ingredient, Instruction
    
    
    class RecipeForm(ModelForm):
    
        class Meta:
            model = Recipe
            exclude = ['owner',]
    
    class IngredientForm(ModelForm):
    
        class Meta:
            model = Ingredient
            exclude = ['owner','recipe',]
    
    class InstructionForm(ModelForm):
    
        class Meta:
            model = Instruction
            exclude = ['recipe',]
    

    views.py

    from .forms import IngredientForm, InstructionForm, RecipeForm
    
    
    def add_new_value(request):
        rform = RecipeForm(request.POST or None)
        iform = IngredientForm(request.POST or None)
        cform = InstructionForm(request.POST or None)
        if rform.is_valid() and iform.is_valid() and cform.is_valid():
            rinstance = rform.save(commit=False)
            iinstance = iform.save(commit=False)
            cinstance = cform.save(commit=False)
            user = request.user
            rinstance.owner = user
            rinstance.save()
            iinstance.owner = user
            cinstance.owner = user
            iinstance.recipe_id = rinstance.id
            cinstance.recipe_id = rinstance.id
            iinstance.save()
            cinstance.save()
            return HttpResponseRedirect('/admin/')
        context = {
            'rform' : rform,
            'iform' : iform,
            'cform' : cform,
        }
        return render(request, "add_new_recipe.html", context)
    

    模板:add_new_recipe.html

    <!DOCTYPE html>
    <html>
    <head>
        <title>Add Recipe</title>
    </head>
    
    <body>
        <div>
            <h1>Add Recipe</h1>
            <form action="" method="post">
                {% csrf_token %}
                <div>
                    {{ rform.as_p }}
                    {{ iform.as_p }}
                    {{ cform.as_p }}
                </div>
                <input type="submit" value="Add recipe" class="submit" />
            </form>
        </div>
    </body>
    </html>
    

    【讨论】:

    • 很高兴我找到了这篇文章。我也试图用内联表单集和通用的 CreateView 来做到这一点。它正在工作,但我不知道如何将子实例的所有者设置为发出请求的用户。这是一个完美的例子,其中使用基于函数的视图和模型表单比使用内联表单集更容易。感谢您发布您的解决方案,它帮了我很多忙。
    • 如何使添加成分或编辑成分?
    猜你喜欢
    • 2020-09-18
    • 2019-11-10
    • 2010-09-30
    • 1970-01-01
    • 2018-05-24
    • 2011-10-11
    • 1970-01-01
    • 2019-09-02
    • 1970-01-01
    相关资源
    最近更新 更多