connect/accounts/forms.py
class UpdatePasswordForm(forms.Form):
    """
    Form for user to update their password
    """
    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super(UpdatePasswordForm, self).__init__(*args, **kwargs)

        self.fields['new_password'] = forms.CharField(
            widget=forms.PasswordInput(attrs={
                'placeholder': _('New Password')
            }),
            error_messages={
                'required': _('Please enter your new password.')
            })

        self.fields['current_password'] = forms.CharField(
            widget=forms.PasswordInput(attrs={
                'placeholder': _('Current Password')
            }),
            error_messages={
                'required': _('Please enter your current password.')
            })

    def clean_current_password(self):
        current_password = self.cleaned_data['current_password']

        if not self.user.check_password(current_password):
            raise forms.ValidationError(
                _('Incorrect password. Please try again.'),
                code='incorrect_pass'
            )
        else:
            pass
connect/accounts/models.py
class UserLink(models.Model):
    """
    Link attached to a user's profile, e.g. github account,
    twitter account, etc.
    """
    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             verbose_name=_('user'),
                             related_name='links')
    anchor = models.CharField(_('anchor text'), max_length=100)
    url = models.URLField(_('url'))
    icon = models.ForeignKey('LinkBrand', blank=True, null=True,
                             on_delete=models.SET_NULL,
                             verbose_name=_('icon'))

    def get_icon(self):
        """
        If there is no icon matched - use default.
        """
        try:
            icon = self.icon.fa_icon
        except AttributeError:
            icon = 'fa-globe'

        return icon

    class Meta:
        verbose_name = _('link')
        verbose_name_plural = _('links')
        unique_together = (('user', 'anchor'), ('user', 'url'))

    def __str__(self):
        return self.anchor

    def save(self, *args, **kwargs):
        """
        Attempt to match a user link to a recognised brand (LinkBrand).
        """
        domain = urlsplit(self.url).netloc

        try:
            self.icon = LinkBrand.objects.get(domain=domain)
        except ObjectDoesNotExist:
            pass

        super(UserLink, self).save(*args, **kwargs)
connect/accounts/models.py
class UserSkill(models.Model):
    """
    How proficient an individual user is at a particular skill.
    This model joins User and Skill ('through' table).
    """
    BEGINNER = 10
    INTERMEDIATE = 20
    ADVANCED = 30
    EXPERT = 40

    PROFICIENCY_CHOICES = (
        ('', '---------'),
        (BEGINNER, _('Beginner')),
        (INTERMEDIATE, _('Intermediate')),
        (ADVANCED, _('Advanced')),
        (EXPERT, _('Expert')),
    )

    user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_("user"))
    skill = models.ForeignKey(Skill, verbose_name=_('skill'))
    proficiency = models.IntegerField(_('proficiency'),
                                      choices=PROFICIENCY_CHOICES,
                                      default=BEGINNER)

    def get_proficiency_percentage(self):
        """
        Return a user's profiency in a particular skill as a percentage,
        based on the position of the proficiency in PROFICIENCY_CHOICES.
        """
        choice_values = [choice[0] for choice in self.PROFICIENCY_CHOICES]
        if '' in choice_values:
            choice_values.remove('')  # Remove the empty proficiency choice
        choice_values.sort()  # Ensure values are in the correct order

        value = choice_values.index(self.proficiency) + 1
        factor = 100 / len(choice_values)
        percentage = round(value * factor)

        return percentage

    class Meta:
        verbose_name = _('user skill')
        verbose_name_plural = _('user skills')
        unique_together = ('user', 'skill')

    def __str__(self):
        return '{} - {}'.format(self.user.get_full_name(), self.skill.name)
