| 1 | .. _ref-contrib-comments-custom: |
| 2 | |
| 3 | ================================== |
| 4 | Customizing the comments framework |
| 5 | ================================== |
| 6 | |
| 7 | Via the :setting:`COMMENTS_APP` setting, the comments framework allows |
| 8 | you to replace the built-in comment model and comment form with your |
| 9 | own classes. |
| 10 | |
| 11 | The COMMENTS_APP |
| 12 | ================ |
| 13 | |
| 14 | A custom :setting:`COMMENTS_APP` should define one or more of the |
| 15 | following module-level functions in it's ``__init__.py`` file. None of |
| 16 | these functions are required, so you can define any combination of |
| 17 | them (all others will use the defaults from |
| 18 | ``django.contrib.comments``): |
| 19 | |
| 20 | .. function:: get_model() |
| 21 | |
| 22 | Return the :class:`~django.db.models.Model` class to use for |
| 23 | comments. This model should inherit from |
| 24 | :class:`django.contrib.comments.models.BaseCommentAbstractModel`, |
| 25 | which defines necessary core fields. |
| 26 | |
| 27 | The default implementation returns |
| 28 | :class:`django.contrib.comments.models.Comment`. |
| 29 | |
| 30 | .. function:: get_form() |
| 31 | |
| 32 | Return the :class:`~django.forms.Form` class you want to use for |
| 33 | creating, validating, and saving your comment model. Your custom |
| 34 | comment form should accept an additional first argument, |
| 35 | ``target_object``, which is the object the comment will be |
| 36 | attached to. |
| 37 | |
| 38 | The default implementation returns |
| 39 | :class:`django.contrib.comments.forms.CommentForm`. |
| 40 | |
| 41 | .. note:: |
| 42 | |
| 43 | The default comment form also includes a number of unobtrusive |
| 44 | spam-prevention features (see |
| 45 | :ref:`notes-on-the-comment-form`). If replacing it with your |
| 46 | own form, you may want to look at the source code for the |
| 47 | built-in form and consider incorporating similar features. |
| 48 | |
| 49 | .. function:: get_form_target() |
| 50 | |
| 51 | Return the URL for POSTing comments. This will be the ``action`` |
| 52 | attribute when rendering your comment form. |
| 53 | |
| 54 | The default implementation returns a reverse-resolved URL pointing |
| 55 | to the :func:`post_comment` view. |
| 56 | |
| 57 | .. note:: |
| 58 | |
| 59 | If you provide a custom comment model and/or form, but you |
| 60 | want to use the default :func:`post_comment` view, you will |
| 61 | need to be aware that it requires the model and form to have |
| 62 | certain additional attributes and methods: see the |
| 63 | :func:`post_comment` view documentation for details. |
| 64 | |
| 65 | .. function:: get_flag_url() |
| 66 | |
| 67 | Return the URL for the "flag this comment" view. |
| 68 | |
| 69 | The default implementation returns a reverse-resolved URL pointing |
| 70 | to the :func:`django.contrib.comments.views.moderation.flag` view. |
| 71 | |
| 72 | .. function:: get_delete_url() |
| 73 | |
| 74 | Return the URL for the "delete this comment" view. |
| 75 | |
| 76 | The default implementation returns a reverse-resolved URL pointing |
| 77 | to the :func:`django.contrib.comments.views.moderation.delete` view. |
| 78 | |
| 79 | .. function:: get_approve_url() |
| 80 | |
| 81 | Return the URL for the "approve this comment from moderation" view. |
| 82 | |
| 83 | The default implementation returns a reverse-resolved URL pointing |
| 84 | to the :func:`django.contrib.comments.views.moderation.approve` view. |
| 85 | |
| 86 | A sample custom comments app |
| 87 | ---------------------------- |
| 88 | |
| 89 | A custom comments app might have an ``__init__.py`` like this:: |
| 90 | |
| 91 | from django.core.urlresolvers import reverse |
| 92 | |
| 93 | def get_model(): |
| 94 | from my_comments_app.models import MyComment |
| 95 | return MyComment |
| 96 | |
| 97 | def get_form(): |
| 98 | from my_comments_app.forms import MyCommentForm |
| 99 | return MyCommentForm |
| 100 | |
| 101 | def get_form_target(): |
| 102 | return reverse('my_comments_app.views.post_comment') |
| 103 | |
| 104 | |
| 105 | ``MyComment`` should inherit from :class:`BaseCommentAbstractModel`, |
| 106 | so in ``models.py``:: |
| 107 | |
| 108 | from django.db import models |
| 109 | from django.contrib.comments.models import BaseCommentAbstractModel |
| 110 | |
| 111 | class MyComment(BaseCommentAbstractModel): |
| 112 | ... fields and custom methods ... |
| 113 | |
| 114 | And ``MyCommentForm`` should accept a target_object argument, |
| 115 | so in ``forms.py``:: |
| 116 | |
| 117 | from django import forms |
| 118 | |
| 119 | class MyCommentForm(forms.Form): |
| 120 | def __init__(self, target_object, data=None, initial=None): |
| 121 | ... |
| 122 | |
| 123 | In order to enable this custom comments app, you would need to have |
| 124 | the following in your project's ``settings.py``:: |
| 125 | |
| 126 | INSTALLED_APPS = ( |
| 127 | ... |
| 128 | 'my_comments_app', |
| 129 | ... |
| 130 | ) |
| 131 | |
| 132 | COMMENTS_APP = 'my_comments_app' |
| 133 | |
| 134 | |
| 135 | API reference |
| 136 | ================================== |
| 137 | |
| 138 | BaseCommentAbstractModel |
| 139 | ------------------------ |
| 140 | |
| 141 | .. class:: BaseCommentAbstractModel |
| 142 | |
| 143 | :class:`BaseCommentAbstractModel` defines the following attributes |
| 144 | and methods, which your custom comment model will inherit: |
| 145 | |
| 146 | .. attribute:: site |
| 147 | |
| 148 | A foreign key to the |
| 149 | :class:`~django.contrib.sites.models.Site` model (see |
| 150 | :ref:`ref-contrib-sites`), defining which site this comment |
| 151 | appears on. |
| 152 | |
| 153 | .. attribute:: content_type |
| 154 | |
| 155 | A foreign key to the |
| 156 | :class:`~django.contrib.contenttypes.models.ContentType` |
| 157 | model. This is the content type of the target object the |
| 158 | comment is attached to. |
| 159 | |
| 160 | .. attribute:: object_pk |
| 161 | |
| 162 | The primary key of the target object. |
| 163 | |
| 164 | .. attribute:: content_object |
| 165 | |
| 166 | A |
| 167 | :class:`~django.contrib.contenttypes.generic.GenericForeignKey` |
| 168 | to the target object, using the :attr:`content_type` and |
| 169 | :attr:`object_pk` attributes. |
| 170 | |
| 171 | .. method:: get_content_object_url() |
| 172 | |
| 173 | Returns a URL that redirects to the URL of the comment's |
| 174 | target object. |
| 175 | |
| 176 | post_comment view |
| 177 | ----------------- |
| 178 | |
| 179 | .. function:: post_comment |
| 180 | |
| 181 | The default :func:`post_comment` view requires the comment model |
| 182 | to have two additional fields: |
| 183 | |
| 184 | .. attribute:: user |
| 185 | |
| 186 | This should be a :class:`ForeignKey` to the :class:`User` |
| 187 | model. The view will store the user who posted the comment in |
| 188 | this field. |
| 189 | |
| 190 | .. attribute:: ip_address |
| 191 | |
| 192 | This should be an :class:`IPAddressField`. The |
| 193 | :func:`post_comment` view will store the remote IP address of |
| 194 | the comment poster in it. |
| 195 | |
| 196 | The :func:`post_comment` view also requires the comment form to |
| 197 | have the following two methods: |
| 198 | |
| 199 | .. method:: security_errors() |
| 200 | |
| 201 | If this method returns a false value, the form will be |
| 202 | considered to have passed anti-spam screening. If it returns |
| 203 | any nonzero value, that value will be coerced to a string and |
| 204 | sent as part of an HTTP 400 (bad request) response. |
| 205 | |
| 206 | .. method:: get_comment_object() |
| 207 | |
| 208 | This method will only be called if the form has passed |
| 209 | validation and returned no :func:`security_errors()`. It |
| 210 | should return an (unsaved) comment object, which will be |
| 211 | annotated with the user and IP address and then saved. |