将ModelFormMixin与DetailView一起使用时出现错误405

时间:2020-06-20 10:29:24

标签: python django django-forms django-templates

我想创建一个显示模型详细信息的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})

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

编辑部分:

Device.StartTimer

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

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

1 个答案:

答案 0 :(得分:0)

我认为以下代码将为您提供帮助。我很久以前编写了代码,但是它似乎可以解决您的问题(我没有使用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

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>

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

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