【问题标题】:Django form redirect after POST is unreliable and needed a success_urlPOST 后的 Django 表单重定向不可靠,需要一个 success_url
【发布时间】:2015-08-31 12:05:27
【问题描述】:

我完全无法理解这种行为,并找到了我不太喜欢的解决方法。任何人都可以帮助启发我吗?上下文是我有一个引导样式的表单来创建新记录(继承自 generic.CreateView)

url.py:

url(r'^$', home, name='home'),
url(r'^main/$', views.MainView.as_view(), name='MainView'),
url(r'^topic/(?P<pk>[0-9]+)/$', catalogue_views.TopicView.as_view(), name='TopicView'),
url(r'^resource/(?P<pk>[0-9]+)/$', catalogue_views.DetailView.as_view(), name='ResourceDetail'),
url(r'^contribute/$', catalogue_views.ContributeView.as_view(success_url="/main/"), name='Contribute'),

views.py:

class ContributeView(generic.CreateView):
    template_name = "openeye/contribute.html"
    form_class = ContributeForm

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(ContributeView, self).dispatch(*args, **kwargs)

class MainView(generic.ListView):

    template_name = "openeye/main.html"
    context_object_name = 'topic_list'

    # TODO Make this only active topic areas?
    def get_queryset(self):
        return TopicArea.objects.all().order_by('name')

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(MainView, self).dispatch(*args, **kwargs)

forms.py:

class ContributeForm(forms.ModelForm):
    class Meta:
        model = CatalogueItem
        fields = ['title', 'topic_area', 'description', 'link', 'what_learn', 'how_apply', 'level', 'relevant_to', 'discovered_by']

    ROLE_CHOICES = [[x.id, x.job] for x in JobType.objects.all()]

    title = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'To sell this resource to others'}), max_length=80, required=True)
    description = forms.CharField(widget=forms.Textarea(attrs={'rows': 2, 'placeholder': 'Clear, e.g. format, duration, activities...'}))
    link = forms.CharField(widget=forms.URLInput(attrs={'placeholder': 'If required, link to resource http://...'}), required=False)
    what_learn = forms.CharField(widget=forms.Textarea(attrs={'rows': 3, 'placeholder':"This is important,."}), label='What will you learn?')
    how_apply = forms.CharField(widget=forms.Textarea(attrs={'rows': 3, 'placeholder':"How could this be put into action afterwards?"}), label='How could you apply this?')
    relevant_to = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, choices=ROLE_CHOICES)

还有一个带有表单的模板:

<div class="container">
        <div class="entry-form row">
            <div class="col-md-10 col-md-offset-1 col-sm-10 col-sm-offset-1 col-xs-10 col-xs-offset-1">
                <form action="{% url 'MainView' %}" method="post" class="form">
                    <input type="hidden" name="next" value="{{ next }}">
                    {% bootstrap_form form %}
                    <button class="btn btn-primary btn-lg" type="submit">Submit Suggestion</button>
                    {% csrf_token %}
                </form>
        </div>
    </div>

表单完美运行,数据很好地保存到数据库中。问题是之后,浏览器转到正确的 URL /main/ 但屏幕为空白。服务器显示 HTTP 405 0,如果我刷新页面,它就可以工作。

如果我更改模板以使 action="{% url 'Contribute' %}" 返回相同的表单,我会收到 HTTP 500 和一条有关“没有要重定向到的 URL”的 Django 消息。所以两个不同的错误由重定向位置决定。在这两种情况下,如果我只是点击浏览器 url 字段并点击返回,它就可以工作。

我确信这最初是有效的,然后就坏了,但我按如下方式解决了它。 success_url 中使用路径的硬代码

url(r'^contribute/$', catalogue_views.ContributeView.as_view(success_url="/main/"), name='Contribute'),

删除模板中的任何操作链接:

<form action="" method="post" class="form">

这是正确的方法吗?为什么尽管访问了正确的 URL,但我的原始方法无法加载页面或出现错误?我很想明白这一点。

【问题讨论】:

  • 服务器在/main/ 上显示 405?那你能把MainView的代码贴出来吗?
  • 我当然添加了它。 /主要的。调用充当站点主页面菜单的 ListView。表单操作可以转到任何页面并获得相同的效果,它似乎不是特定于视图的。
  • 谢谢,这是为了检查您是否在主视图中处理了 post 方法的形式,这会改变我的答案。

标签: python django-forms http-post django-class-based-views


【解决方案1】:

您确定您的数据确实保存在服务器上吗?从您发布的内容来看,这似乎不太可能。这是Django遵循的正常流程:

  1. 获取表单视图 (ContributeView) → 返回一个空表单
  2. 在表单视图 (ContributeView) 上发布 → 如果无效,返回第 1 步。如果有效,则返回 302 Redirectsuccess_url
  3. 在success_url上获取

所以通常情况下,在您的模板中,表单操作应该是空的,因此表单会被发送回生成它的视图。 ContributeView 应该有一个成功的 url,它可以重定向到你想要发送给用户的任何地方:

from django.core.urlresolvers import reverse_lazy
class ContributeView(generic.CreateView):
    # other stuff
    success_url = reverse_lazy('MainView')

使用 405,您得到的行为是因为浏览器尝试将表单直接发送到 MainView,这不是表单视图,告诉浏览器它不知道如何处理 POST 方法.

【讨论】:

  • 谢谢,它可以工作:) 尽管有错误,但记录总是 100% 地保存在数据库中。无论如何,我如上所述将success_url添加到我的课程中。完美的。现在开始了解有关 reverse_lazy 的更多信息...
  • 这很奇怪,但如果您的问题得到解决,我不想花时间了解它是如何节省的。很高兴你能让它工作。顺便说一句,reverse_lazyreverse 相同,只是 url 的实际计算推迟到实际使用。这是必需的,因为您的视图模块在您的 url 之前加载,因此它们尚不可用。
猜你喜欢
  • 2017-08-01
  • 2015-11-04
  • 2015-08-23
  • 2019-04-17
  • 1970-01-01
  • 1970-01-01
  • 2015-12-02
  • 2020-07-14
  • 2019-01-19
相关资源
最近更新 更多