Создание кнопки "нравится/не нравится" в блоге в Django/Wagtail

Я новичок в Django и Wagtail и искал способ реализовать "простую" кнопку "нравится/не нравится" на странице записи блога с помощью Wagtail.

Я включил поле total_likes IntegerField в мою модель для страницы и хотел бы увеличивать или уменьшать этот int в базе данных, когда пользователь нажимает кнопку на html-шаблоне.

Предполагается, что пользователь не вошел в систему. Большинство руководств, которые я нашел, имеют дело с этим только для зарегистрированных пользователей, а это не то, что мне нужно.

Буду рад, если кто-нибудь укажет мне правильное направление. Код models.py приведен ниже.

Я не понимаю, как вызвать функцию из шаблона.

    class BlogEntry(Page):
        date = models.DateField("Post date")
        intro = models.CharField(max_length=250, blank=False)
        body = RichTextField(blank=True)
        tags = ClusterTaggableManager(through=BlogEntryTag, blank=True)
        categories = ParentalManyToManyField('blog.BlogCategory', blank=False)
        total_likes = models.IntegerField(blank=False, default=0)
        image = models.ForeignKey(
            "wagtailimages.Image",
            null=True,
            blank=True,
            on_delete=models.SET_NULL,
            related_name="+"
        )
        streamBody = StreamField([
            ("text", blocks.StaticContentBlock()),
            ("quotes", blocks.QuoteBlock()),
            ("image_and_text", blocks.ImageTextBlock()),
            ("related_articles", blocks.RelatedArticlesBlock()),
            ], null=True, blank=True)
    
        sidebarBody = StreamField([
            ("text", blocks.StaticContentBlock()),
            ("quotes", blocks.QuoteBlock()),
            ("image_and_text", blocks.ImageTextBlock()),
            ("related_articles", blocks.RelatedArticlesBlock()),
            ], null=True, blank=True)
    
    
        search_fields = Page.search_fields + [
            index.SearchField('intro'),
            index.SearchField('body'),
        ]
    
        content_panels = Page.content_panels + [
            MultiFieldPanel([
                ImageChooserPanel("image"),
                FieldPanel('date'),
                FieldPanel('tags'),
                FieldPanel('categories', widget=forms.CheckboxSelectMultiple),
            ], heading="Blog information"),
            FieldPanel('intro'),
            StreamFieldPanel("streamBody"),
        ]
    
    
        sidebar_panels = [
            MultiFieldPanel([
                FieldPanel("sidebarBody"),
                ], heading="Sidebar Content")
            ]
    
        edit_handler = TabbedInterface(
            [
                ObjectList(content_panels, heading="Custom"),
                ObjectList(Page.promote_panels, heading="Promote"),
                ObjectList(Page.settings_panels, heading="Settings"),
                ObjectList(sidebar_panels, heading="Sidebar"),
            ]
        )
    
    
        def __str__(self):
            return self.total_likes
    
        def likePost(self):
            self.total_likes += 1
    
        def dislikePost(self):
            self.total_likes -= 1

Обзор

Добро пожаловать в Django и Wagtail, вам предстоит многому научиться, но, надеюсь, вы найдете в этом удовольствие. Первое, что нужно уяснить, это то, как веб-сайт (браузер/клиент) может общаться с сервером (Python-код под управлением Django/Wagtail). Даже если ваша модель Page имеет метод likePost, вам нужно обеспечить способ для вашего Page, чтобы обработать этот вид запроса.

В Интернете используется система HTTP-запросов, наиболее распространенными из которых являются GET и POST, где GET используется для получения данных для показа пользователю, POST используется для случаев, когда сайт хочет отправить что-то обратно на сервер.

Документация Django по работе с формами может быть хорошим местом для начала, чтобы понять этот процесс немного больше. Как только на вашем сайте появится form (в шаблоне HTML), вы можете обеспечить способ "прослушивания" этой формы при отправке. В Wagtail есть метод, который существует во всех моделях Page и называется serve, и он позволяет переопределить обычное поведение.

Решение

В приведенном ниже решении вам нужно сделать следующее:

1. Добавьте два form к вашему шаблону (например, blog_page.html)

  • Не забудьте загрузить теги wagtailcore_tags, чтобы в форме можно было получить доступ к URL страницы.
  • Для простоты были созданы две формы, одна с кнопкой "нравится", другая с кнопкой "не нравится".
  • Обе формы будут использовать method="POST" и action (это URL для POST), являющийся текущим URL.
  • Каждая форма содержит csrf_token, вы можете прочитать больше об этом в документации Django, но это помогает избежать некоторых проблем безопасности.
  • Каждая форма содержит html input, который hidden имеет имя и значение, мы будем использовать name только в коде сервера, чтобы определить, какая кнопка была нажата.
{% extends "base.html" %}
{% load wagtailcore_tags %}
... BLOG CONTENT
    <form action="{% pageurl page %}" method="POST" role="form">
        {% csrf_token %}
        <input type="hidden" name="like" value="true">
        <input type="submit" value="LIKE">
    </form>
    <form action="{% pageurl page %}" method="POST" role="form">
        {% csrf_token %}
        <input type="hidden" name="dislike" value="true">
        <input type="submit" value="DISLIKE">
    </form>

2. Переопределите метод serve в вашей Page модели

Метод serve на модели Page принимает аргумент request, который является объектом запроса Django request object и должен вернуть ответ. К счастью, нам не нужно думать о том, как строится этот ответ, просто знайте, что мы должны вызвать super (исходную) версию этого метода после любой логики.

  • Проверьте, является ли текущий запрос POST-запросом, и если да, то проверьте, какое значение было отправлено, в зависимости от значения вызовите метод Page, который соответствует
  • .
  • Обновите методы likePost и dislikePost, чтобы обеспечить сохранение данных модели через self.save()
  • .
    class BlogEntry(Page):
    # ...

    def likePost(self):
        self.total_likes += 1
        self.save() ## note: you may need to ensure you call save to update data

    def dislikePost(self):
        self.total_likes -= 1
        self.save() ## note: you may need to ensure you call save to update data

    def serve(self, request):
        if request.method == 'POST':
            if request.POST.get('like'):
                self.likePost()
                # a form POST has been submitted with a value for 'like'
            if request.POST.get('dislike'):
                # a form POST has been submitted with a value for 'dislike'
                self.dislikePost()
        
        # ensure we call the super's serve method so that the page loads correctly
        return super(BlogPage, self).serve(request)


Полезно знать

  • Как вы заметили, это базовый запрос, который не требует аутентификации (входа в систему) для отправки лайков, однако очень вероятно, что вы получите много спама таким способом, и вы можете рассмотреть другие подходы (даже сторонние системы), чтобы обойти это.
  • Этот способ хранения лайков (как целое число) также не даст вам много данных, просто число в текущий момент времени, возможно, стоит отслеживать отдельные отправки и затем предоставлять подсчеты в пользовательском интерфейсе.
  • Вот отличный обзор HTTP от MDN, который я нашел хорошей ссылкой для понимания того, как сервер обрабатывает запросы и ответы.
Вернуться на верх