Custom Django Usermodel - python

i just tried to create my own custom Django user model but it fails if i try to create a new user through the frontend:
Request Method: POST Request URL: http://127.0.0.1:8000/signup/ Django
Version: 2.1b1 Exception Type: AttributeError Exception Value:
'Manager' object has no attribute 'get_by_natural_key'
First i created a new Django App "accounts"
then i've added the following to models.py of the accounts app:
from django.db import models
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser
)
#User Model Manager
class UserManager(BaseUserManager):
def create_user(self, username, password=None):
"""
Creates and saves a User with the given username and password.
"""
if not username:
raise ValueError('Error: The User you want to create must have an username, try again')
user = self.model(
user=self.normalize_username(username),
)
user.set_password(password)
user.save(using=self._db)
return user
def create_staffuser(self, username, password):
"""
Creates and saves a staff user with the given username and password.
"""
user = self.create_user(
username,
password=password,
)
user.staff = True
user.save(using=self._db)
return user
def create_superuser(self, username, password):
"""
Creates and saves a superuser with the given username and password.
"""
user = self.create_user(
username,
password=password,
)
user.staff = True
user.admin = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
user = models.CharField(
verbose_name='username',
max_length=30,
unique=True,
)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False) # a admin user; non super-user
admin = models.BooleanField(default=False) # a superuser
# notice the absence of a "Password field", that's built in.
USERNAME_FIELD = 'user'
REQUIRED_FIELDS = [] # Username & Password are required by default.
def get_full_name(self):
# The user is identified by their Username address
return self.user
def get_short_name(self):
# The user is identified by their Username address
return self.user
def __str__(self): # __unicode__ on Python 2
return self.user
def has_perm(self, perm, obj=None):
"""Does the user have a specific permission?"""
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"""Does the user have permissions to view the app `app_label`?"""
# Simplest possible answer: Yes, always
return True
#property
def is_staff(self):
"""Is the user a member of staff?"""
return self.staff
#property
def is_admin(self):
"""Is the user a admin member?"""
return self.admin
#property
def is_active(self):
"""Is the user active?"""
return self.active
model.py of my actual blog app:
from django.db import models
from django.utils import timezone
from smartfields import fields
from smartfields.dependencies import FileDependency
from smartfields.processors import ImageProcessor
# Categorys of Post Model
class Category(models.Model):
title = models.CharField(max_length=255, verbose_name="Title")
description = models.TextField(max_length=1000, null=True, blank=True)
cover = fields.ImageField(upload_to='categorycovers/', blank=True, null=True, dependencies=[
FileDependency(processor=ImageProcessor(
format='JPEG', scale={'max_width': 350, 'max_height': 350}))
])
icon = fields.ImageField(upload_to='categoryicons/', blank=True, null=True, dependencies=[
FileDependency(processor=ImageProcessor(
format='JPEG', scale={'max_width': 16, 'max_height': 16}))
])
class Meta:
verbose_name = "Category"
verbose_name_plural = "Categories"
ordering = ['title']
def __str__(self):
return self.title
#Post Model
class Post(models.Model):
author = models.ForeignKey('accounts.User', on_delete=models.CASCADE)
title = models.CharField(max_length=75)
content = models.TextField(max_length=10000)
tag = models.CharField(max_length=50, blank=True)
category = models.ForeignKey(Category, verbose_name="Category", on_delete=models.CASCADE, null=True)
postattachment = fields.FileField(upload_to='postattachment/%Y/%m/%d/', blank=True ,null=True)
postcover = fields.ImageField(upload_to='postcover/%Y/%m/%d/', null=True, dependencies=[
FileDependency(processor=ImageProcessor(
format='JPEG', scale={'max_width': 200, 'max_height': 200}))
])
created_date = models.DateField(auto_now_add=True)
published_date = models.DateField(blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
class Meta:
ordering = ["-title"]
def __str__(self):
return self.title
#Comment(s) of Post Model
class Comment(models.Model):
author = models.ForeignKey('accounts.User', on_delete=models.CASCADE)
post=models.ForeignKey(Post, on_delete=models.CASCADE)
content = models.TextField()
created_date = models.DateField(default=timezone.now)
published_date = models.DateField(blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.text
After that i jumpt back to settings.py and added the custom user model to my acctual blog application:
AUTH_USER_MODEL = 'accounts.User'
and i also added
INSTALLED_APPS = [
...
'accounts',
...
]
I dont want any email address for my users. i simply and only want them to be authenticated through the username...
Any hints? Thanks :)

Django AbstractBaseUser class has no field username
in your declaration you declare a username field and named it user
but USERNAME_FIELD is username
change your model like this
class User(AbstractBaseUser):
user = models.CharField(
verbose_name='username',
max_length=30,
unique=True,
)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False) # a admin user; non super-user
admin = models.BooleanField(default=False) # a superuser
USERNAME_FIELD = 'user'
REQUIRED_FIELDS = [] # Username & Password are required by default.
...
also you can rename user field in User model to username and problem solved.

