#django #django-forms
#django #django-forms
Вопрос:
я новичок в django и пытаюсь создать приложение для блога. Последний шаг — иметь возможность создавать комментарий в подробном сообщении в блоге, я попытался поместить форму для создания комментария в то же подробное представление, что и blog_post, и комментарии, когда я пытаюсь создать комментарий с формой, в консоли появляется ошибка: метод post не разрешен,Я перепробовал все, но все еще не работает, пожалуйста, помогите, я высоко ценю вашу помощь В МОЕМ КОДЕ
число просмотров
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from django.http import HttpResponse
from django.views.generic import View
from django.views.generic.base import TemplateView, TemplateResponseMixin, ContextMixin
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.shortcuts import render
from django.utils.decorators import method_decorator
from django.contrib.contenttypes.models import ContentType
from .models import blog_post, Category
from .forms import blog_postForm
from comments.models import Comment
from comments.forms import CommentForm
class CategoryListView(ListView):
model = Category
queryset = Category.objects.all()
template_name = "blog/category_list.html"
class CategoryDetailView(DetailView):
model = Category
def get_context_data(self, *args, **kwargs):
context = super(CategoryDetailView, self).get_context_data(*args, **kwargs)
obj = self.get_object()
blogpost_set = obj.blog_post_set.all()
default_blogpost = obj.default_category.all()
blogposts = ( blogpost_set | default_blogpost ).distinct()
context["blogposts"] = blogposts
return context
class LoginRequiredMixin(object):
@classmethod
def as_view(cls, **kwargs):
view = super(LoginRequiredMixin, cls).as_view(**kwargs)
return login_required(view)
#@method_decorator(login_required)
#def dispatch(self, request, *args, **kwargs):
# return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
class blog_postCreateView(LoginRequiredMixin, CreateView):
#model = blog_post
form_class = blog_postForm
template_name = "form.html"
#fields = ["title", "content"]
def get_success_url(self):
return reverse("blog_post_list")
# @method_decorator(login_required)
# def dispatch(self, request, *args, **kwargs):
# return super(MyView, self).dispatch(request, *args, **kwargs)
class blog_postListView(ListView):
model = blog_post
def get_queryset(self, *args, **kwargs):
qs = super(blog_postListView, self).get_queryset(*args, **kwargs).order_by("-timestamp")
return qs
class blog_postDetailView(DetailView):
model = blog_post
def get_context_data(self, *args, **kwargs):
context = super(blog_postDetailView, self).get_context_data(*args, **kwargs)
obj = self.get_object()
#default_blogpost = obj.default_category.all()
#blogposts = ( blogpost_set | default_blogpost ).distinct()
# content_type = ContentType.objects.get_for_model(blog_post)
# obj_id = obj.id
# comments = Comment.objects.filter(content_type=content_type, object_id= obj_id)
initial_data = {
"content_type": obj.get_content_type,
"object_id": obj.id
}
form = CommentForm(self.request.POST or None, initial=initial_data)
if form.is_valid():
c_type = form.cleaned_data.get("content_type")
content_type = ContentType.objects.get(model=c_type)
obj_id = form.cleaned_data.get('object_id')
content_data = form.cleaned_data.get("content")
new_comment, created = Comment.objects.get_or_create(
user = request.user,
content_type= content_type,
object_id = obj_id,
content = content_data
)
comments = obj.comments.order_by("-timestamp")
context['comments'] = comments
context['comment_form'] = form
return context
class AboutPageView(TemplateView):
template_name = "about.html"
class ContactPageView(TemplateView):
template_name = "contact.html"
class IndexView(ListView):
context_object_name = 'home_list'
template_name = 'blog/index.html'
queryset = blog_post.objects.all().order_by("-timestamp")
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['categories'] = Category.objects.all()
# And so on for more models
return context
blog_post_detail.html
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<!-- Blog Post Content Column -->
<div class="col-lg-8">
<!-- Blog Post -->
<!-- Title -->
<h1>{{ object.title }}</h1>
<!-- Author -->
<p class="lead">
by <a href="#">Start Bootstrap</a>
</p>
<hr>
<!-- Date/Time -->
<p><span class="glyphicon glyphicon-time"></span> Posted on {{ object.timestamp|date }} </p>
<hr>
<!-- Preview Image -->
<!-- <img class="img-responsive" src="http://placehold.it/900x300" alt=""> -->
{% if object.image %}
<img src='{{ object.image.url }}' class='img-responsive' />
{% endif %}
<hr>
<!-- Post Content -->
<div class="content-markdown"><p class="lead">{{ object.content }}</p></div>
<hr>
<!-- Blog Comments -->
<!-- Comments Form LEAVE A COMMENT -->
<div class="well">
<h4>Leave a Comment:</h4>
<!-- <form role="form">
<div class="form-group">
<textarea class="form-control" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form> -->
<form method="POST" action='.'> {% csrf_token %}
{{ comment_form }}
<input type='submit' value='Post comment' class='btn btn-default'>
</form>
<hr/>
</div>
<hr>
<!-- Posted Comments -->
<!-- Comment -->
{% for comment in comments %}
<div class="media">
<a class="pull-left" href="#">
<!-- {% if object.image %}
<img src='{{ object.image.url }}' class='img-responsive' />
{% endif %} -->
<img class="media-object" src="http://placehold.it/64x64" alt="">
</a>
<div class="media-body">
<h4 class="media-heading">{{ comment.content_object }}
<small> by {{ comment.user }} | {{ comment.timestamp|timesince }} ago </small>
</h4>
{{ comment.content }}
<!-- Nested Comment -->
<!-- <div class="media">
<a class="pull-left" href="#">
<img class="media-object" src="http://placehold.it/64x64" alt="">
</a>
<div class="media-body">
<h4 class="media-heading">Nested Start Bootstrap
<small>August 25, 2014 at 9:30 PM</small>
</h4>
Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus.
</div>
</div> -->
<!-- End Nested Comment -->
</div>
</div>
{% endfor %}
</div>
<!-- Blog Sidebar Widgets Column -->
<div class="col-md-4">
<!-- Blog Search Well -->
<div class="well">
<h4>Blog Search</h4>
<div class="input-group">
<input type="text" class="form-control">
<span class="input-group-btn">
<button class="btn btn-default" type="button">
<span class="glyphicon glyphicon-search"></span>
</button>
</span>
</div>
<!-- /.input-group -->
</div>
<!-- Blog Categories Well -->
<div class="well">
<h4>Blog Categories</h4>
<div class="row">
<div class="col-lg-6">
<ul class="list-unstyled">
<li><a href="#">Category Name</a>
</li>
<li><a href="#">Category Name</a>
</li>
<li><a href="#">Category Name</a>
</li>
<li><a href="#">Category Name</a>
</li>
</ul>
</div>
<!-- /.col-lg-6 -->
<div class="col-lg-6">
<ul class="list-unstyled">
<li><a href="#">Category Name</a>
</li>
<li><a href="#">Category Name</a>
</li>
<li><a href="#">Category Name</a>
</li>
<li><a href="#">Category Name</a>
</li>
</ul>
</div>
<!-- /.col-lg-6 -->
</div>
<!-- /.row -->
</div>
<!-- Side Widget Well -->
<div class="well">
<h4>Side Widget Well</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore, perspiciatis adipisci accusamus laudantium odit aliquam repellat tempore quos aspernatur vero.</p>
</div>
</div>
</div>
<!-- /.row -->
{% endblock content %}
модель блога
from __future__ import unicode_literals
from django.conf import settings
from django.core.urlresolvers import reverse
from django.db import models
from django.db.models.signals import pre_save, post_save
from django.utils.text import slugify
# Create your models here.
from comments.models import Comment
from django.contrib.contenttypes.models import ContentType
def upload_location(instance, filename):
#filebase, extension = filename.split(".")
#return "%s/%s.%s" %(instance.id, instance.id, extension)
return "%s/%s" %(instance.id, filename)
class blog_post(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
title = models.CharField(max_length=120)
height_field = models.IntegerField(default=0)
width_field = models.IntegerField(default=0)
image = models.ImageField(upload_to=upload_location, null=True, blank=True, width_field="width_field", height_field="height_field")
slug = models.SlugField(unique=True)
content = models.TextField()
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
categories = models.ManyToManyField('Category', blank=True)
default = models.ForeignKey('Category', related_name='default_category', null=True, blank=True)
def __unicode__(self):
return self.title
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("blog_post_detail", kwargs={"slug": self.slug})
@property
def comments(self):
instance = self
qs = Comment.objects.filter_by_instance(instance)
return qs
@property
def get_content_type(self):
instance = self
content_type = ContentType.objects.get_for_model(instance.__class__)
return content_type
def create_slug(instance, new_slug=None):
slug = slugify(instance.title)
if new_slug is not None:
slug = new_slug
qs = blog_post.objects.filter(slug=slug).order_by("-id")
exists = qs.exists()
if exists:
new_slug = "%s-%s" %(slug, qs.first().id)
return create_slug(instance, new_slug=new_slug)
return slug
def pre_save_post_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = create_slug(instance)
pre_save.connect(pre_save_post_receiver, sender=blog_post)
class Category(models.Model):
title = models.CharField(max_length=120, unique=True)
slug = models.SlugField(unique=True)
description = models.TextField(null=True, blank=True)
active = models.BooleanField(default=True)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
def __unicode__(self):
return self.title
def get_absolute_url(self):
return reverse("category_detail", kwargs={"slug": self.slug })
модель комментариев
from __future__ import unicode_literals
from django.conf import settings
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
#from blog.models import blog_post
class CommentManager(models.Manager):
def filter_by_instance(self, instance):
content_type = ContentType.objects.get_for_model(instance.__class__)
obj_id = instance.id
qs = super(CommentManager, self).filter(content_type=content_type, object_id= obj_id)
return qs
class Comment(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
#post = models.ForeignKey(blog_post)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
content = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
objects = CommentManager()
def __unicode__(self):
return str(self.user.username)
def __str__(self):
return str(self.user.username)
Я высоко ценю вашу помощь
Ответ №1:
Если вы хотите добавить функции редактирования в свое представление, вам необходимо использовать UpdateView
вместо DetailView
Пример
class blog_postDetailView(UpdateView):
form_class = CommentForm
model = blog_post
def get_initial(self):
initial_data = super(blog_postDetailView, self).get_initial()
obj = self.get_object()
initial_data.update({
"content_type": obj.get_content_type,
"object_id": obj.id
})
return initial_data
def get_context_data(self, *args, **kwargs):
context = super(blog_postDetailView, self).get_context_data(*args, **kwargs)
obj = self.get_object()
#default_blogpost = obj.default_category.all()
#blogposts = ( blogpost_set | default_blogpost ).distinct()
# content_type = ContentType.objects.get_for_model(blog_post)
# obj_id = obj.id
# comments = Comment.objects.filter(content_type=content_type, object_id= obj_id)
comments = obj.comments.order_by("-timestamp")
context['comments'] = comments
# your form in template should be called form, doing this line for compatability
context['comments_form'] = context['form']
return context
def form_valid(self, form):
c_type = form.cleaned_data.get("content_type")
content_type = ContentType.objects.get(model=c_type)
obj_id = form.cleaned_data.get('object_id')
content_data = form.cleaned_data.get("content")
new_comment, created = Comment.objects.get_or_create(
user = request.user,
content_type= content_type,
object_id = obj_id,
content = content_data
)
return super(blog_postDetailView, self).form_valid(form)
Комментарии:
1. привет, спасибо за ответ, но я не могу использовать UpdateView вместо DetailView, тогда появляется ошибка: использование ModelFormMixin (базовый класс blog_postDetailView) без атрибута ‘fields’ запрещено. Я думаю, это потому, что я хочу, чтобы пользователи могли создавать комментарии к шаблону «Detailview» сообщения в блоге, поэтому все еще нужно использовать DetailView, что еще я могу сделать?
2. @RobertF. просто добавьте
form
в это представление, и все должно быть в порядке3. я добавил form = commenForm в DetailView, это вы имели в виду? Но все то же самое, все еще в консоли, когда я хочу создать комментарий с формой в шаблоне «Подробное представление» (blog_post_detail.html ) ошибка: метод post не разрешен 405
4. @RobertF. Нет, я имел в виду добавить форму в UpdateView
5. мне очень жаль, что я не совсем понимаю, не могли бы вы быть так добры и опубликовать фиксированный подробный просмотр для / кода, который вы имеете в виду, большое спасибо, спасибооооо 🙂
Ответ №2:
Мне пришлось использовать формы.Форма модели. Единственная проблема в том, что сейчас мне нужно войти в систему, чтобы успешно опубликовать / создать комментарий, в противном случае появляется эта ошибка: объект ‘AnonymousUser’ не повторяется. У кого-нибудь есть решение для этого?
число просмотров
from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse
from django.http import HttpResponse
from django.views.generic import View
from django.views.generic.base import TemplateView, TemplateResponseMixin, ContextMixin
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.shortcuts import render
from django.utils.decorators import method_decorator
from django.contrib.contenttypes.models import ContentType
from .models import blog_post, Category
from .forms import blog_postForm
from comments.models import Comment
from comments.forms import CommentForm
class CategoryListView(ListView):
model = Category
queryset = Category.objects.all()
template_name = "blog/category_list.html"
class CategoryDetailView(DetailView):
model = Category
def get_context_data(self, *args, **kwargs):
context = super(CategoryDetailView, self).get_context_data(*args, **kwargs)
obj = self.get_object()
blogpost_set = obj.blog_post_set.all()
default_blogpost = obj.default_category.all()
blogposts = ( blogpost_set | default_blogpost ).distinct()
context["blogposts"] = blogposts
return context
class LoginRequiredMixin(object):
@classmethod
def as_view(cls, **kwargs):
view = super(LoginRequiredMixin, cls).as_view(**kwargs)
return login_required(view)
#@method_decorator(login_required)
#def dispatch(self, request, *args, **kwargs):
# return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
class blog_postCreateView(LoginRequiredMixin, CreateView):
#model = blog_post
form_class = blog_postForm
template_name = "form.html"
#fields = ["title", "content"]
def get_success_url(self):
return reverse("blog_post_list")
# @method_decorator(login_required)
# def dispatch(self, request, *args, **kwargs):
# return super(MyView, self).dispatch(request, *args, **kwargs)
class blog_postListView(ListView):
model = blog_post
def get_queryset(self, *args, **kwargs):
qs = super(blog_postListView, self).get_queryset(*args, **kwargs).order_by("-timestamp")
return qs
# class blog_postDetailView(DetailView):
# model = blog_post
# def get_context_data(self, *args, **kwargs):
# context = super(blog_postDetailView, self).get_context_data(*args, **kwargs)
# obj = self.get_object()
# #default_blogpost = obj.default_category.all()
# #blogposts = ( blogpost_set | default_blogpost ).distinct()
# # content_type = ContentType.objects.get_for_model(blog_post)
# # obj_id = obj.id
# # comments = Comment.objects.filter(content_type=content_type, object_id= obj_id)
# initial_data = {
# "content_type": obj.get_content_type,
# "object_id": obj.id
# }
# form = CommentForm(self.request.POST or None, initial=initial_data)
# if form.is_valid():
# c_type = form.cleaned_data.get("content_type")
# content_type = ContentType.objects.get(model=c_type)
# obj_id = form.cleaned_data.get('object_id')
# content_data = form.cleaned_data.get("content")
# new_comment, created = Comment.objects.get_or_create(
# user = request.user,
# content_type= content_type,
# object_id = obj_id,
# content = content_data
# )
# comments = obj.comments.order_by("-timestamp")
# context['comments'] = comments
# context['comment_form'] = form
# return context
class blog_postDetailView(UpdateView):
form_class = CommentForm
model = blog_post
template_name = 'blog/blog_post_detail.html'
def get_initial(self):
initial_data = super(blog_postDetailView, self).get_initial()
obj = self.get_object()
initial_data.update({
"content_type": obj.get_content_type,
"object_id": obj.id
})
return initial_data
def get_context_data(self, *args, **kwargs):
context = super(blog_postDetailView, self).get_context_data(*args, **kwargs)
obj = self.get_object()
#default_blogpost = obj.default_category.all()
#blogposts = ( blogpost_set | default_blogpost ).distinct()
# content_type = ContentType.objects.get_for_model(blog_post)
# obj_id = obj.id
# comments = Comment.objects.filter(content_type=content_type, object_id= obj_id)
comments = obj.comments.order_by("-timestamp")
context['comments'] = comments
# your form in template should be called form, doing this line for compatability
context['comments_form'] = context['form']
return context
def form_valid(self, form):
c_type = form.cleaned_data.get("content_type")
content_type = ContentType.objects.get(model=c_type)
obj_id = form.cleaned_data.get('object_id')
content_data = form.cleaned_data.get("content")
new_comment, created = Comment.objects.get_or_create(
user = self.request.user,
content_type= content_type,
object_id = obj_id,
content = content_data
)
return super(blog_postDetailView, self).form_valid(form)
class AboutPageView(TemplateView):
template_name = "about.html"
class ContactPageView(TemplateView):
template_name = "contact.html"
class IndexView(ListView):
context_object_name = 'home_list'
template_name = 'blog/index.html'
queryset = blog_post.objects.all().order_by("-timestamp")
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['categories'] = Category.objects.all()
# And so on for more models
return context
forms.py
from django import forms
from .models import Comment
# class CommentForm(forms.Form):
# content_type = forms.CharField(widget=forms.HiddenInput)
# object_id = forms.IntegerField(widget=forms.HiddenInput)
# #parent_id = forms.IntegerField(widget=forms.HiddenInput, required=False)
# content = forms.CharField(label='', widget=forms.Textarea)
class CommentForm(forms.ModelForm):
content = forms.CharField(widget=forms.Textarea, label='')
class Meta:
model = Comment
fields = ['content_type','object_id', 'content'] # list of fields you want from model
widgets = {'content_type': forms.HiddenInput(),'object_id': forms.HiddenInput(),
}
blog_post_detail.html
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<!-- Blog Post Content Column -->
<div class="col-lg-8">
<!-- Blog Post -->
<!-- Title -->
<h1>{{ object.title }}</h1>
<!-- Author -->
<p class="lead">
by <a href="#">Start Bootstrap</a>
</p>
<hr>
<!-- Date/Time -->
<p><span class="glyphicon glyphicon-time"></span> Posted on {{ object.timestamp|date }} </p>
<hr>
<!-- Preview Image -->
<!-- <img class="img-responsive" src="http://placehold.it/900x300" alt=""> -->
{% if object.image %}
<img src='{{ object.image.url }}' class='img-responsive' />
{% endif %}
<hr>
<!-- Post Content -->
<div class="content-markdown"><p class="lead">{{ object.blog_content }}</p></div>
<hr>
<!-- Blog Comments -->
<!-- Comments Form LEAVE A COMMENT -->
<div class="well">
<h4>Leave a Comment:</h4>
<!-- <form role="form">
<div class="form-group">
<textarea class="form-control" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form> -->
<form method="POST" action='.' enctype='multipart/form-data'> {% csrf_token %}
{{ form }}
<input type='submit' value='Post comment' class='btn btn-default'>
</form>
<hr/>
</div>
<hr>
<!-- Posted Comments -->
<!-- Comment -->
{% for comment in comments %}
<div class="media">
<a class="pull-left" href="#">
<!-- {% if object.image %}
<img src='{{ object.image.url }}' class='img-responsive' />
{% endif %} -->
<img class="media-object" src="http://placehold.it/64x64" alt="">
</a>
<div class="media-body">
<h4 class="media-heading">{{ comment.content_object }}
<small> by {{ comment.user }} | {{ comment.timestamp|timesince }} ago </small>
</h4>
{{ comment.content }}
<!-- Nested Comment -->
<!-- <div class="media">
<a class="pull-left" href="#">
<img class="media-object" src="http://placehold.it/64x64" alt="">
</a>
<div class="media-body">
<h4 class="media-heading">Nested Start Bootstrap
<small>August 25, 2014 at 9:30 PM</small>
</h4>
Cras sit amet nibh libero, in gravida nulla. Nulla vel metus scelerisque ante sollicitudin commodo. Cras purus odio, vestibulum in vulputate at, tempus viverra turpis. Fusce condimentum nunc ac nisi vulputate fringilla. Donec lacinia congue felis in faucibus.
</div>
</div> -->
<!-- End Nested Comment -->
</div>
</div>
{% endfor %}
</div>
<!-- Blog Sidebar Widgets Column -->
<div class="col-md-4">
<!-- Blog Search Well -->
<div class="well">
<h4>Blog Search</h4>
<div class="input-group">
<input type="text" class="form-control">
<span class="input-group-btn">
<button class="btn btn-default" type="button">
<span class="glyphicon glyphicon-search"></span>
</button>
</span>
</div>
<!-- /.input-group -->
</div>
<!-- Blog Categories Well -->
<div class="well">
<h4>Blog Categories</h4>
<div class="row">
<div class="col-lg-6">
<ul class="list-unstyled">
<li><a href="#">Category Name</a>
</li>
<li><a href="#">Category Name</a>
</li>
<li><a href="#">Category Name</a>
</li>
<li><a href="#">Category Name</a>
</li>
</ul>
</div>
<!-- /.col-lg-6 -->
<div class="col-lg-6">
<ul class="list-unstyled">
<li><a href="#">Category Name</a>
</li>
<li><a href="#">Category Name</a>
</li>
<li><a href="#">Category Name</a>
</li>
<li><a href="#">Category Name</a>
</li>
</ul>
</div>
<!-- /.col-lg-6 -->
</div>
<!-- /.row -->
</div>
<!-- Side Widget Well -->
<div class="well">
<h4>Side Widget Well</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore, perspiciatis adipisci accusamus laudantium odit aliquam repellat tempore quos aspernatur vero.</p>
</div>
</div>
</div>
<!-- /.row -->
{% endblock content %}
Ответ №3:
Добавьте метод post внутри DetailView. как показано ниже:
class CategoryDetailView(DetailView):
def post(self, request, *args, **kwargs):
return HttpResponseRedirect('/success/')