fcoelho  committed 1863140

docs section about custom user models

  • Participants
  • Parent commits ccd07bb
  • Branches default

Comments (0)

Files changed (6)

File docs/

 import sys, os
+DOCS_PATH = os.path.abspath(os.path.dirname(__file__))
+sys.path.insert(0, DOCS_PATH)
+sys.path.insert(0, os.path.join(DOCS_PATH, os.path.pardir))
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.
 # Add any Sphinx extension module names here, as strings. They can be extensions
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
 extensions = ['sphinx.ext.todo', 'sphinx.ext.coverage', 'signup_ext']
 # Add any paths that contain templates here, relative to this directory.
 # built documents.
 # The short X.Y version.
-version = '0.1'
+from signup import __version__
+version = __version__
 # The full version, including alpha/beta/rc tags.
-release = '0.1'
+release = __version__
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.

File docs/customizing.rst

+Using custom user models
+This app was created to be used with custom user models, which were introduced
+in Django 1.5. While the basic configuration in :ref:`setup` allows you to use
+``django-signup`` with the default user model, some extra configuration is
+needed in order to work with custom user models.
+The custom user model
+Consider the following user model and associated manager:
+.. code-block:: python
+    from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
+    from django.db import models
+    class CustomUserManager(BaseUserManager):
+        def create_user(self, email, password=None):
+            if not email:
+                raise ValueError('missing email')
+            user = self.model(email=email)
+            user.set_password(password)
+            return user
+        def create_superuser(self, email, password):
+            #for this example, nothing special happens here
+            return self.create_user(email, password)
+    class CustomUser(AbstractBaseUser):
+        email = models.EmailField(
+            max_length=254,
+            unique=True,
+            db_index=True
+        )
+        objects = CustomUserManager()
+        USERNAME_FIELD = 'email'
+        def get_short_name(self):
+            return
+        def get_full_name(self):
+            return
+This model has, in practice, two fields: ``email`` and ``password``, the
+latter which is provided by ``AbstractBaseUser``.
+The custom sign up form
+When this user model is installed (see the `docs <dj-custom-user-models>`_),
+it is already available to Django, but ``django-signup`` requires you to
+create a custom version of what Django provides as
+`UserCreationForm <dj-user-creation-form>`_.
+This form should have all the necessary information needed to create a custom
+user model instance through the ``CustomUser.objects.create_user`` method.
+What that really means is:
+* For every field in ``CustomUser.REQUIRED_FIELDS`` plus
+  ``CustomUser.USERNAME_FIELD``, there should be a field of the same name in
+  the sign up form;
+* The only exception is the ``password`` field, which is populated from three
+  possible different sources: ``password``, ``password1``, or ``password2``.
+  This is to accommodate forms which have duplicated fields for password
+  checking (which you should do anyway).
+  When calling ``create_user``, ``django-signup`` will use the first available
+  value from those three options, so make sure that, if you have more than one
+  password field, the values match. Ensure that with a ``clean_*`` method on
+  the form, as shown below.
+  The drawback of this approach is that you have to call your password fields
+  ``password{,1,2}`` instead of, say, ``pw`` or anything else.
+For the user model described above, this form might look like the following:
+.. code-block:: python
+    from django import forms
+    from your_app.models import CustomUser
+    class UserSignUpForm(forms.Form):
+        email = forms.EmailField()
+        password1 = forms.CharField(widget=forms.PasswordInput)
+        password2 = forms.CharField(widget=forms.PasswordInput)
+        def clean_email(self):
+            email = self.cleaned_data['email'].strip()
+            try:
+                CustomUser.objects.get(email__iexact=email)
+                raise forms.ValidationError('email already exists')
+            except CustomUser.DoesNotExist:
+                return email
+        def clean_password2(self):
+            pw1 = self.cleaned_data.get('password1')
+            pw2 = self.cleaned_data.get('password2')
+            if pw1 and pw2 and pw1 == pw2:
+                return pw2
+            raise forms.ValidationError("passwords don't match")
+Note that you should implement whatever logic you need to verify your data
+here. In this case, we're checking for uniqueness of the email field and that
+both passwords match. The email field is also going to be checked when the
+new user is about to be inserted at the database, but by performing our check
+in the form we're able to provide the user with a meaningful message about why
+the signup process didn't go as expected.
+.. _dj-custom-user-models:
+.. _dj-user-creation_form:
+Using the new form
+Next, you have to tell ``django-signup`` that you want to use this specific
+form during the registration process. Suppose that the above form is inside
+the ``your_app/`` file. Then, you have to add the following to your
+project settings:
+.. code-block:: python
+    SIGNUP_FORM_CLASS = 'your_app.forms.UserSignUpForm'

File docs/index.rst

+   customizing
    :maxdepth: 2

File docs/management.rst

 Until now, there is only one management command, documented below.
+.. _clear_expired_signups:

File docs/setup.rst

+.. _setup:

File signup/

-__version__ = '0.1'
+__version__ = '0.2'