Нет привязки комментария к каждому посту
models.py
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.text import slugify
class Post(models.Model):
"""Посты"""
author = models.ForeignKey(User, verbose_name='Пользователь', on_delete=models.CASCADE)
title = models.CharField(max_length=255, verbose_name='Название поста')
text = models.TextField(max_length=2000, verbose_name='Текст')
photo = models.ImageField(upload_to='None', height_field=None, width_field=None, max_length=100)
slug = models.SlugField(max_length=50, verbose_name="URL поста", unique=True)
# Не рекомендуется с версии 1.7
comments = GenericRelation('comment')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post', kwargs={'game_post': self.slug})
def save(self, *args, **kwargs):
value = self.title
self.slug = slugify(value, allow_unicode=True)
super().save(*args, **kwargs)
class Meta:
verbose_name = 'Пост'
verbose_name_plural = 'Посты'
class Comment(models.Model):
"""Комментарии к посту"""
user = models.ForeignKey(User, verbose_name='Пользователь', on_delete=models.CASCADE, null=True, blank=True)
text = models.TextField(verbose_name='Текст комментария')
# При удалении будут уничтожены все связанные объекты
parent = models.ForeignKey(
'self',
verbose_name='Родительский комментарий',
blank=True,
null=True,
related_name='comment_children',
on_delete=models.CASCADE
)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
timestamp = models.DateTimeField(auto_now=True, verbose_name='Дата создания комментария')
is_child = models.BooleanField(default=False)
@property
def get_parent(self):
if not self.parent:
return self.parent
def __str__(self):
return f'Пользователь {self.user} оставил комментарий: {self.text}'
class Meta:
verbose_name = 'Комментарий'
verbose_name_plural = 'Комментарии'
views.py
Считаю, что проблема здесь пробовал менять значения contenttype, но все четно.
def comment(request):
comments = Post.objects.first().comments.all()
result = create_comments_tree(comments)
comment_form = CommentForm(request.POST or None)
return render(request, 'mainalithis/comment.html', {'comments': result, 'comment_form': comment_form})
def create_comment(request):
comment_form = CommentForm(request.POST or None)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.user = request.user
new_comment.text = comment_form.cleaned_data['text']
new_comment.content_type = ContentType.objects.get(model='post')
new_comment.object_id = 1
new_comment.parent = None
new_comment.is_child = False
new_comment.save()
return HttpResponseRedirect('/comments')
@transaction.atomic()
def create_child_comment(request):
user_name = request.POST.get('user')
current_id = request.POST.get('id')
text = request.POST.get('text')
user = User.objects.get(username=user_name)
content_type = ContentType.objects.get(model='post')
parent = Comment.objects.get(id=int(current_id))
is_child = False if not parent else True
Comment.objects.create(
user=user, text=text, content_type=content_type, object_id=True, parent=parent, is_child=is_child)
comments_ = Post.objects.first().comments.all()
comments_list = create_comments_tree(comments_)
return render(request, 'mainalithis/comment.html', {'comments': comments_list})
utils.py
def get_children(qs_child):
res = []
for comment in qs_child:
c = {
'id': comment.id,
'text': comment.text,
'timestamp': comment.timestamp.strftime('%Y-%m-%d %H:%m'),
'author': comment.user,
'is_child': comment.is_child,
'parent_id': comment.get_parent
}
if comment.comment_children.exists():
c['children'] = get_children(comment.comment_children.all())
res.append(c)
return res
def create_comments_tree(qs):
res = []
for comment in qs:
c = {
'id': comment.id,
'text': comment.text,
'timestamp': comment.timestamp.strftime('%Y-%m-%d %H:%m'),
'author': comment.user,
'is_child': comment.is_child,
'parent_id': comment.get_parent
}
if comment.comment_children:
c['children'] = get_children(comment.comment_children.all())
if not comment.is_child:
res.append(c)
return res
comments_tree.py
from django.template import Library
from django.utils.html import mark_safe
register = Library()
@register.filter()
def comments_filter(comments_list):
res = """
<ul style = "list-style-type: none;">
<div class = "col-md-12 mt-2">
{}
</div>
</ul>
"""
i = ''
#mb - отступ снизу
#mt - оступ сверху
for comment in comments_list:
i += """
<li>
<div class = "col-md-12 mb-2 mt-2 p-0">
<small>{author}</small> | опубликовано: {timestamp}
<hr>
<p>{text} | id={id}</p>
<a href="#" class = "reply" data-id = "{id}" data-parent = {parent_id}>Ответить</a>
<form action ="" method = "POST" class = "comment-form form-group" id = "form-{id}" style="display:none;">
<textarea type = "text" class = "form-control" name = "comment-text"></textarea><br>
<input type = "submit" class = "btn btn-primary submit-reply" data-id="{id}" data-submit-reply="{parent_id}" value = "Отправить">
</form>
</div>
</li>
""".format(id=comment['id'], author=comment['author'], timestamp=comment['timestamp'], text=comment['text'], parent_id=comment['parent_id'])
if comment.get('children'):
i += comments_filter(comment['children'])
return mark_safe(res.format(i))
comment.html
{% load comments_tree %}
{% load crispy_forms_tags %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
{% for post in posts %}
<div>
<p>{{post.description}}</p>
<p>{{ post.title }}</p>
<p>{{ post.text }}</p>
<p>{{ post.author }}</p>
<p>{{ post.middle_star }}</p>
</div>
{% endfor %}
<title>title</title>
</head>
<body>
<div class="row">
<div class = "col-md-3">
</div>
<div class = "col-md-6">
{{ comments|comments_filter }}
<hr>
<div class = "col-md-12">
<form action="{%url 'comment_create' %}" method="POST" >
{% csrf_token %}
{{comment_form|crispy}}
<input type="submit" class = "btn btn-primary" value="Отправить">
</form>
</div>
</div>
<div class = "col-md-6">
</div>
</div>
</body>
<script
src="https://code.jquery.com/jquery-3.5.1.js"
integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc="
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>
<script>
$(document).ready(function(){
$(".reply").on('click', function(){
var commentId = $(this).attr('data-id')
$("#form-"+commentId).fadeToggle();
})
$(".submit-reply").on('click', function(e){
e.preventDefault()
var parentId = $(this).attr('data-submit-reply')
var id = $(this).attr('data-id')
var text = $("#form-"+id).find('textarea[name="comment-text"]').val();
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
const csrftoken = getCookie('csrftoken');
data = {
user: "{{ request.user.username }}",
parentId: parentId,
text: text,
id: id,
csrfmiddlewaretoken: csrftoken
}
$.ajax({
method: "POST",
data: data,
url: "{% url 'comment_child_create' %}",
success: function(data){
window.location.replace('/comments')
}
})
})
})
</script>
<style>
.textarea{
width: 90%;
height: 70px;
resize: none;
}
</style>
</html>
Ответы (1 шт):
Автор решения: Zhenia Kviatkivskyi
→ Ссылка
Привяжи в модели Comment посты через ForeignKey
post = models.ForeignKey(Post,
verbose_name='пост',
on_delete=models.SET_NULL
)
urls.py
path("post/<int:pk>/", views.PostDetailView.as_view()
views.py
class PostDetailView(View):
"""Вывод полной статьи"""
def get(self,request, **kwargs):
template = 'app_name/your_page.html'
post = get_object_or_404(Post, id= kwargs.get("pk"))
return render(request, template, {'post': post})
А в теплейте через связь ForeignKey post.comments.all циклом вывести все прикрепленные к данной статье комменты.
<div class="post">
<p>{{ post.title }}</p>
<p>{{post.text }}</p>
{% for comment in post.comment.all %}
<p>{{ comment.text }}</p>
{% endfor %}
</div>