I am fairly new at using Django, so pardon if anything in unclear.
Basically, I have created a custom user model:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class AccountManager(BaseUserManager):
def create_user(self, username, password=None):
if not username:
raise ValueError('A username is required for you to sign up')
user = self.model(
username=username,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, username, password):
user = self.create_user(
password=password,
username=username,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
username = models.CharField(max_length=40, unique=True)
password = models.CharField(max_length=999)
points = 0
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = 'username' # Cannot be included in required fields
REQUIRED_FIELDS = ['password']
objects = AccountManager()
def __str__(self):
return self.username
def has_perm(self, perm, obj=None):
return self.is_admin
#staticmethod
def has_module_perms(app_label):
return True
Under class Account(AbstractBaseUser), I have defined an attribute points. I want to make it such that whenever the user redirects, the user gets some points.
from django.shortcuts import render, redirect
def home_page_view(request):
return render(request, "home_page.html", {})
def free_points(request):
request.user.points += 10
request.user.save()
return render(request, "add_points_test.html", {})
To check whether the points has been added, I changed the code under views a little:
from django.shortcuts import render, redirect
def home_page_view(request):
print(request.user.points)
return render(request, "home_page.html", {})
def add_points_view(request):
request.user.points += 10
request.user.save()
print(request.user.points)
return render(request, "add_points_test.html", {})
From what I have seen, when the user is redirected to add_points_view, the print statement under add_points_view printed out 10. However, when the user is redirected back to home_page_view, the print statement under home_page_view printed out 0 instead of 10. This shows me that points hasn't changed at all.
I'm not sure what I'm supposed to do. Sorry if this question is a bad question, I really can't find anything on the internet.
Thanks in advance.
The core problem is that you didn't define points as a persistent field, so even if you call the save method in add_points_view the information is gonna be lost.
Check https://docs.djangoproject.com/en/3.0/topics/db/models/
Related
I have an API that has a createaccount endpoint. I pass a password when creating the user and the password is passed as string. However, when it is passed to the serializer it comes out as a list, which causes this error: Password must be a string or bytes, got list this error also duplicates itself to my other two attributes, username and account_type as seen below. I have had to do list comprehension by getting the first element of the lists to get the values which I feel is the incorrect way of dealing with this issue.
Here is my models.py for the Account model with its associated Manager:
from django.db import models
import django.contrib.auth.models as auth_models
class AccountManager(auth_models.BaseUserManager):
def create_user(self, username, account_type, password=None):
if not account_type:
raise ValueError("Users must have an account type")
if not username:
raise ValueError("Users must have a username")
requested_account_type = account_type[0]
user = self.model(username=username, account_type=requested_account_type)
user.set_password(password[0])
user.save(using=self._db)
return user
def create(self, username, account_type):
if not account_type:
raise ValueError("Users must have an account type")
if not username:
raise ValueError("Users must have a username")
requested_account_type = account_type[0]
user = self.model(username=username, account_type=requested_account_type)
user.save(using=self._db)
return user
def create_superuser(self, username, password, account_type="jool-admin"):
user = self.create_user(
password=password, username=username, account_type=account_type
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class Account(auth_models.AbstractBaseUser):
username = models.CharField(max_length=40, unique=True, primary_key=True)
ACCOUNT_TYPE_CHOICES = (
("admin", "Admin"),
("manager", "Manager"),
("staff", "Staff"),
)
account_type = models.CharField(
choices=ACCOUNT_TYPE_CHOICES,
default="EMPLOYEE",
blank=False,
null=False,
max_length=10,
)
date_joined = models.DateTimeField(verbose_name="Date Joined", auto_now_add=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = "username"
REQUIRED_FIELDS = ["account_type"]
objects = AccountManager()
Here is the serializer to go with the model:
class AccountSerializer(serializers.ModelSerializer):
def create(self, validated_data):
user = Account.objects.create_user(**validated_data)
return user
class Meta:
model = Account
fields = "__all__"
Here is the view for the endpoint:
class UserRecordView(views.APIView):
"""
API View to create or get a list of all the registered
users. GET request returns the registered users whereas
a POST request allows to create a new user.
"""
permission_classes = [CanViewUserRecord, permissions.IsAuthenticated]
def get(self, format=None):
users = Account.objects.all()
serializer = AccountSerializer(users, many=True)
return response.Response(serializer.data)
def post(self, request):
serializer = AccountSerializer(data=request.data)
if serializer.is_valid(raise_exception=ValueError):
serializer.create(validated_data=request.data)
return response.Response(serializer.data, status=status.HTTP_201_CREATED)
return response.Response(
{
"error": True,
"error_msg": serializer.error_messages,
},
status=status.HTTP_400_BAD_REQUEST,
)
I noticed that the data parameter that calls the serializer is the first instance where all the values are lists:
data=<QueryDict: {'username': ['test2'], 'password': ['test123'], 'account_type': ['admin']}>
This is causing me problems as django saves the values in the list format, so instead of the username being "test2" in the database, it is ['test2'], which causes a lot of errors when calling the API. Any ideas of how I can fix this or what I'm doing wrong. Thank you
I would like to know if it’s possible to create his own login page (from scratch) without using any Django default login forms because I want to add other fields in addition?
Thanks in advance
You could write your own view, but it's better to just subclass the Django LoginView and change as much as you need, for example:
from django.http import HttpResponseRedirect
from django.contrib.auth.views import LoginView
from django.contrib.auth import login
from .forms import MyCustomLoginForm
class SignInView(LoginView):
form_class = MyCustomLoginForm
template_name = 'path/to/my_template.html'
def form_valid(self, form):
# Form is valid, do whatever you need.
login(self.request, form.get_user())
response = HttpResponseRedirect(self.get_success_url())
return response
forms.py
from django import forms
from django.contrib.auth.forms import AuthenticationForm
class MyCustomLoginForm(AuthenticationForm):
age = forms.IntegerField(label='Age', required=True)
def clean_age(self):
age = self.cleaned_data['age']
# validate age
return age
in this user model, I have declared username field as email. User can't get login using username and password. User have to provide email and password to get login.
my models.py
class UserManager(BaseUserManager):
def create_user(self, email, password=None, active=True, is_staff=False, is_admin=False,is_superuser=False):
if not email:
raise ValueError("Users must have an email address")
if not password:
raise ValueError("Users must have password")
user_obj = self.model(
email=self.normalize_email(email)
)
user_obj.set_password(password)
user_obj.staff = is_staff
user_obj.admin = is_admin
user_obj.active = active
user_obj.superuser = is_superuser
user_obj.save(using=self._db)
return user_obj
def create_superuser(self, email, password=None):
user = self.create_user(
email,
password=password,
is_superuser=True,
is_staff=True,
is_admin=True,
)
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True)
staff = models.BooleanField(default=False)
superuser = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
def _str_(self):
return self.email
#property
def is_staff(self):
return self.staff
#property
def is_superuser(self):
return self.superuser
my views.py
from .models import User
class LoginAPIView(APIView):
def post(self, request):
serializer = LoginSerializers(data=request.data)
if serializer.is_valid():
data = serializer.data
email = data['email']
password = data['password']
user = authenticate(email=email, password=password)
if user is not None:
login(request, user)
token, created = Token.objects.get_or_create(user=user)
return Response({"message": "success", "code": status.HTTP_201_CREATED, "details": serializer.data,
"Token": token.key})
return Response(
{"message": "error", "code": status.HTTP_401_UNAUTHORIZED, "details": ["Invalid credentials"]})
my serializers.py:
class LoginSerializers(serializers.Serializer):
username = serializers.CharField(max_length=255)
password = serializers.CharField(max_length=128)
may be this could help you
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.
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.
I'm trying to create a new user in my Django app but nothing happens. I'm using a custom user auth model. Part of the code I edited from the docs. Why the error message "Users must have an email address" is reported by the model and not the forms? Why am I not able to create a user? I don't get any error back.
My model:
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
from django.utils import timezone
class MyUserManager(BaseUserManager):
def create_user(self, email, name, neighborhood, password=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
name=name,
neighborhood=neighborhood
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, name, neighborhood, password):
user = self.create_user(
email=email,
name=name,
password=password,
neighborhood=neighborhood
)
user.is_admin = True
user.save(using=self._db)
return user
class MyUser(AbstractBaseUser):
name = models.CharField(max_length=255)
email = models.EmailField(max_length=255, unique=True)
created_at = models.DateTimeField(default=timezone.now, blank=True)
neighborhood = models.CharField(max_length=255)
consultant_id = models.IntegerField(null=True)
moip_id = models.IntegerField(null=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name', 'neighborhood']
def __str__(self):
return self.name
def get_full_name(self):
return self.name
def get_short_name(self):
return self.name
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
My form:
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from dashboard.models import MyUser
class UserCreationForm(forms.ModelForm):
password = forms.CharField(label='Senha', widget=forms.PasswordInput)
confirm_password = forms.CharField(label='Confirmar senha', widget=forms.PasswordInput)
class Meta:
model = MyUser
# Note - include all *required* MyUser fields here,
# but don't need to include password and confirm_password as they are
# already included since they are defined above.
fields = ('email', 'name', 'neighborhood',)
def clean(self):
cleaned_data = super(UserCreationForm, self).clean()
password = cleaned_data.get('password')
confirm_password = cleaned_data.get('confirm_password')
if password and confirm_password and password != confirm_password:
raise forms.ValidationError('As senhas nao batem.')
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data['password'])
if commit:
user.save()
return user
And my view:
from django.shortcuts import render
from frontend.forms import UserCreationForm
# Create your views here.
def register(request):
message = None
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
return render(request, 'frontend/register.html', {'message': message})
So far I know, you do not raise error from forms, you just -
1) add the error in it, then it automatically gets invalided by django and is posted back with error and also
2) since you are overriding the clean method you must return the cleaned data. So change the clean method with these details -
def clean(self):
cleaned_data = self.cleaned_data
password = cleaned_data.get('password')
confirm_password = cleaned_data.get('confirm_password')
if password and confirm_password and password != confirm_password:
#raise forms.ValidationError('As senhas nao batem.') => we do not raise error in form clean, instead we add it in validation error.
self.add_error('confirm_password', 'As senhas nao batem.')
return super(UserCreationForm, self).clean() # =>this line is IMPORTANT to not break the calling hierarchy
a little shorter -
def clean(self):
if self.cleaned_data['password'] != self.cleaned_data['confirm_password']:
self.add_error('confirm_password', 'Password & Confirm Password must match.')
return super().clean()
Sine you are not returning anything, the cleaned_data of your form is empty and thus django is returning you back to the form page with no data in it.