In error django.core.exceptions.FieldError: Unknown field(s) (username) specified for User, Django complained about unknown field username in your Custom User model, you don't have username field but you stated USERNAME_FIELD = 'username'.
The simple solution is to rename your user field to username.
If you need that name for some reason (user) you should change username to user in get_full_name and get_short_name and don't forget also in create_user (user = self.model(user =self.normalize_username(username),))
Try:
Reaname all created users to some other name (ex. my_user) because you have tow varibales with the same name (the USERNAME_FIELD and the user created)
from django.db import models
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser
)
#User Model Manager
class UserManager(BaseUserManager):
def create_user(self, user, password=None):
"""
Creates and saves a User with the given username and password.
"""
if not user:
raise ValueError('Error: The User you want to create must have an username, try again')
my_user = self.model(
user=self.normalize_username(user),
)
my_user.set_password(password)
my_user.save(using=self._db)
return my_user
def create_staffuser(self, user, password):
"""
Creates and saves a staff user with the given username and password.
"""
my_user = self.create_user(
user,
password=password,
)
my_user.staff = True
my_user.save(using=self._db)
return my_user
def create_superuser(self, user, password):
"""
Creates and saves a superuser with the given username and password.
"""
my_user = self.create_user(
user,
password=password,
)
my_user.staff = True
my_user.admin = True
my_user.save(using=self._db)
return my_user
class User(AbstractBaseUser):
user = models.CharField(
verbose_name='username',
max_length=30,
unique=True,
)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False) # a admin user; non super-user
admin = models.BooleanField(default=False) # a superuser
# notice the absence of a "Password field", that's built in.
USERNAME_FIELD = 'user'
REQUIRED_FIELDS = [] # Username & Password are required by default.
def get_full_name(self):
# The user is identified by their Username address
return self.user
def get_short_name(self):
# The user is identified by their Username address
return self.user
def __str__(self): # __unicode__ on Python 2
return self.user
def has_perm(self, perm, obj=None):
"""Does the user have a specific permission?"""
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"""Does the user have permissions to view the app `app_label`?"""
# Simplest possible answer: Yes, always
return True
#property
def is_staff(self):
"""Is the user a member of staff?"""
return self.staff
#property
def is_admin(self):
"""Is the user a admin member?"""
return self.admin
#property
def is_active(self):
"""Is the user active?"""
return self.active
Your settings.py file looks great.
I hope this will help.

Related

UndefinedTable: relation "user" does not exist

