Permettre aux utilisateurs de commenter votre site avec Django Comments Xtd

Cet article montrera comment ajouter de l'interactivité à votre site en permettant à vos lecteurs de commenter, en utilisant le package Django Comments Xtd. Laissez un commentaire pour me faire savoir ce que vous en pensez!

12 Juillet 2020 15:34
Remarque: une ligne modifiée dans la méthode save() du modèle CustomComment, voir ci-dessous

Construire votre propre fonctionnalité de commentaire sans packages externes n'est pas très difficile, mais ne vous fournira que des fonctionnalités de base. L'intégration avec des joueurs externes tels que Disqus est une autre option. Dans ce tutoriel, on va construire notre fonctionnalité de commentaire avec le package Django Comments Xtd, qui étend le cadre de commentaires Django Comments autrefois officiel. Il a beaucoup de fonctionnalités que vous attendez d'un cadre de commentaires, comme commenter des commentaires (threads), signaler, aimer / détester, la prévention du spam, etc.

Les instructions nous disent de l'installer d'abord:

pip3 install django-comments-xtd

et l'ajouter à requirements.txt. Vérifiez que vous avez django.contrib.sites dans votre INSTALLED_APPS et définissez le domaine du site dans votre administrateur Django égal à localhost: 8000. Ajoutez

'django_comments_xtd',
'django_comments',

à votre INSTALLED_APPS après l'application dans laquelle vous les utilisez. Assurez-vous que le courrier électronique est configuré dans votre fichier de paramètres, car l'application va l'utiliser. Le tutoriel de l'application donne un aperçu complet des configurations; on mettra en œuvre les commentaires (j'aime / je n'aime pas) et le filetage, ainsi qu'on ajoutera certaines fonctionnalités. Il y a quelques paramètres standard à ajouter à notre base.py (remplacez example.com par votre domaine):

COMMENTS_APP = 'django_comments_xtd'
COMMENTS_XTD_SALT = (b"Timendi causa est nescire. "
                     b"Aequam memento rebus in arduis servare mentem.")
COMMENTS_XTD_FROM_EMAIL = "noreply@example.com"
COMMENTS_XTD_CONTACT_EMAIL = "helpdesk@example.com"

On doit également ajouter l'espace url à urls.py de notre projet (remarque: le tutoriel utilise la syntaxe brute r''; nous n'en avons pas besoin ici car il n'y a pas de caractères spéciaux):

path('comments/', include('django_comments_xtd.urls')),

Dans models.py, on doit ajouter une méthode get_absolute_url à notre modèle ArticlePage, car par défaut il n'en a pas. Il a cependant une méthode get_url, on ajoute donc simplement:

def get_absolute_url(self):
    return self.get_url()

On va également modifier légèrement le modèle de commentaire de deux manières. Tout d'abord, nous y ajouterons un champ page, afin qu'on puisse accéder directement à la page à partir d'un commentaire. Cela facilite la liste de tous les commentaires par page, par ex. en admin, si nous le choisissons. Deuxièmement, si un utilisateur enregistré fait le commentaire, on remplisse automatiquement le champ user_name avec le champ display_name de notre modèle utilisateur. Par défaut, il est rempli avec le nom complet de l'utilisateur, mais comme on a le display_name dans notre modèle utilisateur, on pourra aussi bien l'utiliser.

from django_comments_xtd.models import XtdComment

class CustomComment(XtdComment):
    page = ParentalKey(ArticlePage, on_delete=models.CASCADE, related_name='customcomments')

    def save(self, *args, **kwargs):
        if self.user:
            self.user_name = self.user.display_name
        self.page = ArticlePage.objects.get(pk=self.object_pk)
        super(CustomComment, self).save(*args, **kwargs)

Le champ ParentalKey parle de lui-même. Pour enregistrer automatiquement la page et le nom d'affichage, nous remplaçons la méthode save () du modèle. Le modèle de commentaires Django et donc sa version étendue XtdComment ont déjà des champs user_name, user (avec le modèle utilisateur actuel) et object_pk, étant la clé primaire de l'objet auquel le commentaire est lié, dans notre cas une instance ArticlePage. Remarque: pour les utilisateurs non enregistrés qui soumettent des commentaires, le champ user ne sera pas renseigné, d'où la déclaration conditionnelle. On utilise ces champs dans la méthode save (). On doit faire connaître ce nouveau modèle dans nos paramètres avec:

COMMENTS_XTD_MODEL = 'cms.models.CustomComment'

Afficher tous les commentaires par page dans Wagtail admin est désormais aussi simple que d'ajouter la ligne suivante aux content_panels de notre modèle ArticlePage:

InlinePanel('customcomments', label=_("Comments")),

Cependant, avec beaucoup de commentaires, cela pourrait devenir un peu compliqué, alors n'hésitez pas à ignorer cela. La vue d'ensemble des commentaires dans l'admin Django traditionnel est bien meilleure. Pour cela, on doit ajouter ce qui suit à notre admin.py:

from django_comments_xtd.admin import XtdCommentsAdmin

class CustomCommentAdmin(XtdCommentsAdmin):
    list_display = ('cid', 'name', 'page', 'object_pk',
                    'ip_address', 'submit_date', 'followup', 'is_public',
                    'is_removed')
    fieldsets = (
        (None, {'fields': ('content_type', 'page', 'object_pk', 'site')}),
        ('Content', {'fields': ('user', 'user_name', 'user_email',
                                'user_url', 'comment', 'followup')}),
        ('Metadata', {'fields': ('submit_date', 'ip_address',
                                 'is_public', 'is_removed')}),
    )

admin.site.register(CustomComment, CustomCommentAdmin)

Par rapport à l'exemple du didacticiel, on n'a ajouté que le champ page et supprimé quelques champs.

Il est temps de regarder les modèles html. Comme cela est très bien décrit dans le tutoriel, on ira rapidement. On ajoute un formulaire de commentaire et tous les commentaires existants au modèle qui contient notre article (dans notre cas article_page.html):

{% load wagtailimages_tags widget_tweaks comments comments_xtd static %}

<div class="container-fluid mt-4 comment-form">
    {% render_comment_form for page %}
</div>

{% get_comment_count for page as comment_count %}
{% if comment_count %}
    <hr>
    <div class="container-fluid mt-4 media-list">
        {% render_xtdcomment_tree for page allow_feedback show_feedback %}
    </div>
{% endif %}

Django Comments Xtd propose trois balises de modèle ici:

  • render_comment_form pour rendre le formulaire de commentaire
  • get_comment_count pour récupérer le nombre de commentaires pour l'objet courant (dans notre cas l'objet page)
  • render_xtdcomment_tree pour afficher tous les commentaires en mode fileté pour la page en cours

Il fournit également deux arguments:

  • allow_feedback pour activer J'aime / Je n'aime pas (symboles pouces vers le haut / bas)
  • show_feedback pour afficher le nombre de "J'aime" et de "Je n'aime pas"

Les balises sont chargés en haut via comments et comments_xtd, ainsi que d'autres balises dont nous avons besoin pour les modèles inclus (voir ci-dessous). Les paramètres qui doivent être ajoutés à notre fichier de paramètres pour que cela fonctionne sont les suivants:

COMMENTS_XTD_MAX_THREAD_LEVEL = 1  # default is 0
COMMENTS_XTD_LIST_ORDER = ('-thread_id', 'order')  # default is ('thread_id', 'order')
COMMENTS_XTD_APP_MODEL_OPTIONS = {
    'cms.articlepage': {
        'allow_flagging': False,
        'allow_feedback': True,
        'show_feedback': True,
    }
}

Le premier paramètre autorise les réponses sur les commentaires, mais pas les réponses sur les réponses. Bien sûr, vous pouvez changer cela à votre guise. Le deuxième paramètre fait apparaître les commentaires dans l'ordre chronologique inverse. Le troisième paramètre désactive le signalement (expliqué dans le didacticiel) et autorise les commentaires.

On souhaite également modifier deux modèles:

  • form.html affiche le formulaire de commentaire. Copiez-le et placez-le dans un nouveau répertoire /comments dans le répertoire /templates de votre application.
  • comment_tree.html affiche tous les commentaires filetés. Copiez-le et placez-le dans un nouveau répertoire /django_comments_xtd dans le répertoire /templates de votre application.

On laissera tous les autres modèles tels quels, mais n'hésitez pas à modifier leur style comme bon vous semble. En regardant form.html, on voit beaucoup d'éléments: des champs cachés, un pot de miel (pour l'anti-spam) deux boutons de soumission (un pour l'aperçu). Attention à ne rien enlever de vital! On fera ce qui suit:

  • utilisez notre modèle standard account/form_field.html, qui nous donnera le style et les commentaires du widget-tweaks, et simplifiera quelque peu le modèle,
  • pour cela, on ajoute également class="needs-validation" novalidate à notre form,
  • on laissera de côté la condition d'avoir un nom complet pour afficher le champ de nom,
  • on laissera de côté le champ URL,
  • et omettez les classes offset dans la case à cocher et les boutons de soumission.

Avec cela, notre modèle form.html devient:

{% load i18n comments %}

