Объединение DetailView и CreateView в Django 3.2/4.0, как объясняется в документации
Я создаю общий блог и пытаюсь дать пользователям возможность оставлять комментарии прямо на странице статьи. Я пытаюсь реализовать это, комбинируя DetailView
с CreateView
.
В документации представлено 3 различных решения этой проблемы:
FormMixin
+DetailView
: это ответ, который документация Django не советует , но который советует большинство ответов на SO, которые я смог найтиDetailView
только + написать методpost
: "лучшее решение" согласно Django docs .
DetailView
+FormView
: "альтернативное лучшее решение", и то, которое я пытаюсь реализовать .
"Альтернативное лучшее" решение заключается в создании DetailView
для статей и FormView
для комментариев, но в документации говорится, что "Этот подход также может быть использован с любыми другими общими представлениями на основе классов", что означает, что DetailView + CreateView должны быть возможны.
- В этом вопросе SO предлагается смешать DetailView и CreateView. Однако, объяснение в этом ответе неполное.
- Другой вопрос SO, среди советов использовать
FormMixin
s, имеет такой ответ, который близок, но отличается. - Другие вопросы (1, 2 и т.д.) касаются только методов
FormMixin
иDetailView
+post
.
Вот моя реализация на данный момент:
models.py:
class Article(models.Model):
slug = models.SlugField()
# title, body, author
def get_absolute_url(self):
return reverse("article_detail", kwargs={"slug": self.slug})
class Comment(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name="comments", to_field="slug")
body = models.TextField()
# ...
def get_absolute_url(self):
return reverse("article_detail", kwargs={"slug": self.article.slug})
views.py:
class ArticleDetailView(DetailView):
model = Article
template_name = "article_detail.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["form"] = CommentCreateView()
return context
class CommentCreateView(CreateView):
"""create comment"""
model = Comment
fields = ["body"]
template_name = "comment_create.html"
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.article = Article.objects.filter(
slug=self.kwargs.get("slug")
).first()
self.object.author = self.request.user
self.object.save()
return super().form_valid(form)
def post(self, request, *args, **kwargs):
self.object = self.get_object()
return super().post(request, *args, **kwargs)
def get_success_url(self):
return reverse("article_detail", kwargs={"slug": self.object.article.slug})
class ArticleCommentView(View):
def get(self, request, *args, **kwargs):
view = ArticleDetailView.as_view()
return view(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
view = CommentCreateView.as_view()
return view(request, *args, **kwargs)
urls.py:
urlpatterns = [
# ...
path("article/<slug:slug>", ArticleDetailView.as_view(), name="article_detail"),
path("comment/new", CommentCreateView.as_view(), name="comment_create"),
]
article_detail.html:
{% extends 'base.html' %}
{% block content %}
{{ article.title }}
{{ article.author }}
{{ article.body }}
<form method="post" action="{% url 'comment_create'%}">
{% csrf_token %}
<textarea name="{{ form.body.name }}">{{ form.body.value|default_if_none:'' }}</textarea>
</div>
<button type="submit">
Post Comment
</button>
</div>
</form>
<!-- {% for comment in article.comments.all %} ...-->
{% endblock %}