.. _comments:
********
Comments
********
Django Cast provides a full commenting system built on top of
`django-contrib-comments `_.
Comments can be enabled or disabled at three levels:
App level
The global :ref:`CAST_COMMENTS_ENABLED ` setting
(defaults to ``False``).
Blog level
Each ``Blog`` model has a ``comments_enabled`` field (defaults to ``True``).
Post level
Each ``Post`` model also has a ``comments_enabled`` field (defaults to
``True``).
A comment form is only rendered when **all three levels** evaluate to enabled.
.. _comments_configuration:
Configuration
=============
To enable the built-in comments integration, set:
.. code-block:: python
COMMENTS_APP = "cast.comments"
.. _comments_settings:
Settings
--------
``CAST_COMMENTS_ENABLED``
Master switch for the entire comment system. Set to ``True`` to enable
comments. Defaults to ``False``.
``CAST_COMMENTS_EXCLUDE_FIELDS``
Tuple of form field names to hide from the comment form. Useful for
removing fields like ``email``, ``url``, or ``title``. Defaults to ``()``.
Also accepts the legacy name ``FLUENT_COMMENTS_EXCLUDE_FIELDS``.
``CAST_COMMENTS_DEFAULT_MODERATOR``
Dotted Python path to a moderator class. The class must provide ``allow()``
and ``moderate()`` methods (see :ref:`comments_moderation`). Set to
``"none"``, ``"null"``, ``"default"``, or ``""`` to use a built-in
``NullModerator`` that allows all comments and never moderates. Defaults to
``"cast.moderation.Moderator"`` (the built-in spam filter moderator).
Also accepts the legacy name ``FLUENT_COMMENTS_DEFAULT_MODERATOR``.
``CAST_COMMENTS_FORM_CSS_CLASS``
CSS class applied to the comment form. Defaults to
``"comments-form form-horizontal"``.
``CAST_COMMENTS_LABEL_CSS_CLASS``
CSS class for form labels (crispy-forms). Defaults to ``"col-sm-2"``.
``CAST_COMMENTS_FIELD_CSS_CLASS``
CSS class for form field wrappers (crispy-forms). Defaults to
``"col-sm-10"``.
``CRISPY_TEMPLATE_PACK``
The crispy-forms template pack used for rendering form fields and AJAX
error messages. Not specific to django-cast but affects how comment form
errors are rendered in AJAX responses. Defaults to ``"bootstrap4"``.
Example configuration:
.. code-block:: python
COMMENTS_APP = "cast.comments"
CAST_COMMENTS_ENABLED = True
CAST_COMMENTS_EXCLUDE_FIELDS = ("email", "url", "title")
CAST_COMMENTS_DEFAULT_MODERATOR = "cast.moderation.Moderator"
.. _comments_internals:
How ``COMMENTS_APP`` Integration Works
=======================================
Setting ``COMMENTS_APP = "cast.comments"`` tells ``django-contrib-comments``
to use the cast comments package. The package provides two hook functions
in its ``__init__.py``:
``get_model()``
Returns ``CastComment``, a **proxy model** (``managed = False``) that
adds a custom manager with ``select_related("user")`` for efficient
queryset loading. When ``threadedcomments`` is installed, ``CastComment``
inherits from ``ThreadedComment`` instead of the plain ``Comment`` model.
``get_form()``
Returns ``CastCommentForm``, which extends the appropriate base form
(``ThreadedCommentForm`` or ``CommentForm``). It removes fields listed in
``CAST_COMMENTS_EXCLUDE_FIELDS`` and reorders the remaining fields so
security fields (``content_type``, ``object_pk``, ``timestamp``,
``security_hash``) appear first, the ``parent`` field follows in threaded
mode, visible fields come next, and the ``honeypot`` field is placed last.
.. _comments_threaded_replies:
Threaded Replies
================
If ``threadedcomments`` is in ``INSTALLED_APPS``, threaded replies are
enabled automatically. The comment system detects the package at startup and
switches the base model from ``django_comments.models.Comment`` to
``threadedcomments.models.ThreadedComment``, which adds a ``parent`` foreign
key for nesting.
When threaded mode is active:
- The comment form includes a hidden ``parent`` field.
- Each rendered comment shows a "reply" link that sets the ``parent`` value via
the JavaScript layer (see :ref:`comments_ajax_posting`).
- The comment list template uses ``fill_tree`` and ``annotate_tree`` filters
from ``threadedcomments`` to produce nested ```` markup.
- The flat list template (``flat_list.html``) is used when threaded comments are
disabled.
.. note::
Install ``django-threadedcomments`` and add ``"threadedcomments"`` to
``INSTALLED_APPS`` to enable threaded replies. No additional configuration
is required.
.. _comments_ajax_posting:
AJAX Comment Posting
====================
Comments are posted asynchronously via a dedicated AJAX endpoint. The
JavaScript client (``ajaxcomments.ts``, built as an IIFE by Vite) intercepts
the comment form submission and uses ``fetch`` to POST to
``/comments/post/ajax/``. The request includes an
``X-Requested-With: XMLHttpRequest`` header so the server-side view can
distinguish it from a regular form submission.
.. _comments_ajax_server_flow:
Server-Side Flow
----------------
The ``post_comment_ajax`` view handles the request:
1. **Authentication check** -- if the user is logged in, ``name`` and
``email`` are auto-filled from the user profile when not provided.
2. **Target resolution** -- the ``content_type`` and ``object_pk`` fields
identify the target object (typically a ``Post`` page).
3. **Form validation** -- the standard ``django_comments`` form is
instantiated. Security hash and honeypot checks run first.
4. **Preview mode** -- if the ``preview`` button was clicked and the form is
valid, the view renders the comment HTML and returns it without saving. If
the form has errors, no comment object is produced and the response
contains only the error details.
5. **Signal dispatch** -- ``comment_will_be_posted`` fires, giving the
moderator (see :ref:`comments_moderation`) a chance to mark the comment
as spam. If any receiver returns ``False``, the comment is rejected.
6. **Save and respond** -- the comment is saved, ``comment_was_posted``
fires, and a JSON response is returned.
.. _comments_ajax_response:
JSON Response Format
--------------------
On success or form-validation errors, the AJAX endpoint returns a JSON object
with the following fields. Early failures (missing fields, invalid content
type, security hash mismatch) return a plain-text HTTP 400 response instead.
JSON fields:
``success``
Boolean indicating whether the comment was accepted.
``action``
Either ``"post"`` or ``"preview"``.
``errors``
A dictionary of field-name to rendered error HTML (empty on success).
``html``
The rendered comment HTML fragment, ready to insert into the page. Only
present when a comment object was successfully created or previewed (absent
on validation errors).
``comment_id``
The database ID of the saved comment (absent on preview or error).
``parent_id``
The parent comment ID when threaded replies are active (``null`` for
top-level comments).
``is_moderated``
Present only for staff users. ``true`` when the comment was auto-moderated
(marked not public).
``use_threadedcomments``
Boolean indicating whether threaded comment mode is active.
``object_id``
The primary key of the commented-on object.
.. _comments_ajax_assets:
Client-Side Assets
------------------
The AJAX comment posting uses bundled assets under:
- ``fluent_comments/js/ajaxcomments.js``
- ``fluent_comments/css/ajaxcomments.css``
If these are not included in your templates, the form falls back to the
default django-contrib-comments flow (redirecting to ``comments/posted/`` and
``comments/preview/``).
The form template at ``comments/form.html`` sets
``data-ajax-action="{% url 'comments-post-comment-ajax' %}"`` on the
``