Получение ошибки 405 при использовании ModelFormMixin с DetailView - PullRequest
0 голосов
/ 20 июня 2020

Я хочу создать страницу DetailView, на которой отображаются детали модели, но я хочу добавить раздел комментариев на странице DetailView с помощью ModelFormMixin.

Это мой код views.py:

class PostDetailView(ModelFormMixin, DetailView):
    model = UserPost
    context_object_name='post_detail'
    form_class = UserCommentForm

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

    def get_absolute_url(self):
        return reverse(request, 'basic_app:post_detail', kwargs={'pk':self.pk})

Но когда я нажимаю кнопку отправки, появляется следующая ошибка:

Отредактированная часть:

Это мой файл views.py

model.py

forms.py

userpost_detail. html

изображение браузера перед нажатием кнопки ввода

изображение браузера после нажатия кнопки ввода

django страница администратора

Прошу прощения за то, что не загрузил фактический код, потому что было слишком сложно загрузить этот массив кода.

1 Ответ

0 голосов
/ 22 июня 2020

Думаю, вам поможет следующий код. Я давно кодирую его как go, но, похоже, он решил вашу проблему (я не использовал тег git, поэтому я создал модель PostTag):

Модели:

from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils.timezone import localtime
from django.urls import reverse

class User(AbstractUser):
    pass

class PublishedManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(status='published')

class PostTag(models.Model):
    name = models.CharField(max_length=40)
    slug = models.SlugField(max_length=40)

    def __str__(self):
        return self.name

class Post(models.Model):
    POST_STATUS = (('draft', 'Draft'), ('published', 'Published'))

    title = models.CharField(max_length=100)
    body = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts')
    created = models.DateTimeField(auto_now_add=True)
    publish = models.DateTimeField(auto_now=True)
    updated = models.DateTimeField(auto_now=True)
    slug = models.SlugField(max_length=100, unique_for_date='publish')
    status = models.CharField(max_length=10, choices=POST_STATUS, default='draft')
    tags = models.ManyToManyField(PostTag, blank=True)

    def get_absolute_url(self):
        local_time = localtime(self.publish)
        return reverse("blog:post_date_detail", args=[local_time.year, local_time.month, local_time.day, self.slug])

    class Meta:
        ordering = ('-publish',)

    def __str__(self):
        return self.title
    
    objects = models.Manager() # The default manager.
    published = PublishedManager() # Custom manager.

class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
    name = models.CharField(max_length=80)
    email = models.EmailField()
    body = models.TextField()
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    active = models.BooleanField(default=True)

    def get_absolute_url(self):
        local_time = localtime(self.post.publish)
        return reverse("blog:post_date_detail", args=[local_time.year, local_time.month, local_time.day, self.post.slug])

    class Meta:
        ordering = ('created',)
        
    def __str__(self):
        return f'Comment by {self.name} on {self.post}'

Просмотры:

from django.shortcuts import render, get_object_or_404, HttpResponseRedirect
from django.views.generic import ListView, DetailView, View
from django.views.generic.edit import FormView, SingleObjectMixin, CreateView
from django.views.generic.dates import YearArchiveView, MonthArchiveView, DateDetailView
from django.core.mail import send_mail
from django.db.models import Count

from .models import Post, User, Comment, PostTag
from .forms import EmailPostForm, CommentForm


class PostListView(ListView):
    queryset = Post.published.all()
    context_object_name = 'posts'
    paginate_by = 4

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # si hay kwargs se actualiza el context
        if self.kwargs:
            context["tag"] = self.kwargs['tag_slug']
        return context

    def get_queryset(self):
        tag = None
        if self.kwargs:
            tag_slug = self.kwargs['tag_slug']
            tag = get_object_or_404(PostTag, slug=tag_slug)
            posts = self.queryset.filter(tags__in=[tag])
            return posts
        return self.queryset

class PostYearArchiveView(YearArchiveView):
    queryset = Post.published.all()
    template_name = 'blog/post_list.html'
    date_field = "publish"
    context_object_name = 'posts'
    make_object_list = True
    paginate_by = 4

class PostMonthArchiveView(MonthArchiveView):
    queryset = Post.published.all()
    template_name = 'blog/post_list.html'
    date_field = "publish"
    context_object_name = 'posts'
    month_format='%m'
    paginate_by = 4

