Django:发布表单数据时找不到页面(404)

时间:2020-06-19 17:47:36

标签: django forms redirect django-views

我正在尝试创建一个表单以在作者详细信息页面上提交博客文章,以便该博客文章将自动使用当前作者作为其“ blog_author”外键。我知道这种方法不是“安全”的-它是一个项目站点,并且我正在尝试学习一种新的设计模式。 Django文档建议使用1个父视图和2个子视图分别处理get和post(https://docs.djangoproject.com/en/3.0/topics/class-based-views/mixins/)。

该页面使用get可以很好地呈现,但是该帖子给我一个错误,显示为“找不到页面(404)-找不到与查询匹配的博客帖子”。父视图(blog.views.AuthorDetail)引发了异常,但是没有回溯。

编辑:表格从一开始就应该是ModelForm

这是我的观点:

class BlogAuthorDetailView(generic.DetailView):
    model = BlogAuthor

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['form'] = BlogSubmitForm()
        return context

class BlogSubmit(SingleObjectMixin, FormView):
    template_name = 'blogauthor_detail.html'
    form_class = BlogSubmitForm
    model = BlogPost
    
    def post(self, request, *args, **kwargs):
        if not request.user.is_authenticated:
            return HttpResponseForbidden()
        self.object = self.get_object()
        #Should I be overriding form_valid() to use the line above? Not sure if I'm doing my data 
        #handling in the right place
        return super().post(request, *args, **kwargs)

    def form_valid(self, form):
        blogpost = form.save(commit=False)
        blogpost.blog_author = self.object
        blogpost.save()
        return redirect('blog_author-detail', pk=self.object.id)
        
class AuthorDetail(View):
    def get(self, request, *args, **kwargs):
        view = BlogAuthorDetailView.as_view()
        return view(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        view = BlogSubmit.as_view()
        return view(request, *args, **kwargs)

URL:

urlpatterns = [
    path('', views.index, name='index'),
    path('blogs/', views.BlogPostListView.as_view(), name='blogs'),
    path('blog/<int:pk>', views.BlogPostDetailView.as_view(), name='blogpost-detail'),
    path('bloggers/', views.BlogAuthorListView.as_view(), name='bloggers'),
    path('blogger/<int:pk>', views.AuthorDetail.as_view(), name='blog_author-detail'),
    path('blog/<int:pk>/create', views.BlogCommentCreate.as_view(), name='comment_create')
]

模板:

{% extends "base_generic.html" %}

{% block content %}
  <h1>Title: {{ blogauthor.title }}</h1>

  <p><strong>Author:</strong> <a href="">{{ blogauthor }}</a></p> 
  <p><strong>Biography:</strong> {{ blogauthor.biography }}</p> 
  <p><strong>User:</strong> {{ blogauthor.user }}</p>  
  <p><strong>Posts:</strong>    
  {% for blog in blogauthor.blogpost_set.all %}
      <p>  {{ blog.title }} </p>
  {% endfor %} </p>
  <form action="" method="post">
    {% csrf_token %}
    <table>
    {{ form.as_table }}
    </table>
    <input type="submit" value="Submit">
  </form>

  <div style="margin-left:20px;margin-top:20px">
    <h4>Comments: Coming Soon!</h4>
{% endblock %}

型号:

class BlogPost(models.Model):
    date_created = models.DateField(blank=False, default = date.today)
    blog_author = models.ForeignKey('BlogAuthor', on_delete = models.SET_NULL, null=True)
    title = models.TextField(max_length=70)
    content = models.TextField(max_length=400, null=False)
    class Meta:
        ordering = ['date_created']
    def get_absolute_url(self):
        """Returns the url to access a particular blog post instance."""
        return reverse('blogpost-detail', args=[str(self.id)])
    def __str__(self):
        return self.title

forms.py:

class BlogSubmitForm(forms.Form):
    title = forms.CharField()
    content = forms.CharField(widget=forms.Textarea(attrs={'cols': 40, 'rows': 8}))
    date_created = forms.DateField()

这时,我怀疑问题与form_valid覆盖中的redirect()调用有关。

我尝试过的事情包括:

  1. 将表单的操作从空白更改为与我的URL路径相同的URL(可能是我做错了此事)
  2. 更改form_valid()中的代码以读取form.instance.blog_author = self.object(相同的错误消息,因此我认为不是这样)
  3. 解决form_valid()的重定向调用,包括:改用self.object或URL,使用硬编码的url,摆脱第二个参数,并将第二个arg更改为pk =,slug =。 / li>
  4. 添加get_success_url替代项(真的不知道为什么会起作用)

edit:在我的本地服务器中显示的例外帖子之一转到了blog / blogger / 4,这是我想要的URL。不知道是什么问题。

1 个答案:

答案 0 :(得分:1)

这使您对模板的使用方式感到困惑。无论如何,我认为这里最简单的解决方案是从BlogAuthor获取request.user数据,这是最合逻辑的,否则,任何人都可以向其他用户发布任何内容,只要他们可以预测其主键即可(是一个安全漏洞)。您可以尝试以下方法:

from django.contrib.auth.mixins import LoginRequiredMixin

class BlogSubmit(LoginRequiredMixin, CreateView):
    template_name = 'blogauthor_detail.html'
    form_class = BlogSubmitForm
    model = BlogPost

    def get_success_url(self):
      return reverse('blog_author-detail', pk=self.object.id)

    def form_valid(self, form):
        form.blog_author = self.request.user.blogauthor # assuming BlogAuthor has OneToOne relation with User
        return super(BlogSubmit, self).form_valid(form)

更新

FormView的目的是从Forms收集数据,CreateView用来存储和创建新实例。无论如何,您需要像这样更改代码以使其正常工作:

class BlogSubmit(LoginRequiredMixin, SingleObjectMixin, FormView):
    template_name = 'blogauthor_detail.html'
    form_class = BlogSubmitForm
    model = BlogAuthor

    def get_success_url(self):
        return reverse('blog_author-detail', pk=self.object.id)

    def form_valid(self, form):
        self.object = self.get_object()
        form.blog_author = self.object 
        form.save()
        return super(BlogSubmit, self).form_valid(form)

还更新表单:

class BlogSubmitForm(forms.ModelForm):
    class Meta:
       model = BlogPost
       fields = ['title', 'date_created', 'content']

仅供参考,要使SingleObjectMixin有效,您需要将模型从BlogPost更改为BlogAuthor