简体   繁体   English

在表单中使用Django上下文处理器

[英]Using Django Context Processors with forms

I have multiple forms to be shown everywhere in my project and hence I read that having a context_processor was the best way to do it. 我的项目中到处都有多种形式显示,因此我读到有一个context_processor是最好的方法。 So, I created one inside my app and it looks something like this: 因此,我在应用程序内部创建了一个,看起来像这样:

def forms_processor(request):

    name_form = NewNameForm()
    work_form = NewWorkForm()
    address_form = NewAddressForm()

    context = {'name_form': name_form,
           'work_form': work_form,
           'address_form': work_form,
           }
    return context

This works great, I can just use {{name_form}} anywhere in my templates and that renders the form. 这很好用,我可以在模板的任何地方使用{{name_form}}并呈现表单。

Now my question is, where do I validate the form? 现在我的问题是,我在哪里验证表格? In my views.py or the context_processors.py ? 在我的views.pycontext_processors.py Right now my views for name_form looks something like this: 现在,我对name_form视图如下所示:

def user_profile(request):
    if request.method == 'POST':
        name_form = NewNameForm(request.POST)

        if name_form.is_valid():
            form.save()

    else:
        ctx = {'title': 'Profile', 'active_tab': 'Profile'}

    return render (request, 'user_profile.html', ctx)

This isn't working actually, if I submit an invalid form, it just comes back to the same page and won't show a populated form. 这实际上不起作用,如果我提交了无效的表单,它将返回到同一页面,并且不会显示填充的表单。

If someone could guide me or redirect me to some docs on this topic, that'd be awesome! 如果有人可以指导我或将我重定向到有关此主题的一些文档,那真是太棒了! Thanks! 谢谢!

The problem is that your processor instantiates the form on each render. 问题在于您的处理器会在每个渲染器上实例化表单。 Each time you call render, your processor is called, which instantiates a new form and displays THAT form, not the form instance that you created in the view. 每次调用render时,都会调用处理器,该处理器实例化一个新表单并显示THAT表单,而不是您在视图中创建的表单实例。 Therefore, the form being rendered is a blank instance but the form that contains the input and errors was destroyed by garbage collection after finishing your view. 因此,正在呈现的表单是一个空白实例,但是包含输入和错误的表单在完成视图后被垃圾回收破坏了。

A way I would do this, is passing the form you create in the view back to context before rendering. 我这样做的一种方式是在渲染之前将在视图中创建的表单传递回上下文。 Pass it in to a context key such as "name_form_filled". 将其传递到上下文密钥,例如“ name_form_filled”。 Then if that variable is present in the context, don't render "name_form", instead render "name_form_filled". 然后,如果该变量存在于上下文中,则不呈现“ name_form”,而是呈现“ name_form_filled”。

views.py views.py

def user_profile(request):
    ctx = {}
    if request.method == 'POST':
        name_form = NewNameForm(request.POST)

        if name_form.is_valid():
            name_form.save() # you named this named_form, not form.
            # If you want to redirect to another view when the form is saved successfuly, do it here.
        else:
            ctx["name_form_filled"] = form

    else:
        ctx.update({'title': 'Profile', 'active_tab': 'Profile'})

    return render (request, 'user_profile.html', ctx)

user_profile.html user_profile.html

<div id="form_container">
    {% if name_form_filled %}
    <!-- Render form that has input and errors from previous POST. -->
    {{ name_form_filled }}
    {% else %}
    <!-- render empty initial form. User has not attempted to submit yet. -->
    {{ name_form }}
    {% endif %}
</div>

=========================================================================== ================================================== ========================

Another way you could do this is turn this view into a class based view and inherit a base class based view. 您可以执行此操作的另一种方法是将该视图转换为基于类的视图并继承基于基类的视图。 This base class will override the get_context_data method and add your three forms. 这个基类将覆盖get_context_data方法并添加您的三种形式。 Note that you won't be using the context processor with this methodology so you could get rid of it if wanted in this case. 请注意,您不会将上下文处理器与这种方法一起使用,因此在这种情况下,如果需要可以将其删除。

All views that use your form will extend the base view class. 使用表单的所有视图都将扩展基本视图类。 Then, after evaluating your form, if it is invalid, overwrite your name_form context key with the invalid form instance, which will be in your context. 然后,在评估表单后,如果该表单无效,请使用将在您的上下文中存在的无效表单实例覆盖您的name_form上下文键。

views.py views.py

class BaseView(View):
    def get_context_data(self, *args, **kwargs):
        context = {
            "name_form": NewNameForm(),
            "work_form": NewWorkForm(),
            "address_form": NewAddressForm()
        }
        return context


class UserProfileView(BaseView):
    def get(self, request, *args, **kwargs):
        # Do GET logic here.
        ctx = self.get_context_data(*args, **kwargs) # BaseView.get_context_data will be called here unless you override it in this class.
        ctx.update({'title': 'Profile', 'active_tab': 'Profile'})
        return render (request, 'user_profile.html', ctx)

    def post(self, request, *args, **kwargs):
        # Do POST logic here.
        ctx = self.get_context_data(*args, **kwargs) # BaseView.get_context_data will be called here unless you override it in this class.

        name_form = NewNameForm(request.POST)

        if name_form.is_valid():
            name_form.save()
        else:
            ctx["name_form"] = name_form # will replace the empty form in context with the form instance created in name_form that has input and errors.
        return render (request, 'user_profile.html', ctx)

user_profile.html user_profile.html

<div id="form_container">
    <!-- Will render whatever is in name_form. If this is after the
    user has submitted an invalid form, this form will be populated with input and errors because we overwrote it in the view. -->
    {{ name_form }}
</div>

=========================================================================== ================================================== ========================

I personally think that the first solution is the best but when you start getting more complex, you should probably switch over to the second solution as class based views make complex views way easier. 我个人认为第一个解决方案是最好的,但是当您开始变得更复杂时,您可能应该切换到第二个解决方案,因为基于类的视图使复杂的视图变得更容易。

Direct answer: you validate the form in views.py with is_valid() method. 直接答案:您可以使用is_valid()方法在views.py验证表单。 What you need is to populate context with bound form if the form is invalid: 您需要的是如果表单无效则用绑定表单填充上下文:

def user_profile(request):
    ctx = {'title': 'Profile', 'active_tab': 'Profile'}

    if request.method == 'POST':
        name_form = NewNameForm(request.POST)
        if name_form.is_valid():
            form.save()
            return redirect(YOUR_REDIRECT_URL) # Always redirect after successful POST
        ctx['form'] = form  # if form is invalid return it with context

    return render (request, 'user_profile.html', ctx)

Read more in documentation . 文档中阅读更多内容

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM