Last active
July 15, 2019 10:08
-
-
Save squio/1e5fe410d42622d4a54712daba4dfb77 to your computer and use it in GitHub Desktop.
Add hooks to update Allauth email for a user from the Django contrib.auth panel without altering the contrib.auth.models.User model in any way
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" App administration """ | |
from django import forms | |
from django.contrib import admin | |
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin | |
from django.contrib.auth.models import User | |
from django.contrib.auth.forms import UserCreationForm, UserChangeForm | |
from django.contrib.auth.decorators import login_required | |
from django.utils.translation import gettext_lazy as _ | |
from allauth.account.models import EmailAddress | |
from myapp.models.user import Profile | |
from myapp.forms import ProfileForm | |
# Require Allauth login: | |
# https://django-allauth.readthedocs.io/en/latest/advanced.html#admin | |
admin.site.login = login_required(admin.site.login) | |
class AllEmailField(forms.EmailField): | |
""" Extend email validation to check Allauth tables as well """ | |
def validate(self, value): | |
super().validate(value) | |
exists = EmailAddress.objects.filter(email=value).count() | |
if exists > 0: | |
raise forms.ValidationError(_("E-mail address is already in use"), 'invalid') | |
class CustomUserCreationForm(UserCreationForm): | |
""" User Creation with additional model fields """ | |
# add fields which are not part of Django default admin | |
# Custom email validator validates email uniqueness, also with allauth table | |
email = AllEmailField(widget=forms.EmailInput(), required=False) | |
first_name = forms.CharField(required=False) | |
last_name = forms.CharField(required=False) | |
class Meta(UserCreationForm): | |
model = User | |
fields = '__all__' | |
class CustomUserChangeForm(UserChangeForm): | |
""" User Edit with additional model fields """ | |
# Custom email validator validates email uniqueness, also with allauth table | |
email = AllEmailField(widget=forms.EmailInput(), required=False) | |
class Meta(UserCreationForm): | |
model = User | |
fields = '__all__' | |
# Define an inline admin descriptor for Profile model | |
# which acts a bit like a singleton | |
class ProfileInline(admin.StackedInline): | |
""" User Profile form """ | |
model = Profile | |
form = ProfileAdminForm | |
can_delete = False | |
class UserAdmin(BaseUserAdmin): | |
""" Extend User Admin """ | |
# Override user creation form | |
# add fields which are not part of Django default admin | |
add_form = CustomUserCreationForm | |
add_fieldsets = BaseUserAdmin.add_fieldsets + ( | |
(None, {'fields': ('email', 'first_name', 'last_name')}), | |
) | |
# override Edit / change form | |
form = CustomUserChangeForm | |
# Add profile inline | |
inlines = (ProfileInline, ) | |
list_per_page = 20 | |
def save_model(self, request, obj, form, change): | |
# Keep email address updated with Allauth | |
# only if email field has changed: | |
if not 'email' in form.changed_data: | |
# go ahead with original save action | |
super().save_model(request, obj, form, change) | |
else: | |
# first: check if email already exists in Django Allauth | |
exists = EmailAddress.objects.filter(email=obj.email).count() > 0 | |
# Is it one of our own addresses? | |
is_own = obj.pk and EmailAddress.objects.filter(user=obj, email=obj.email).count() > 0 | |
if exists: | |
if is_own: | |
# go ahead and make this our primary email address | |
super().save_model(request, obj, form, change) | |
email = EmailAddress.objects.filter(user=obj, email=obj.email).get() | |
email.primary = True | |
email.save() | |
return | |
else: | |
# this should already have been handled by validation in CustomUserChangeForm | |
raise forms.ValidationError(_("E-mail address is already in use by another account"), 'invalid') | |
# If we have an existing user object | |
if obj.pk: | |
# obj has the changed email address | |
# so get original value from DB, if it exists | |
orig_email = User.objects.get(pk=obj.pk).email | |
try: | |
# only if email was set previously (orig_email) | |
exists = EmailAddress.objects.filter(user=obj, email=orig_email).get() | |
# update existing email address from user | |
exists.primary = True | |
exists.change(request, obj.email, confirm=False) | |
except EmailAddress.DoesNotExist: | |
# we should create a new Email Address after the User has been saved | |
exists = False | |
else: | |
exists = False | |
super().save_model(request, obj, form, change) | |
# email was not set before in Allauth | |
# add it as primary email to allauth table | |
if not exists: | |
email = EmailAddress.objects.create(user=obj, email=obj.email, primary=True) | |
# Re-register UserAdmin | |
admin.site.unregister(User) | |
admin.site.register(User, UserAdmin) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment