Django: страница не найдена (404) при публикации данных формы - PullRequest
0 голосов
/ 19 июня 2020

Я пытаюсь создать форму для отправки сообщения в блоге на странице сведений об авторе, чтобы сообщение в блоге автоматически использовало текущего автора в качестве внешнего ключа «blog_author». Я знаю, что этот подход небезопасен - это сайт проекта, и я пытаюсь изучить новый шаблон дизайна. В Django docs рекомендуется использовать 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()

На этом этапе я подозреваю, что проблема связана с моим вызовом redirect () в переопределении form_valid.

Я пробовал включать:

  1. Изменение действия формы с пустого на тот же URL-адрес, что и в моих URL-путях (возможно, я сделал это неправильно)
  2. Изменение кода в form_valid () для чтения form.instance.blog_author = self.object (то же точное сообщение об ошибке, поэтому я не думаю, что это это)
  3. Возникновение с вызовом перенаправления form_valid (), включая: использование вместо этого self.object или URL-адрес, использование жестко запрограммированного URL-адреса, избавление от второй аргумент и изменение второго аргумента на pk =, slug =.
  4. Добавление get_success_url ov erride (на самом деле не знаю, почему это сработает)

edit: один из исключенных вызовов post, который обнаружился на моем локальном сервере, отправился в blog / blogger / 4, это URL-адрес, который я хочу . Не уверен, в чем проблема.

1 Ответ

1 голос
/ 19 июня 2020

Это сбивает с толку, как вы используете шаблон. В любом случае, я думаю, что самое простое решение здесь - получить данные 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 - собирать данные из форм, а 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']

FYI, чтобы SingleObjectMixin работал, вам нужно изменить модель с BlogPost на BlogAuthor

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...