connect/accounts/forms.py
class RequestInvitationForm(forms.Form):
    """
    Form for member of the public to request an invitation.
    """
    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)
        super(RequestInvitationForm, self).__init__(*args, **kwargs)

    full_name = forms.CharField(
        max_length=30,
        error_messages={'required': _('Please enter your full name.')}
    )

    email = forms.EmailField(
        error_messages={
            'required': _('Please enter your email address.'),
            'invalid': _('Please enter a valid email address.')
        })

    comments = forms.CharField(
        widget=forms.Textarea(attrs={'placeholder': _('Please explain why you '
                                                      'would like to join '
                                                      'this site')}),
        error_messages={
            'required': _('Please describe why you would like '
                          'to create an account.')
        }
    )

    def clean_email(self):
        """
        Check whether the email is in the system.  If it is registered
        to a closed account, send the user a reactivation link.
        """
        email = self.cleaned_data['email']

        user = get_user(email)
        if user:
            if user.is_closed:
                invite_user_to_reactivate_account(user, request=self.request)
                raise forms.ValidationError(
                    _('This email address is already registered to another '
                      '(closed) account. To reactivate this account, '
                      'please check your email inbox. To register a new '
                      'account, please use a different email address.'),

                    code='email_registered_to_closed_account'
                )

            else:
                raise forms.ValidationError(
                    _('Sorry, this email address is already '
                        'registered to another user.'),

                    code='email_already_registered'
                )

        return email
connect/accounts/forms.py
class UpdateEmailForm(forms.Form):
    """
    Form for user to update their password.
    """
    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super(UpdateEmailForm, self).__init__(*args, **kwargs)

        self.fields['email'] = forms.EmailField(
            initial=self.user.email,
            widget=forms.EmailInput(attrs={
                'placeholder': _('Email')
            }),
            error_messages={
                'required': _('Please enter your new email address.'),
                'invalid': _('Please enter a valid email address.')
            })

        self.fields['password'] = forms.CharField(
            widget=forms.PasswordInput(attrs={
                'placeholder': _('Password')
            }),
            error_messages={
                'required': _('Please enter your password.'),
            })

    def clean_email(self):
        email = self.cleaned_data['email']

        if email != self.user.email:
            validate_email_availability(email)

        return email

    def clean_password(self):
        password = self.cleaned_data['password']

        if not self.user.check_password(password):
            raise forms.ValidationError(
                _('Incorrect password. Please try again.'),
                code='incorrect_pass'
            )
        else:
            pass
connect/accounts/models.py
class Role(models.Model):
    """
    Roles that users can take when connecting with others.
    e.g. Mentor, Mentee, Coding Partner, etc.
    """
    name = models.CharField(_('name'), max_length=100)
    description = models.TextField(_('description'), blank=True)

    class Meta:
        verbose_name = _('role')
        verbose_name_plural = _('roles')

    def __str__(self):
        return self.name
connect/accounts/forms.py
class BaseSkillFormSet(BaseFormSet):
    def clean(self):
        """
        Adds validation to check that no skill is listed twice
        and that all skills have both a name and proficiency.
        """
        if any(self.errors):
            return

        skills = []

        for form in self.forms:
            if form.cleaned_data:
                skill = form.cleaned_data['skill']
                proficiency = form.cleaned_data['proficiency']

                # Check that no two skills are the same
                if skill and proficiency:
                    if skill in skills:
                        raise forms.ValidationError(
                            _('Each skill can only be entered once.'),
                            code='duplicate_skill'
                        )

                    skills.append(skill)

                # Check that all skills have both a name and proficiency
                if skill and not proficiency:

                    raise forms.ValidationError(
                        _('All skills must have a proficiency.'),
                        code='missing_proficiency'
                    )

                elif proficiency and not skill:
                    raise forms.ValidationError(
                        _('All skills must have a skill name.'),
                        code='missing_skill_name'
                    )
connect/accounts/forms.py
class CloseAccountForm(forms.Form):
    """
    Form for user to close their account
    """
    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super(CloseAccountForm, self).__init__(*args, **kwargs)

        self.fields['password'] = forms.CharField(
            widget=forms.PasswordInput(attrs={
                'placeholder': _('Password')
            }),
            error_messages={
                'required': _('Please enter your password.')
            })

    def clean_password(self):
        """
        Adds validation to:
        - Ensure current password matches the user's password.
        """
        password = self.cleaned_data.get('password')

        if not self.user.check_password(password):
            raise forms.ValidationError(
                _('Incorrect password. Please try again.'),
                code='incorrect_pass'
            )
        else:
            pass
connect/accounts/forms.py
class ActivateAccountForm(forms.Form):
    """
    Form for a user to activate their account
    (after clicking on invitation link)
    """
    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super(ActivateAccountForm, self).__init__(*args, **kwargs)

        self.fields['full_name'] = forms.CharField(
            initial=self.user.full_name,
            error_messages={
                'required': _('Please enter your full name.')
            })

    password = forms.CharField(
        widget=forms.PasswordInput,
        error_messages={
            'required': _('Please select a password.')
        })

    confirm_password = forms.CharField(
        widget=forms.PasswordInput,
        error_messages={
            'required': _('Please confirm your password.')
        })

    def clean(self):
        """
        Adds validation to:
        - Ensure password and reset confirm password are the same.
        """
        cleaned_data = super(ActivateAccountForm, self).clean()

        password1 = cleaned_data.get('password')
        password2 = cleaned_data.get('confirm_password')

        if password1 != password2:
            raise forms.ValidationError(_('Your passwords do not match. '
                                          'Please try again.'),
                                        code='unmatched_passwords')

        return cleaned_data
connect/accounts/forms.py
class LinkForm(forms.Form):
    """
    Form for individual user links

    """
    anchor = forms.CharField(max_length=100,
                             widget=forms.TextInput(attrs={
                                 'placeholder': _('Link Name / Anchor Text'),
                             }),
                             required=False)

    url = forms.URLField(
        widget=forms.URLInput(attrs={'placeholder': _('URL')}),
        error_messages={'invalid': _('Please enter a valid URL.')},
        required=False)
connect/accounts/utils.py
def create_inactive_user(email, full_name):
    """
    Create inactive user with basic details.
    Used when moderators invite new users and when a member of the public
    requests an account.
    """
    User = get_user_model()

    user = User.objects.create_user(email)
    user.is_active = False
    user.full_name = full_name
    user.set_unusable_password()

    return user
connect/accounts/view_utils.py
def save_links(request, user, formset):
    """Wrapper function to save paired link anchors and URLs."""
    save_paired_items(request, user, formset, UserLink, 'anchor', 'url')
connect/utils.py
def send_connect_email(subject, template, recipient, site, sender='',
                       url='', comments='', logged_against=''):
    """
    Sends an email to notify users and moderators of relevant events.
    Generates a plain text email from html template counterpart.
    """

    email_header_url = site.config.email_header.url
    email_header = ''.join(['http://', site.domain, email_header_url])

    template_vars = {
        'recipient': recipient,
        'site_name': site.name,
        'url': url,
        'sender': sender,
        'comments': comments,
        'logged_against': logged_against,
        'contact_email':  site.config.email,
        'email_header': email_header,
        # TODO: dynamically retrieve color from CSS
        'link_color': 'e51e41'
    }

    # Render HTML email:
    html_body = render_to_string(template, template_vars)

    # Render plain text email:
    text_body = html_body

    # Strip out HTML head section:
    p = re.compile('<head>(.|\s)*?</head>')
    text_body = p.sub('', text_body)
    # Strip out excessive whitespace:
    text_body = strip_tags(text_body).strip()
    p = re.compile('(\r|\n)(\x20|\t)+')
    text_body = p.sub('\n', text_body)
    p = re.compile('(\r|\n)(\r|\n)+')
    text_body = p.sub('\n\n', text_body)

    email = send_mail(subject=subject,
                      message=text_body,
                      from_email=site.config.email,
                      recipient_list=[recipient.email],
                      html_message=html_body)

    return email
connect/accounts/forms.py
class SkillForm(forms.Form):
    """
    Form for individual user skills
    """
    skills = Skill.objects.all()
    skill = forms.ModelChoiceField(queryset=skills, required=False)

    proficiency = forms.ChoiceField(choices=UserSkill.PROFICIENCY_CHOICES,
                                    required=False)
connect/accounts/view_utils.py
def match_link_to_brand(user_links):
    """
    Attempt to match a user's links to recognised brands (LinkBrand).
    This functionality also exists as a custom save() method on the model.
    -- Use this with functions that create and update in bulk.
    """
    for link in user_links:
        domain = urlsplit(link.url).netloc

        try:
            brand = LinkBrand.objects.get(domain=domain)
            link.icon = brand
            link.save()

        except ObjectDoesNotExist:
            pass

    return user_links