<form method="POST" action="{% comment_form_target %}" class="needs-validation" novalidate>
    {% csrf_token %}
    <fieldset>
        <input type="hidden" name="next" value="{% url 'comments-xtd-sent' %}"/>
    
        <div class="alert alert-danger" data-comment-element="errors" hidden>
        </div>

        {% for field in form %}
            {% if field.is_hidden %}<div>{{ field }}</div>{% endif %}
        {% endfor %}

        <div style="display:none">{{ form.honeypot }}</div>

        <div class="form-group">
            {% with field=form.comment %}{% include "account/form_field.html" %}{% endwith %}
        </div>

        {% if not request.user.is_authenticated %}
            <div class="form-group">
                {% with field=form.name %}{% include "account/form_field.html" %}{% endwith %}
            </div>
        {% endif %}

        {% if not request.user.is_authenticated or not request.user.email %}
            <div class="form-group">
                {% with field=form.email %}{% include "account/form_field.html" %}{% endwith %}
            </div>
        {% endif %}

        <div class="form-group custom-control custom-checkbox">
            <small>
                {{ form.followup }}
                <label for="id_followup{% if cid %}_{{ cid }}{% endif %}" class="custom-control-label">&nbsp;{{ form.followup.label }}</label>
            </small>
        </div>

    </fieldset>

    <div class="form-group">
        <input type="submit" name="post" value="{% trans 'Send' %}" class="btn btn-outline-primary btn-sm" />
        <input type="submit" name="preview" value="{% trans 'Preview' %}" class="btn btn-outline-secondary btn-sm" />
    </div>
</form>

Dans le modèle comment_tree.html, on remplace le nom de la classe CSS comment par xtdcomment, pour éviter un conflit avec Wagtail Code Block, et supprime un peu d'espacement (pb-3 à la ligne 11, pour être exact). On ajoutera également la photo d'utilisateur de notre modèle d'utilisateur. Le code remplaçant le code actuel de la photo devient:

{% if item.comment.user.photo %}
    <img alt="" src="{{ item.comment.user.photo.url }}" class="profile-image-thumbnail">
{% else %}
    {{ item.comment.user_email|xtd_comment_gravatar }}
{% endif %}

Remarque: les symboles J'aime / Je n'aime pas sont générés via FontAwesome, et bien qu'ils semblent être dans les fichiers statiques de Django Comments Xtd, je n'ai pas pu les faire fonctionner. J'ai donc ajouté ce qui suit à mon modèle base.html:

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/all.css">

Le style est aussi simple que possible et cohérent avec le reste du site. On alignera le texte et les formulaires à gauche et utiliserons une largeur de 800px. La première classe ci-dessous est générée dans account/form_field.html, toutes les autres ont été définies explicitement. Ajoutez au fichier CSS:

.form-control.input-field-comment {
    width: 800px;
    max-width: 100%;
    height: 80px;
}
/* for the comment section on article pages */
.comment-form  {
    width: 800px;
    max-width: 100%;
    margin-left: 0;
}
.media-list {
    width: 800px;
    max-width: 100%;
    margin-left: 0;
}
.xtdcomment {
    border: 1px solid lightgrey;
    margin-bottom: 10px;
    padding: 5px;
}
/* for thumbnail image in comments */
.profile-image-thumbnail {
    float: left;
    width: 64px;
    height: 64px;
    max-width: 100%;
    margin-right: 5px;
    margin-bottom: 5px;
}

C'est tout. Migrez la base de données pour intégrer les modifications de modèle et exécutez le serveur. Lorsque vous êtes connecté, vous ne verrez qu'un champ de formulaire de commentaire et une case à cocher à notifier. Lorsque vous n'êtes pas connecté, vous verrez deux champs supplémentaires pour un nom et un e-mail. La soumission d'un commentaire nécessite une vérification par e-mail. Cela peut être désactivé avec COMMENTS_XTD_CONFIRM_EMAIL = False, mais il est sage de prendre des mesures supplémentaires contre le spam et les abus, comme décrit dans le didacticiel. Essayez de soumettre et de prévisualiser certains commentaires, de répondre aux commentaires, d'aimer / de ne pas aimer les commentaires. Vous pouvez afficher tous les commentaires dans l'administrateur Django.

Un inconvénient est que lorsqu'un utilisateur enregistré souhaite commenter mais n'est pas connecté, il doit se rendre sur la page de connexion pour se connecter, puis revenir à l'article spécifique pour commenter. Lisez la suite si vous souhaitez intégrer la connexion dans la page de l'article pour résoudre ce problème. Nous allons également discuter un peu plus de Django Comments Xtd.

Commentez cet article (connectez-vous d'abord ou confirmez par nom et email ci-dessous)