class PostDateDetailView(DateDetailView):
    queryset = Post.published.all()
    date_field = "publish"
    month_format='%m'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        obj = self.get_object()
        post_tags_pks = obj.tags.all().values_list('pk', flat=True)
        related_posts = self.queryset.filter(tags__in=post_tags_pks).exclude(pk=obj.pk)
        related_posts = related_posts.annotate(same_tags=Count('tags')).order_by('-same_tags','-publish')[:3]
        context["related_posts"] = related_posts
        comments = obj.comments.filter(active=True)
        context["comments"] = comments
        context['post_id'] =  obj.pk
        context['form'] = CommentForm()
        return context

class NewComment(CreateView):
    model = Comment
    template_name = 'blog/post_detail.html'
    form_class = CommentForm

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        post = context["form"].instance.post
        context['post'] = post
        post_tags_pks = post.tags.all().values_list('pk', flat=True)
        related_posts = Post.published.filter(tags__in=post_tags_pks).exclude(pk=post.pk)
        related_posts = related_posts.annotate(same_tags=Count('tags')).order_by('-same_tags','-publish')[:3]
        context["related_posts"] = related_posts
        comments = post.comments.filter(active=True)
        context["comments"] = comments
        return context

class PostDetail(View):

    def get(self, request, *args, **kwargs):
        view = PostDateDetailView.as_view()
        return view(request, *args, **kwargs)

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


class SharePostView(SingleObjectMixin, FormView): 
    form_class = EmailPostForm
    template_name = 'blog/post_share.html'
    success_url = '/blog'
    context_object_name = 'posts'
    queryset = Post.published.all()

    def get(self, request, *args, **kwargs):
        post = self.get_object()
        context = {'post': post, 'form': self.form_class}
        return render(request, self.template_name, context)   

    def form_valid(self, form):    
        post = self.get_object()
        post_url = self.request.build_absolute_uri(post.get_absolute_url())
        form.send_mail(post, post_url)
        return super(SharePostView, self).form_valid(form)

Соображения: см. Get_context_data, чтобы добавить другие данные в контекст: в этом случае теги, related_post, форма и т. Д. c ... Я использовал 3 вида. DateDetailView (аналогично вашему DetailView) для отображения страницы (с необходимым контекстом). CreateView для управления методом POST и сохранения комментария в БД. Я также добавил контекст для получения информации о посте. Наконец, представление с намерением управлять тем же URL-адресом, но вызывает соответствующее представление, когда запрос GET или POST. См. Urls.py

URLS:

from django.urls import path
from blog import views


from blog.models import Post

app_name = 'blog'

urlpatterns = [
    path("", views.PostListView.as_view(), name="post_list"),
    path('tag/<slug:tag_slug>/', views.PostListView.as_view(), name='post_list_by_tag'),
    path('<int:year>/', views.PostYearArchiveView.as_view(), name="post_year_archive"),
    path('<int:year>/<int:month>/', views.PostMonthArchiveView.as_view(), name="post_month_numeric"),
    path('<int:year>/<int:month>/<int:day>/<slug:slug>/', views.PostDetail.as_view(), name="post_date_detail"),
    path('<int:pk>/share/', views.SharePostView.as_view(), name='post_share'),
]

Форма комментария:

class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ('name', 'email', 'body', 'post')
        
        widgets = {
            'name': forms.TextInput(attrs={'placeholder': 'Name'}),
            'email': forms.EmailInput(attrs={'placeholder': 'E-mail'}),
            'body': forms.Textarea(attrs={'placeholder': 'Write your message here'}),
            'post' : forms.HiddenInput(),
        }

форма в шаблоне:

<form method="post" action="" novalidate>
            {% csrf_token %}
            <div class="input-group input-group-icon">
                {{ form.name }}
                <div class="input-icon"><i class="fas fa-user"></i></div>
                {% if form.name.errors %}
                    {{form.name.errors}}
                {% endif %}
            </div>

            <div class="input-group input-group-icon">
                {{form.email }}
                <div class="input-icon">
                    <i class="fas fa-envelope"></i>
                </div> 
                {% if form.email.errors %}
                    {{form.email.errors}}
                {% endif %}
            </div>

            <div class="msg">
                <div class="input-group">{{form.body}}
                    {% if form.body.errors %}
                        {{form.body.errors}}
                    {% endif %} 
                </div>
            </div>
            <input type="hidden" name="post" value="{{ post.pk }}">
            <div class="input-group send-reset">
                <input type="submit" value="Enviar Comentario" />
            </div>
        </form>

Соображения: См. Input type = hidden, чтобы получить post.pk. Это необходимо для сохранения поля comment.post.

Думаю, я рассмотрел все возможные проблемы. Надеюсь, это поможет !!

...