I am deploying a fresh new Django app on the server. The problem is when I migrate all the apps in the project. I'm getting UndefinedTable: relation "user" does not exist.
Things I have done already:
removed all the migrations from all the apps
created a new database and new migrations and still getting that error.
Weird scenarios:
After deployment when I run the Django app locally on the server and hit API locally on the server using curl everything is working fine. like user sign up, but when I try to see in the database it is just empty (refer to the screenshot below). it doesn't even show columns for this user table, but for other tables, I can see columns as well.
but if I hit API with server endpoint I'm getting 500 error with exception :
relation "user" does not exist
LINE 1: SELECT (1) AS "a" FROM "user" WHERE "user"."email" = '
after migrations I am able to create super user but when I tried to login getting 500 error. and Undefined table relation user does not exit.
Expection:
AUTH_USER_MODEL = 'registration.User'
models.py
from django.db import models
# Create your models here.
import uuid
from django.db import models
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser
from django.utils import timezone
from .managers import CustomUserManager
from rest_framework_simplejwt.tokens import RefreshToken
AUTH_PROVIDERS = {'facebook': 'facebook', 'google': 'google',
'twitter': 'twitter', 'email': 'email'}
# Create your models here.
class User(AbstractBaseUser, PermissionsMixin):
# These fields tie to the roles!
A = 1
I = 2
C = 3
USER_ROLE = (
(A, 'A'),
(I, 'I'),
(C, 'C')
)
# Roles created here
uuid = models.UUIDField(unique=True, editable=False, default=uuid.uuid4)
username = models.CharField(max_length=255, unique=True, db_index=True)
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=50, blank=True)
last_name = models.CharField(max_length=50, blank=True)
role = models.PositiveSmallIntegerField(choices=USER_ROLE, blank=True, null=True)
date_joined = models.DateTimeField(auto_now_add=True)
is_verified = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_deleted = models.BooleanField(default=False)
created_date = models.DateTimeField(default=timezone.now)
modified_date = models.DateTimeField(default=timezone.now)
auth_provider = models.CharField(
max_length=255, blank=False,
null=False, default=AUTH_PROVIDERS.get('email'))
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'role']
objects = CustomUserManager()
class Meta:
db_table = 'user'
verbose_name = 'user'
verbose_name_plural = 'users'
def __str__(self):
return self.email
def save(self, *args, **kwargs):
self.is_staff = True if self.role == self.ADMIN else False
self.is_superuser = True if self.role == self.ADMIN else False
super(User, self).save(*args, **kwargs)
def tokens(self):
refresh = RefreshToken.for_user(self)
return {
'refresh': str(refresh),
'access': str(refresh.access_token)
}
managers.py (CustomUserManager)
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import ugettext_lazy as _
class CustomUserManager(BaseUserManager):
"""
Custom user model where the email address is the unique identifier
and has an is_admin field to allow access to the admin app
"""
def create_user(self, username, email, role, password=None):
if username is None:
raise TypeError('Users should have a username')
if email is None:
raise TypeError('Users should have a Email')
user = self.model(username=username, role=role, email=self.normalize_email(email))
user.set_password(password)
user.save()
return user
def create_superuser(self, username, role, email, password=None):
"""
Creates and saves a superuser with the given email and password.
"""
if password is None:
raise TypeError('Password should not be none')
user = self.create_user(
username,
email,
role,
password=password,
)
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
views.py
renderer_classes = (UserRenderer,)
permission_classes = [AllowAny]
def post(self, request):
user = request.data
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
user_data = serializer.data
user = User.objects.get(email=user_data['email'])
token = RefreshToken.for_user(user).access_token
current_site = get_current_site(request).domain
relativeLink = reverse('email-verify')
absurl = 'http://' + current_site + relativeLink + "?token=" + str(token)
email_body = 'Hi ' + user.username + \
' Use the link below to verify your email \n' + absurl
data = {'email_body': email_body, 'to_email': user.email,
'email_subject': 'Verify your email'}
# Util.send_email(data)
mail.send(
[user.email],
"abc#gmail.com",
subject='Account Verification',
message=email_body,
priority='now',
)
return Response(user_data, status=status.HTTP_201_CREATED)
serializer.py
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(
max_length=68, min_length=6, write_only=True)
role = serializers.IntegerField(write_only=True)
default_error_messages = {
'username': 'The username should only contain alphanumeric characters'}
class Meta:
model = User
fields = ['email', 'username', 'password', 'role']
def validate(self, attrs):
email = attrs.get('email', '')
username = attrs.get('username', '')
role = attrs.get('role', '')
if not username.isalnum():
raise serializers.ValidationError(
self.default_error_messages)
return attrs
def create(self, validated_data):
return User.objects.create_user(**validated_data)
python 3.10
Django 3.2

Unknown field(s) (username) specified for Account. Check fields/fieldsets/exclude attributes of class AccountAdmin

