Комментарии с помощью contentype

    blazer |   25.03.2019 |   11:46:17 |   Django |

Всем доброго времени суток! Сегодня я расскажу, как делал свою систему коментариев к интернет магазину. Сразу скажу, что здесь приведен не весь код а его часть т.к. основная логика обработки функций является коммерческой.

На сайте комментарии должны создваться для нескольких разделов это Новости и Продукт. Думаю не правильно было бы писать комментарии как для одного раздела так и для другого. Логично сделать одно приложение "комментарии" и подключать его к другим приложениям к которым это нужно.

 

Приступим.

Создаем новое прложение Comments  и добавляем его в массив installed_apps вашего проекта.

Пишем модель комментариев, в моем случае я сделал так.

class Comment(MPTTModel):
    parent = TreeForeignKey('self', blank=True, null=True, verbose_name='Родительская категория', related_name='children', on_delete=models.CASCADE, editable=False) # editable=False (Скрыл поле parent в админке)
    user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE, verbose_name='Пользователь')
    text = models.TextField(verbose_name='Комментарий')
    email = models.EmailField(max_length=50, blank=True, verbose_name='e-mail')
    user_name = models.CharField(max_length=100, blank=True, verbose_name='Логин пользователя')
    like = models.IntegerField(default=0, verbose_name='like')
    dislike = models.IntegerField(default=0, verbose_name='dislike')
    user_like = models.ManyToManyField(User, verbose_name='Кто поставил лайк', related_name='users_like', blank=True)
    user_dislike = models.ManyToManyField(User, verbose_name='Кто поставил дизлайк', related_name='users_dislike', blank=True)
    count_comment = models.IntegerField(default=0, verbose_name='Количество комментариев')
    is_active = models.BooleanField(default=False, verbose_name='Модерация')
    created = models.DateTimeField(auto_now_add=True, verbose_name='Создан')
    updated = models.DateTimeField(auto_now=True, verbose_name='Обновлен')

    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)  # Создаем связь с внешней моделью ContentType.
    object_id = models.PositiveIntegerField()  # Содаем поле, которое будет хранить значения первичных ключей экземпляров модели с которой создана связь.
    content_object = GenericForeignKey('content_type', 'object_id')  # В это поле передаем в качестве аргументов, имена полей созданных ранее.

    class Meta:
        verbose_name = 'Комментарий'
        verbose_name_plural = 'Коментарии'
        ordering = ['-created']

    def __str__(self):
        return '{}'.format(self.content_object)

Как видно в модели Comment нет связи ForeignKey на внешнюю модель в которой мы бы хотели выводить комментарии, в моем случае это модель News и Product. Вместо этого у нас есть связь на промежуточную модель ContentType. Вот об этом нужно поговорить подробнее.

content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)  # Создаем связь с внешней моделью ContentType.
object_id = models.PositiveIntegerField()  # Содаем поле, которое будет хранить значения первичных ключей экземпляров модели с которой создана связь.
content_object = GenericForeignKey('content_type', 'object_id')  # В это поле передаем в качестве аргументов, имена полей созданных ранее.

В моедле я создал три поля, эти поля подписаны комментариями. Если кратко, то Content Types Framework сохраняет информацию о моделях в таблицу contenttypes, а именно: название приложения, название модели и тип.

Это говорит о том, что таким образом можно создать GenericForeignKey на любую модель используя всего одно поле.

Нужно не забыть в моделях в которых будут выводится комментарии сделать обратную ссылку на комментарии comments = GenericRelation('comments.comment') 

В моем случае я добавил это поле в модель News в приложении info и модель Product в приложении shop. Позже объясню для чего это нужно будет.

Далее создаем templatetags, как это сделать я писал в этой статье.  Создаем в проекте каталог templatetags в нем создаем файл __init__.py - говорит что это модуль питона и создаем сам модуль comments.py .

from django import template
from django.core.paginator import Paginator
from django.contrib.contenttypes.models import ContentType

from comments.forms import CommentForm, CommentFormCaptcha

register = template.Library()

@register.inclusion_tag('add_comments.html')
def add_comment(obj, request):
    '''Создаем темплейттег'''

    '''Создание словаря для инициализации формы начальными значениями'''
    form_initial = {'content_type': ContentType.objects.get_for_model(obj), 'object_id': obj.pk}

    '''Получаем комментарии связанные с объектом'''
    comments = obj.comments.filter(is_active=True).order_by('-created')

    '''Счетаем общее количество коментариев к посту'''
    all_comment = comments.count()

    '''Пагинация комментариев'''
    paginator = Paginator(comments, 5)
    page = request.GET.get('page')
    comments = paginator.get_page(page)

    '''Проверяем, если пользователь не авторизован то выводим форму с капчей иначе если авторизован, то выводим форму без капчи'''
    if not request.user.is_authenticated:
        form = CommentFormCaptcha(initial=form_initial)  # Форма с капчей
    else:
        form = CommentForm(initial=form_initial)  # Форма без капчи


    return {'comments': comments,
            'all_comment': all_comment,
            'form': form,
            'request': request,
            }



Впринципе тут особо нечего описывать не нужно т.к. все и так понятно и подписано в самом коде. Сотит отметить, что шаблон для этого темплейттега я сделал "add_comments.html" в нем будет осуществляться создание и вывод комментариев.

Дальше в  forms.py создаем форму комментариев, в urls.py создаем маршрутизацию, в views.py создаем функцию которая будет создавать комментарий, функцию редактирования комментария, функцию удаления комментария и функции лайка и дизлайка. Подробно я не буду описывать это все т.к. это страндарно.

Чтоб отобразить комментарии нужно в шаблоне приложения где вы хотите вывести комментарии подгрузить модуль темплейттега {% load comments %} и вывести сам темплейттег в моем случае для новостей {% add_comment newsdetails request %} и для продукта {% add_comment product request %}

Что бы посчетать количество комметарев к статье, нужно задействовать нашу обратную ссылку о которой я писал ренее на модель комментариев. Здесь мы добираемся до модели комментариев all_comment = newsdetails.comments.count() .

Конечно это не полная статья а больше как заметка для себя, если у вас будут какие либо вопросы, то вы всегда можете написать мне на емейл или через форму обратной связи.

 

Ваши комментарии

Комментарии могут оставлять только зарегистрированые пользователи!

Disqus - комментарии

blog comments powered by Disqus