Gebruikers in staat stellen om op je site te reageren met Django Comments Xtd

Dit artikel laat zien hoe je wat interactiviteit aan je site kunt toevoegen door je lezers te laten reageren met het pakket Django Comments Xtd. Laat een reactie achter om me te laten weten wat je ervan vindt!

12 juli 2020 15:34
Let op: één regel gewijzigd in save () methode van het model CustomComment, zie hieronder

Het bouwen van je eigen commentaarfunctionaliteit zonder externe pakketten is niet erg moeilijk, maar biedt alleen basisfunctionaliteit. Integreren met externe spelers zoals Disqus is een andere optie. In deze tutorial bouwen we onze commentaarfunctionaliteit met het pakket Django Comments Xtd, dat het eens officiële Django Comments Framework uitbreidt. Het heeft veel van de functionaliteit die u van een opmerkingenraamwerk mag verwachten, zoals reageren op opmerkingen (threads), markeren, like/dislike, spampreventie etc.

De instructies zeggen ons het eerst te installeren:

pip3 install django-comments-xtd

Voeg het toe aan requirements.txt. Controleer of je django.contrib.sites in je INSTALLED_APPS hebt en stel het domein van de Site in je Django-admin gelijk aan localhost: 8000. Voeg

'django_comments_xtd',
'django_comments',

aan je INSTALLED_APPS toe na de toepassing waarin je ze gebruikt. Zorg ervoor dat je e-mail hebt geconfigureerd in je instellingenbestand, aangezien de applicatie het gaat gebruiken. De tutorial van de applicatie geeft een compleet overzicht van de configuraties; we zullen feedback (like/dislike) en threading implementeren, evenals wat functionaliteit toevoegen. Er zijn enkele standaardinstellingen om toe te voegen aan onze base.py (vervang example.com door je eigen domein):

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"

We moeten ook de urls toevoegen aan de urls.py van ons project (let op: de tutorial gebruikt raw string syntax r''; we hebben dat hier niet nodig omdat er geen speciale karakters zijn):

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

In onze models.py moeten we een get_absolute_url-methode toevoegen aan ons ArticlePage-model, omdat het er standaard geen heeft. Het heeft echter wel een get_url-methode, dus we voegen eenvoudig toe:

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

We zullen het opmerkingenmodel ook op twee manieren enigszins wijzigen. Eerst zullen we er een veld page aan toevoegen, zodat we de pagina direct vanuit een opmerking kunnen openen. Dit maakt het gemakkelijk om alle opmerkingen per pagina weer te geven, b.v. in admin, als we daarvoor kiezen. Ten tweede, als een geregistreerde gebruiker de opmerking maakt, vullen we automatisch het veld user_name in met het veld display_name van ons gebruikersmodel. Standaard is het gevuld met de volledige naam van de gebruiker, maar aangezien we de display_name in ons gebruikersmodel hebben, kunnen we deze net zo goed gebruiken.

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)

Het ParentalKey-veld spreekt voor zich. Om de pagina en de weergavenaam automatisch op te slaan, overschrijven we de methode save () van het model. Het Django comments model en dus de uitgebreide versie XtdComment hebben al velden user_name, user (met het huidige gebruikersmodel) en object_pk, zijnde de primaire sleutel van het object waaraan de opmerking is gekoppeld, in ons geval een ArticlePage-instantie. Noot: voor niet-geregistreerde gebruikers die opmerkingen indienen, is het veld user leeg, vandaar het if-statement. We gebruiken deze velden in de save () methode. We moeten dit nieuwe model in onze instellingen bekend maken met:

COMMENTS_XTD_MODEL = 'cms.models.CustomComment'

Alle opmerkingen per pagina weergeven in Wagtail admin kan nu door eenvoudigweg de volgende regel toe te voegen aan de content_panels van ons ArticlePage-model:

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

Maar met veel opmerkingen kan dit een beetje rommelig worden, dus sla dit gerust over. Het commentaaroverzicht in de traditionele Django-admin is veel beter. Om dit te hebben, moeten we het volgende toevoegen aan onze 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)

In vergelijking met het voorbeeld in de tutorial hebben we alleen het page veld toegevoegd en een paar velden verwijderd.

Tijd om de templates te bekijken. Aangezien dit heel goed beschreven staat in de tutorial gaan we hier snel doorheen. We voegen een commentaarformulier en alle bestaande commentaren toe aan de template die ons artikel bevat (in ons geval 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 biedt hier drie templatetags:

  • render_comment_form om het commentaarformulier weer te geven
  • get_comment_count om het aantal commentaren voor het huidige object op te halen (in ons geval het page-object)
  • render_xtdcomment_tree om alle commentaren in threaded mode voor de huidige pagina weer te geven

Het biedt ook twee argumenten:

  • allow_feedback om like/dislike in te schakelen (duimen omhoog / omlaag symbolen)
  • show_feedback om het aantal likes en dislikes weer te geven

De templatetags worden bovenaan geladen via comments en comments_xtd, samen met andere tags die we nodig hebben voor ingesloten templates (zie hieronder). De instellingen die aan ons instellingenbestand moeten worden toegevoegd om dit te laten werken, zijn:

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,
    }
}

De eerste parameter staat reacties op opmerkingen toe, maar geen reacties op reacties. Je kunt dit natuurlijk naar eigen inzicht wijzigen. Met de tweede parameter worden opmerkingen weergegeven in omgekeerde chronologische volgorde. De derde parameter schakelt markeren uit (uitgelegd in de tutorial) en staat feedback toe.

We willen ook twee templates wijzigen:

  • form.html geeft het commentaarformulier weer. Kopieer het en plaats het in een nieuwe directory /comments in de directory /templates van de app.
  • comment_tree.html geeft alle threaded reacties weer. Kopieer het en plaats het in een nieuwe directory /django_comments_xtd in de directory /templates van de app.

We laten alle andere sjablonen zoals ze zijn, maar je kunt de styling naar eigen inzicht aanpassen. Als we naar form.html kijken, zien we veel elementen: verborgen velden, een honeypot (voor antispam), twee verzendknoppen (één voor preview). Pas op dat je niets vitaals verwijdert! We doen het volgende:

  • we gebruiken onze standaard account/form_field.html-template, die ons de widget-tweaks-styling en feedback geeft, en ook de sjabloon enigszins vereenvoudigt,
  • daarvoor voegen we ook class="needs-validation" novalidate toe aan onze formulier-tag,
  • we laten de voorwaarde weg om een volledige naam te hebben om het naamveld weer te geven,
  • we laten het URL-veld weg,
  • en laten de offset-klassen op het selectievakje en verzendknoppen weg.

Daarmee wordt onze template form.html:

{% 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>

In de template comment_tree.html vervangen we de CSS-klassenaam comment door xtdcomment, om een conflict met Wagtail Code Block te voorkomen, en verwijderen we een beetje spatiëring (pb-3 in regel 11 om precies te zijn). We zullen ook de gebruikersfoto van ons gebruikersmodel toevoegen. De code die de huidige code voor de foto vervangt, wordt:

{% 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 %}

Opmerking: de like / dislike-symbolen worden gegenereerd via FontAwesome en hoewel ze in de statische bestanden van Django Comments Xtd lijken te staan, kon ik ze niet werkend krijgen. Dus ik heb het volgende toegevoegd aan mijn base.html-template:

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

Styling is zo eenvoudig mogelijk en consistent met de rest van de site. We zullen tekst en formulieren links uitlijnen en een breedte van 800px gebruiken. De eerste klasse hieronder wordt gegenereerd in account/form_field.html, alle andere zijn expliciet gedefinieerd. Voeg toe aan het CSS-bestand:

.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;
}

Dat is alles. Migreer de database om de modelwijzigingen op te nemen en de server uit te voeren. Wanneer je bent ingelogd, zie je alleen een veld voor een reactieformulier en een selectievakje om op de hoogte te worden gehouden. Als je niet bent ingelogd, zie je twee extra velden voor een naam en een e-mail. Het indienen van een opmerking vereist verificatie per e-mail. Dit kan worden uitgeschakeld met COMMENTS_XTD_CONFIRM_EMAIL = False, maar dan is het verstandig om aanvullende maatregelen te nemen tegen spam en misbruik, zoals beschreven in de tutorial. Probeer enkele opmerkingen in te dienen en te bekijken, te reageren op opmerkingen, like / dislikes te geven. Je kunt alle reacties bekijken in Django admin.

Een ongemak is dat wanneer een geregistreerde gebruiker wil reageren maar niet is ingelogd, hij / zij naar de inlogpagina moet gaan om in te loggen en dan terug moet gaan naar het specifieke artikel om te reageren. Lees verder als u de login in de artikelpagina wilt integreren om dit op te lossen. Ook zullen we Django Comments Xtd daar wat verder bespreken.

Reageer op dit artikel (log eerst in of bevestig hieronder met naam en email)