Ive been spending hours on figuring out how to fix this error however I cannot figure it out? I have specified the different fields.
This occurs when im in the admin panel and i try to add a new account - SNI works fine. I dont understand. Am i missing something? I have set the user field too
Model
from asyncio import FastChildWatcher
import email
from pyexpat import model
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class userCouncil(BaseUserManager):
def create_user(self, userID, password=None):
if not email:
raise ValueError("Email is required")
user = self.model(userID = self.normalize_email(userID))
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, userID, password):
user = self.model(userID = self.normalize_email(userID))
user.set_password(password)
user.is_staff = True
user.is_admin = True
user.save(using=self._db)
return user
class sni(models.Model):
SNI = models.CharField(max_length=10, primary_key=True)
# USERNAME_FIELD = 'SNI'
def __str__(self):
return self.SNI
class Account(AbstractBaseUser):
userID = models.EmailField(max_length=80, unique=True)
name = models.CharField(max_length=100)
dateOfBirth = models.DateField(max_length=8, null=True)
homeAddress = models.CharField(max_length=100, null=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
sni = models.OneToOneField(sni, on_delete=models.CASCADE, null=True, blank=True)
USERNAME_FIELD = 'userID'
objects = userCouncil()
def __str__(self):
return self.userID
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
Admin
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import Account, sni
class AccountAdmin(UserAdmin):
ordering = ['userID']
list_display = ('userID', 'is_staff', 'is_admin')
search_fields = ['userID']
readonly_fields = ('id','userID')
filter_horizontal = ()
list_filter = ()
fieldsets = ()
admin.site.register(sni)
admin.site.register(Account, AccountAdmin)

Can't login in admin panel with superuser or with normal users with custom User Model

I created a AbstractUser model in Django which adds some custom fields, but now whenever I create a user (whether by calling User.create_user() or with python manage.py createsuperuser), the user is created fine with a hashed password, but I cannot use the password to login. When I try to login on the admin console, I get "Please enter the correct username and password for a staff account. Note that both fields may be case-sensitive." I cannot for the life of me figure out what is going wrong since in my database, the correct username + a hashed password appear when I create a user.
This is my user Model
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.base_user import BaseUserManager
class AccountManager(BaseUserManager):
use_in_migrations = True
def _create_user(self, username, password, avg_recipe_rating=None, num_ratings_received=0, num_recipes_created=0):
user = self.model(username=username)
user.set_password(password)
user.num_ratings_received=num_ratings_received
user.num_recipes_created=num_recipes_created
user.avg_recipe_rating=avg_recipe_rating
user.save(using=self._db)
return user
def create_user(self,username, password, avg_recipe_rating=None, num_ratings_received=0, num_recipes_created=0):
return self._create_user(username, password, avg_recipe_rating, num_ratings_received, num_recipes_created)
def create_superuser(self,username, password, avg_recipe_rating=None, num_ratings_received=0, num_recipes_created=0):
return self._create_user(username, password, avg_recipe_rating, num_ratings_received, num_recipes_created)
class User(AbstractUser):
user_id = models.AutoField(primary_key=True)
avg_recipe_rating = models.FloatField(blank=True, null=True)
num_ratings_received = models.IntegerField(null=False)
num_recipes_created = models.IntegerField()
last_login = None
groups = None
user_permissions = None
first_name = None
last_name = None
email = None
date_joined = None
objects = AccountManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = []
#property
def is_staff(self):
return True
#property
def is_active(self):
return True
#property
def is_superuser(self):
return True
class Meta:
managed = True
db_table = 'SampleUser'

Django authenticate not returning existent users

My forms.py :
class UserLoginForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(attrs=
{'class':'form-control form-control-lg','placeholder':'Username'}))
password = forms.CharField(widget=forms.PasswordInput(attrs=
{'class':'form-control form-control-lg','placeholder':'Password'}))
def clean(self, *args, **kwargs):
username = self.cleaned_data.get("username")
password = self.cleaned_data.get("password")
if username and password:
user = authenticate(username=username, password=password)
if user is None:
raise forms.ValidationError("This user does not exist")
elif user is not None:
if not user.is_active:
raise forms.ValidationError("This user is not longer
active.")
elif not user.check_password(password):
raise forms.ValidationError("Incorrect password")
return super(UserLoginForm, self).clean(*args, **kwargs)
models.py :
class User(AbstractUser):
is_client = models.BooleanField(default=False)
is_trainer = models.BooleanField(default=False)
username = models.CharField('username', max_length=150, unique=True)
email = models.EmailField(unique=True)
hub = models.ForeignKey(Hub, on_delete=models.CASCADE,blank=True,
null=True)
USER_POSITIONS = ((0, 'Not a member'), (1, 'Member'), (2, 'Excom'),
(3, 'Leader'))
hub_position = models.CharField(default='Not Member',max_length=50)
mentor = models.ForeignKey('self' ,on_delete=models.CASCADE,
blank=True,null=True)
terms = models.BooleanField(blank=True,default=False)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email','terms']
def get_absolute_url(self):
return reverse('student:dashboard', kwargs={'pk': self.pk})
I want the user to be redirected to the resend activation link page if he hasnt activated already .Now after i register the user and skip account activation and then try to login ,it shows validation error "This user does not exist" eventhough this user is registered in the User model .
The problem lies with the version of Django that you're using.
The more recent versions of Django return users for any authentication, only if user.is_active=TRUE
My suggestion to solve this problem would be the use of CustomUserModel for your User.
I use something like this:
class User(AbstractBaseUser):
email = models.EmailField(db_index=True, unique=True, max_length=255)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = UserManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
and add AUTH_USER_MODEL = 'myapp.User' in my settings.py
Basically, go for a CustomUserModel that suits your needs and that should do it.

Use email to login in Django 1.11, I use cookiecutter-django with allauth

I started using cookiecutter-django because it seems so much advanced than just django-admin to start my project. So I created an eCommerce website and it requires only email to log in not the username.
So, I tried to follow the docs and changes my settings.py like this:
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
AUTH_USER_MODEL = 'accounts.User'
LOGIN_REDIRECT_URL = 'users:redirect'
LOGIN_URL = 'account_login'
Here is my accounts.User model:
from django.db import models
from django.contrib.auth.models import (
AbstractBaseUser, BaseUserManager
)
class UserManager(BaseUserManager):
def create_user(self, email, full_name, password=None, is_active=True, is_staff=False, is_admin=False):
if not email:
raise ValueError("Users must have an email address")
if not password:
raise ValueError("Users must have a password")
if not full_name:
raise ValueError("Users must have a fullname")
user_obj = self.model(
email = self.normalize_email(email),
full_name = full_name
)
user_obj.set_password(password)
user_obj.staff = is_staff
user_obj.admin = is_admin
user_obj.active = is_active
user_obj.save(using=self._db)
return user_obj
def create_staffuser(self, email, full_name, password=None):
user = self.create_user(
email,
full_name,
password=password,
is_staff=True
)
return user
def create_superuser(self, email, full_name, password=None):
user = self.create_user(
email,
full_name,
password=password,
is_staff=True,
is_admin=True
)
return user
class User(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True)
full_name = models.CharField(max_length=255, blank=True, null=True)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELD = ['full_name']
objects = UserManager()
def __str__(self):
return self.email
def get_full_name(self):
return self.full_name
def get_short_name(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.staff
#property
def is_admin(self):
return self.admin
#property
def is_active(self):
return self.active
There is default users dir which has its own models.py, views.py and urls.py but I have no knowledge to modify it.
urls.py:
from django.conf.urls import url
from . import views
urlpatterns = [
url(
regex=r'^$',
view=views.UserListView.as_view(),
name='list'
),
url(
regex=r'^~redirect/$',
view=views.UserRedirectView.as_view(),
name='redirect'
),
url(
regex=r'^(?P<username>[\w.#+-]+)/$',
view=views.UserDetailView.as_view(),
name='detail'
),
url(
regex=r'^~update/$',
view=views.UserUpdateView.as_view(),
name='update'
),
]
models.py:
from django.contrib.auth.models import AbstractUser
from django.core.urlresolvers import reverse
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
#python_2_unicode_compatible
class User(AbstractUser):
# First Name and Last Name do not cover name patterns
# around the globe.
name = models.CharField(_('Name of User'), blank=True, max_length=255)
def __str__(self):
return self.username
def get_absolute_url(self):
return reverse('users:detail', kwargs={'username': self.username})
views.py:
from django.core.urlresolvers import reverse
from django.views.generic import DetailView, ListView, RedirectView, UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import User
from enrolments.models import Enrolment
class UserDetailView(LoginRequiredMixin, DetailView):
model = User
# These next two lines tell the view to index lookups by username
slug_field = 'username'
slug_url_kwarg = 'username'
class UserRedirectView(LoginRequiredMixin, RedirectView):
permanent = False
def get_redirect_url(self):
return reverse('users:detail',
kwargs={'username': self.request.user.username})
class UserUpdateView(LoginRequiredMixin, UpdateView):
fields = ['name', ]
# we already imported User in the view code above, remember?
model = User
# send the user back to their own page after a successful update
def get_success_url(self):
return reverse('users:detail',
kwargs={'username': self.request.user.username})
def get_object(self):
# Only get the User record for the user making the request
return User.objects.get(username=self.request.user.username)
class UserListView(LoginRequiredMixin, ListView):
model = User
# These next two lines tell the view to index lookups by username
slug_field = 'username'
slug_url_kwarg = 'username'
Here is the error when I sign in, although it let me sign in when I go to the homepage. but when I click 'Sign In' button it prompts me with this error. Please guide me through it.
Thank you in advance.
As of now (June 2020) there is an easier way to do this with Django Cookie cutter.
Firstly in the Django settings config/settings/base.py we need to adjust the AllAuth settings so that firstly the email is used as the primary identifier and not username, and secondly so that the username field is hidden in the SignUp page
ACCOUNT_AUTHENTICATION_METHOD = "email"
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_EMAIL_VERIFICATION = "mandatory"
The Django AllAuth documentation of this can be found here
Then in the User model, we add a signal that will fire whenever the user instance is updated and copy the email address over to the username field. This way they stay in sync. The while loop just deals with the situation if there are conflicting email addresses (which their should not be):
#receiver(pre_save, sender=User)
def update_username_from_email(sender, instance, **kwargs):
user_email = instance.email
username = user_email[:130]
n = 1
while User.objects.exclude(pk=instance.pk).filter(username=username).exists():
n += 1
username = user_email[: (129 - len(str(n)))] + "-" + str(n)
instance.username = username
This user model update was proposed by #ferrangb here
Finally, I managed to figure out the way.
Here is my new models.py:
from django.db import models
from django.contrib.auth.models import (
AbstractBaseUser, BaseUserManager
)
class UserManager(BaseUserManager):
def create_user(self, email, username, full_name, password=None, is_active=True, is_staff=False, is_admin=False):
if not email:
raise ValueError("Users must have an email address")
if not password:
raise ValueError("Users must have a password")
if not full_name:
raise ValueError("Users must have a fullname")
user_obj = self.model(
email = self.normalize_email(email),
full_name = full_name,
username = new_username
)
user_obj.set_password(password)
user_obj.staff = is_staff
user_obj.admin = is_admin
user_obj.active = is_active
user_obj.save(using=self._db)
return user_obj
def create_staffuser(self, username, email, full_name, password=None):
user = self.create_user(
email,
full_name,
username=username,
password=password,
is_staff=True
)
return user
def create_superuser(self, username, email, full_name, password=None):
user = self.create_user(
email,
full_name,
username=username,
password=password,
is_staff=True,
is_admin=True
)
return user
class User(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True)
full_name = models.CharField(max_length=255, blank=True, null=True)
username = models.CharField(max_length=255, blank=True, null=True)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELD = ['full_name']
objects = UserManager()
def __str__(self):
return self.email
def get_full_name(self):
return self.full_name
def get_short_name(self):
return self.email
def get_username(self):
return self.username
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.staff
#property
def is_admin(self):
return self.admin
#property
def is_active(self):
return self.active
Here is my views.py file in 'users' dir:
from django.core.urlresolvers import reverse
from django.views.generic import DetailView, ListView, RedirectView, UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin
from accounts.models import User
from enrolments.models import Enrolment
class UserDetailView(LoginRequiredMixin, DetailView):
model = User
# These next two lines tell the view to index lookups by username
slug_field = 'username'
slug_url_kwarg = 'username'
class UserRedirectView(LoginRequiredMixin, RedirectView):
permanent = False
def get_redirect_url(self):
return reverse('users:detail',
kwargs={'username': self.request.user.username})
class UserUpdateView(LoginRequiredMixin, UpdateView):
fields = ['full_name', ]
# we already imported User in the view code above, remember?
model = User
# send the user back to their own page after a successful update
def get_success_url(self):
return reverse('users:detail',
kwargs={'username': self.request.user.username})
def get_object(self):
# Only get the User record for the user making the request
return User.objects.get(username=self.request.user.username)
class UserListView(LoginRequiredMixin, ListView):
model = User
# These next two lines tell the view to index lookups by username
slug_field = 'username'
slug_url_kwarg = 'username'
and my settings.py file:
# ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_EMAIL_REQUIRED = True
# ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
AUTH_USER_MODEL = 'accounts.User'
LOGIN_REDIRECT_URL = 'users:redirect'
LOGIN_URL = 'account_login'
Although, I need to have username while signing up only but after that, it just works. I don't need to change any other files.
I hope this helps.
Thanks.

Categories