I don't have the standard Django User model to rely on. How would you combine both, AbstractUser and Allauth. Should I build out the views first "SignUpView.as_view" or should I work out how how the path "accounts/" should tie in with allauth?
I was attempting to adapt a functioning e-commerce site by removing/including aspects, one of these adaptations was a Custom User model.
I'm following this tutorial:
It's excellent, just not sure how to accomodate allauth, which must be in this project due to the ease of its social login.
urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('', include('home.urls')),
path('admin/', admin.site.urls),
path('accounts/', include('allauth.urls')),
path('projects/', include('projects.urls')),
# path('profiles/', include('profiles.urls')),
# path('accounts/signup/', users.SignUpView.as_view(), name='signup'),
# path('accounts/signup/volunteer/', volunteers.VolunteerSignUpView.as_view(), name='volunteer_signup'),
# path('accounts/signup/organisation/', organisations.OrganisationsSignUpView.as_view(), name='organisation_signup'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.utils.html import escape, mark_safe
class User(AbstractUser):
is_volunteer = models.BooleanField(default=False)
is_organisation = models.BooleanField(default=False)
class Volunteer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
def __str__(self):
return self.user.username
Here's my settings.py file
settings.py
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.linkedin_oauth2',
'home',
'projects',
'profiles' ,
# Other
'crispy_forms',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'projectSaasy.urls'
CRISPY_TEMPLATE_PACK = 'bootstrap4'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'templates'),
os.path.join(BASE_DIR, 'templates', 'allauth'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
'builtins': [
'crispy_forms.templatetags.crispy_forms_tags',
'crispy_forms.templatetags.crispy_forms_field',
]
},
},
]
AUTHENTICATION_BACKENDS = [
# Needed to login by username in Django admin, regardless of `allauth`
'django.contrib.auth.backends.ModelBackend',
# `allauth` specific authentication methods, such as login by e-mail
'allauth.account.auth_backends.AuthenticationBackend',
]
SITE_ID = 1
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
ACCOUNT_AUTHENTICATION_METHOD = 'username_email'
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
ACCOUNT_SIGNUP_EMAIL_ENTER_TWICE = True
ACCOUNT_USERNAME_MIN_LENGTH = 4
LOGIN_URL = '/accounts/login/'
LOGIN_REDIRECT_URL = '/'
# Social accounts
# This is the most helpful guide:
# https://python.plainenglish.io/why-you-should-let-the-user-to-authenticate-with-social-accounts-df30b0ba4793
SOCIALACCOUNT_PROVIDERS = {
'linkedin': {
'SCOPE': [
'r_basicprofile',
'r_emailaddress'
],
'PROFILE_FIELDS': [
'id',
'first-name',
'last-name',
'email-address',
'picture-url',
'public-profile-url',
]
}
}
# This allows social sign-up to be instantaneous (change back to "True")
SOCIALACCOUNT_AUTO_SIGNUP = True
WSGI_APPLICATION = 'projectSaasy.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
AUTH_USER_MODEL = "profiles.User"
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
Here's the forms.py
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.db import transaction
from profiles.models import Volunteer, User
class VolunteerSignUpForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
@transaction.atomic
def save(self):
user = super().save(commit=False)
user.is_volunteer = True
user.save()
volunteer = Volunteer.objects.create(user=user)
volunteer.interests.add(*self.cleaned_data.get('interests'))
return user
And the views.py
views.py
from django.contrib.auth import login
from django.shortcuts import redirect
from django.views.generic import CreateView
from .forms import VolunteerSignUpForm
from .models import User
class VolunteerSignUpView(CreateView):
model = User
form_class = VolunteerSignUpForm
template_name = 'registration/signup_form.html'