fcoelho avatar fcoelho committed 1863140

docs section about custom user models

Comments (0)

Files changed (6)

 
 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.

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)
+            user.save(using=self._db)
+            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 self.email
+        def get_full_name(self):
+            return self.email
+
+This model has, in practice, two fields: ``email`` and ``password``, the
+latter which is provided by ``AbstractBaseUser``.
+
+The custom sign up form
+-----------------------
+
+Requirements
+************
+
+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.
+
+Implementation
+**************
+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: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#substituting-a-custom-user-model
+.. _dj-user-creation_form: https://docs.djangoproject.com/en/dev/topics/auth/default/#django.contrib.auth.forms.UserCreationForm
+
+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/forms.py`` file. Then, you have to add the following to your
+project settings:
+
+.. code-block:: python
+
+    SIGNUP_FORM_CLASS = 'your_app.forms.UserSignUpForm'
+
    setup
    templates
    management
+   customizing
    :maxdepth: 2
 
 

docs/management.rst

 
 Until now, there is only one management command, documented below.
 
+.. _clear_expired_signups:
+
 ``clear_expired_signups``
 -------------------------
 
+.. _setup:
+
 Setup
 =====
 

signup/__init__.py

-__version__ = '0.1'
+__version__ = '0.2'
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.