【问题标题】:Getting error 405 while using ModelFormMixin with DetailView将 ModelFormMixin 与 DetailView 一起使用时出现错误 405
【发布时间】:2020-06-20 10:29:24
【问题描述】:

我想创建一个显示模型详细信息的 DetailView 页面,但我想使用 ModelFormMixin 在 DetailView 页面中添加一个 Comment 部分。

这是我的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})

但是当我点击提交按钮时,它显示以下错误:

编辑部分:

This is my views.py file

model.py

forms.py

userpost_detail.html

browser image before clicking enter button

browser image after clicking enter button

django admin page

很抱歉没有上传实际代码,因为上传大量代码太难了。

【问题讨论】:

  • 您好,您必须定义一个 post 方法。我猜您收到了一个不允许的方法错误,这就是页面无法正常工作的原因。
  • 谢谢 Diego,让我继续努力,我会及时通知你结果
  • 错误的问题解决了,但是评论没有保存在数据库中。我去了管理员的网站,它没有显示任何评论。请帮帮我
  • 嗯,你必须在 post 方法中明确定义一个 is_valid 函数才能在数据库中做一些事情。我假设你有两个模型(Post 和 Comment)。我认为您想呈现一个表单以对相关帖子发表评论。这不是那么简单。你能展示模型和新视图吗?
  • 嘿 Diego,我编辑了我的问题。您可以在编辑部分找到代码的图像。

标签: python django django-forms django-templates


【解决方案1】:

我认为以下代码会对您有所帮助。很久以前写过代码,不过好像解决了你的问题(我没用过taggit,所以创建了一个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、表单等... 我使用了 3 个视图。 DateDetailView(类似于您的 DetailView)来显示页面(带有所需的上下文)。 CreateView 管理 POST 方法并将评论保存到数据库中。我还添加了上下文以获取帖子信息。 最后一个视图,旨在管理相同的 URL,但调用适当的视图 当请求是 GET 或 POST 时。见 urls.py

网址:

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>

注意事项:查看输入type=hidden获取post.pk。这是保存 comment.post 字段所必需的。

我想我涵盖了您可能遇到的所有问题。希望对你有帮助!!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-25
    • 2018-06-16
    • 1970-01-01
    • 1970-01-01
    • 2015-02-17
    • 2017-08-15
    • 2015-03-02
    • 2013-07-14
    相关资源
    最近更新 更多