Django 1.5のカスタムユーザーモデルとdjango-registration その3

以下の続き

Django 1.5のカスタムユーザーモデルとdjango-registration - brainstorm
Django 1.5のカスタムユーザーモデルとdjango-registration その2 - brainstorm


Django 1.5のカスタムユーザーモデルを使っていて、fork版のdjango-registrationでユーザー登録できるだろうか
eire1130 / django-registration ― Bitbucket


登録処理の入り口であるviews.registerを見ると、backendやform_classはカスタマイズ可能になっている

def register(request, backend, success_url=None, form_class=None,
             disallowed_url='registration_disallowed',
             template_name='registration/registration_form.html',
             extra_context=None):

formを指定しないとデフォルトのRegistrationFormが表示されるので、カスタムユーザーモデルがusername、emailを持ってない場合などは自作する必要がある。
今回はemailをusernameとして使ってるのでこんな感じにしてみた。

try:
    from django.contrib.auth import get_user_model
except ImportError:  # django < 1.5
    from django.contrib.auth.models import User
else:
    User = get_user_model()
from django import forms
from django.utils.translation import ugettext_lazy as _

attrs_dict = {'class': 'required'}


class MyRegistrationForm(forms.Form):
    email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,
                                                               maxlength=75)),
                             label=_("E-mail"))
    email_confirm = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,
                                                                       maxlength=75)),
                                     label=_("E-mail(again)"))
    password1 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False),
                                label=_("Password"))
    password2 = forms.CharField(widget=forms.PasswordInput(attrs=attrs_dict, render_value=False),
                                label=_("Password (again)"))

    def clean_email(self):
        existing = User.objects.filter(email__iexact=self.cleaned_data['email'])
        if existing.exists():
            raise forms.ValidationError(_("A user with that email already exists."))
        return self.cleaned_data['email']

    def clean(self):
        print "clean"
        if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
            if self.cleaned_data['password1'] != self.cleaned_data['password2']:
                raise forms.ValidationError(_("The two password fields didn't match."))

        if 'email' in self.cleaned_data and 'email_confirm' in self.cleaned_data:
            if self.cleaned_data['email'] != self.cleaned_data['email_confirm']:
                raise forms.ValidationError(_("The two email fields didn't match."))

        return self.cleaned_data


views.register関数はフォームの入力値がvalidであれば、backendのregister関数を呼び出す

デフォルトで用意されているDefaultBackendのregister関数はこんな感じ

    def register(self, request, **kwargs):
        username, email, password = kwargs['username'], kwargs['email'], kwargs['password1']
        if Site._meta.installed:
            site = Site.objects.get_current()
        else:
            site = RequestSite(request)
        new_user = RegistrationProfile.objects.create_inactive_user(username, email,
                                                                    password, site)
        signals.user_registered.send(sender=self.__class__,
                                     user=new_user,
                                     request=request)
        return new_user

みてみると、フォームからusernameという入力値が渡ってくることが前提になっている。ここはカスタムのバックエンドを作成して修正する必要がある。


さらにRegistrationProfileManagerのcreate_inactive_userもusername、email、passwordを受け取る仕様になっている

create_inactive_userの中身をみると、User(カスタムユーザーモデル)のManagerのcreate_userをを呼び出していて、ここでも引数が固定になっている

    def create_inactive_user(self, username, email, password,
                             site, send_email=True):
        new_user = User.objects.create_user(username, email, password)
        new_user.is_active = False
        new_user.save()

        registration_profile = self.create_profile(new_user)

        if send_email:
            registration_profile.send_activation_email(site)

        return new_user

create_userとcreate_superuserはカスタムユーザーモデルを作成する場合は、自分で定義しなおすことになっているので、ここが固定だと対応できない。


ここまで見てもういいやって感じになってしまったんだけど、今回のようにusernameを持たないカスタムユーザーモデルを使う場合、django-registrationは(fork版でも)使えない。


backendやRegistrationProfileなど部分部分をカスタマイズしまくれば対応できると思うけど、
そこまでするのであれば、最初からregistrationに依存せず、自前でロジック組んだほうがよさそう。