1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
|
.. _forms:
.. module:: django_contact_form.forms
Contact form classes
====================
There are two contact-form classes included in django-contact-form;
one provides all the infrastructure for a contact form, and will
usually be the base class for subclasses which want to extend or
modify functionality. The other is a subclass which adds spam
filtering to the contact form.
The ContactForm class
---------------------
.. class:: ContactForm
The base contact form class from which all contact form classes
should inherit.
If you don't need any customization, you can use this form to
provide basic contact-form functionality; it will collect name,
email address and message.
The :class:`~django_contact_form.views.ContactFormView` included
in this application knows how to work with this form and can
handle many types of subclasses as well (see below for a
discussion of the important points), so in many cases it will be
all that you need. If you'd like to use this form or a subclass of
it from one of your own views, here's how:
1. When you instantiate the form, pass the current
:class:`~django.http.HttpRequest` object as the keyword
argument `request`; this is used internally by the base
implementation, and also made available so that subclasses can
add functionality which relies on inspecting the request (such
as spam filtering).
2. To send the message, call the form's :meth:`save` method, which
accepts the keyword argument `fail_silently` and defaults it to
`False`. This argument is passed directly to Django's
:func:`~django.core.mail.send_mail` function, and allows you to
suppress or raise exceptions as needed for debugging. The
:meth:`save` method has no return value.
Other than that, treat it like any other form; validity checks and
validated data are handled normally, through the
:meth:`~django.forms.Form.is_valid` method and the
:attr:`~django.forms.Form.cleaned_data` dictionary.
Under the hood, this form uses a somewhat abstracted interface in
order to make it easier to subclass and add functionality.
The following attributes play a role in determining behavior, and
any of them can be implemented as an attribute or as a method (for
example, if you wish to have :attr:`from_email` be dynamic, you
can implement a method named :meth:`from_email` instead of setting
the attribute :attr:`from_email`).
.. attribute:: from_email
The email address (:class:`str`) to use in the `From:` header
of the message. By default, this is the value of the Django
setting :data:`~django.conf.settings.DEFAULT_FROM_EMAIL`.
.. attribute:: recipient_list
A :class:`list` of recipients for the message. By default, this
is the email addresses specified in the setting
:data:`~django.conf.settings.MANAGERS`.
.. attribute:: subject_template_name
A :class:`str`, the name of the template to use when rendering
the subject line of the message. By default, this is
`django_contact_form/contact_form_subject.txt`.
.. attribute:: template_name
A :class:`str`, the name of the template to use when rendering
the body of the message. By default, this is
`django_contact_form/contact_form.txt`.
And two methods are involved in producing the contents of the
message to send:
.. method:: message
Returns the body of the message to send. By default, this is
accomplished by rendering the template name specified in
:attr:`template_name`.
:rtype: str
.. method:: subject
Returns the subject line of the message to send. By default,
this is accomplished by rendering the template name specified
in :attr:`subject_template_name`.
:rtype: str
.. warning:: **Subject must be a single line**
The subject of an email is sent in a header (named
`Subject:`). Because email uses newlines as a separator between
headers, newlines in the subject can cause it to be interpreted
as multiple headers; this is the `header injection attack
<https://en.wikipedia.org/wiki/Email_injection>`_. To prevent
this, :meth:`subject` will always force the subject to a single
line of text, stripping all newline characters. If you override
:meth:`subject`, be sure to either do this manually, or use
:func:`super` to call the parent implementation.
Finally, the message itself is generated by the following two
methods:
.. method:: get_message_dict
This method loops through :attr:`from_email`,
:attr:`recipient_list`, :meth:`message` and :meth:`subject`,
collecting those parts into a dictionary with keys
corresponding to the arguments to Django's `send_mail`
function, then returns the dictionary. Overriding this allows
essentially unlimited customization of how the message is
generated. Note that for compatibility, implementations which
override this should support callables for the values of
:attr:`from_email` and :attr:`recipient_list`.
:rtype: dict
.. method:: get_message_context
.. warning:: **Renamed method**
Prior to django-contact-form 2.x, this method was named
`get_context()`. It was renamed to `get_message_context()`
in django-contact-form 2.0. See :ref:`the upgrade guide
<renamed-get-context>` for details.
For methods which render portions of the message using
templates (by default, :meth:`message` and :meth:`subject`),
generates the context used by those templates. The default
context will be a :class:`~django.template.RequestContext`
(using the current HTTP request, so user information is
available), plus the contents of the form's
:attr:`~django.forms.Form.cleaned_data` dictionary, and one
additional variable:
`site`
If `django.contrib.sites` is installed, the currently-active
:class:`~django.contrib.sites.models.Site` object. Otherwise,
a :class:`~django.contrib.sites.requests.RequestSite` object
generated from the request.
:rtype: dict
Meanwhile, the following attributes/methods generally should not
be overridden; doing so may interfere with functionality, may not
accomplish what you want, and generally any desired customization
can be accomplished in a more straightforward way through
overriding one of the attributes/methods listed above.
.. attribute:: request
The :class:`~django.http.HttpRequest` object representing the
current request. This is set automatically in `__init__()`, and
is used both to generate a
:class:`~django.template.RequestContext` for the templates and
to allow subclasses to engage in request-specific behavior.
.. method:: save
If the form has data and is valid, will send the email, by
calling :meth:`get_message_dict` and passing the result to
Django's :func:`~django.core.mail.send_mail` function.
Note that subclasses which override `__init__` or :meth:`save`
need to accept `*args` and `**kwargs`, and pass them via
:func:`super`, in order to preserve behavior (each of those
methods accepts at least one additional argument, and this
application expects and requires them to do so).
The Akismet (spam-filtering) contact form class
-----------------------------------------------
.. class:: AkismetContactForm
A subclass of :class:`ContactForm` which adds spam filtering, via
`the Wordpress Akismet spam-detection service
<https://akismet.com/>`_.
Use of this class requires you to provide configuration for the
Akismet web service; you'll need to obtain an Akismet API key, and
you'll need to associate it with the site you'll use the contact
form on. You can do this at <https://akismet.com/>. Once you have,
you can configure in either of two ways:
1. Put your Akismet API key in the Django setting
:data:`~django.conf.settings.AKISMET_API_KEY`, and the URL it's
associated with in the setting
:class:`~django.conf.settings.AKISMET_BLOG_URL`, or
2. Put your Akismet API key in the environment variable
`PYTHON_AKISMET_API_KEY`, and the URL it's associated with in
the environment variable `PYTHON_AKISMET_BLOG_URL`.
You will also need `the Python Akismet module
<http://akismet.readthedocs.io/>`_ to communicate with the Akismet
web service. You can install it by running `pip install akismet`,
or django-contact-form can install it automatically for you if you
run `pip install django-contact-form[akismet]`.
Once you have an Akismet API key and URL configured, and the
`akismet` module installed, you can drop in
:class:`AkismetContactForm` anywhere you would have used
:class:`ContactForm`. A URLconf is provided in django-contact-form,
at `django_contact_form.akismet_urls`, which will correctly
configure :class:`AkismetContactForm` for you.
|