connect/accounts/forms.py
class BaseLinkFormSet(BaseFormSet):
    def clean(self):
        """
        Adds validation to check that no two links have the same anchor or URL
        and that all links have both an anchor and URL.
        """
        if any(self.errors):
            return

        anchors = []
        urls = []
        duplicates = False

        for form in self.forms:
            if form.cleaned_data:
                anchor = form.cleaned_data['anchor']
                url = form.cleaned_data['url']

                # Check that no two links have the same anchor or URL
                if anchor and url:
                    if anchor in anchors:
                        duplicates = True
                    anchors.append(anchor)

                    if url in urls:
                        duplicates = True
                    urls.append(url)

                if duplicates:
                    raise forms.ValidationError(
                        _('Links must have unique anchors and URLs.'),
                        code='duplicate_links'
                    )

                # Check that all links have both an anchor and URL
                if url and not anchor:
                    raise forms.ValidationError(
                        _('All links must have an anchor.'),
                        code='missing_anchor'
                    )
                elif anchor and not url:
                    raise forms.ValidationError(
                        _('All links must have a URL.'),
                        code='missing_URL'
                    )
connect/accounts/view_utils.py
def save_skills(request, user, formset):
    """Wrapper function to save paired skills and proficiencies."""
    save_paired_items(request, user, formset, UserSkill, 'skill',
                      'proficiency')
connect/accounts/forms.py
class ProfileForm(forms.Form):
    """
    Form for user to update their own profile details
    (excluding skills and links which are handled by separate formsets)
    """
    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super(ProfileForm, self).__init__(*args, **kwargs)

        self.fields['full_name'] = forms.CharField(
            max_length=30,
            initial=self.user.full_name,
            widget=forms.TextInput(attrs={
                'placeholder': _('Name'),
            }),
            error_messages={
                'required': _('Please enter your full name.')
            })

        self.fields['bio'] = forms.CharField(
            initial=self.user.bio,
            widget=forms.Textarea(attrs={
                'class': 'bio',
                'placeholder': _('Add some details about yourself...'),
                'rows': 'auto',
            }),
            required=False)

        roles = Role.objects.all()
        self.fields['roles'] = RoleModelMultipleChoiceField(
            initial=self.user.roles.all(),
            queryset=roles,
            widget=forms.CheckboxSelectMultiple(),
            required=False)
connect/accounts/models.py
class Skill(models.Model):
    """
    Represents a skill in the community.
    """
    name = models.CharField(_('name'), max_length=100, unique=True)
    owner = models.ManyToManyField(settings.AUTH_USER_MODEL,
                                   through='UserSkill',
                                   verbose_name=_('owner'))

    class Meta:
        verbose_name = _('skill')
        verbose_name_plural = _('skills')

    def __str__(self):
        return self.name


Question: from django.contrib import messages
from django.contrib.auth import authenticate, get_user_model, login, logout
from django.contrib.auth.decorators import login_required
from django.contrib.auth.hashers import make_password
from django.contrib.sites.shortcuts import get_current_site
from django.core.urlresolvers import reverse
from django.forms.formsets import formset_factory
from django.shortcuts import get_object_or_404, redirect, render
from django.utils.timezone import now
from django.utils.translation import ugettext as _
from connect.utils import send_connect_email
from connect.accounts.forms import (
    ActivateAccountForm, BaseLinkFormSet, BaseSkillFormSet, CloseAccountForm,
    LinkForm, ProfileForm, RequestInvitationForm, SkillForm, UpdateEmailForm,
    UpdatePasswordForm
)
from connect.accounts.models import Role, Skill, UserLink, UserSkill
from connect.accounts.utils import create_inactive_user
from connect.accounts.view_utils import (
    match_link_to_brand, save_links, save_skills
)





User = get_user_model()


def request_invitation(request):
    """
    Allow a member of the public to request an account invitation.
    """
    site = get_current_site(request)

    if request.method == 'POST':
        form = RequestInvitationForm(request.POST, request=request)

        if form.is_valid():

            # Create inactive user
            full_name = form.cleaned_data['full_name']
            email = form.cleaned_data['email']

Answer:             new_user = create_inactive_user(email, full_name)