I would like to create an API for a mobile application. In this application, we can create an account, and of course, edit our profile.
For create an account, I use the django account default model like that:
models.py:
def create_user(self, email, username, phone, deliveryAddress, postalCode, city, password=None):
if not email:
raise ValueError("Users must have an email address")
if not username:
raise ValueError('Users must have an username')
if not phone:
raise ValueError('Users must have a phone number')
if not deliveryAddress:
raise ValueError('Users must have a delivery Address')
if not postalCode:
raise ValueError("Users must have a postal code")
if not city:
raise ValueError('Users must have a city')
user = self.model(
email = self.normalize_email(email),
username = username,
phone = phone,
deliveryAddress = deliveryAddress,
postalCode = postalCode,
city = city,
)
user.set_password(password)
user.save(using = self._db)
return user
def create_superuser(self, email, username, phone, deliveryAddress, postalCode, city, password=None):
user = self.create_user(
email = self.normalize_email(email),
username = username,
password = password,
phone = phone,
deliveryAddress = deliveryAddress,
postalCode = postalCode,
city = city,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using = self._db)
class memberArea(AbstractBaseUser):
username = models.CharField(max_length=255)
email = models.EmailField(max_length=255, unique=True)
phone = models.TextField()
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last login', auto_now=True)
deliveryAddress = models.TextField()
postalCode = models.CharField(max_length=255)
forget = models.TextField(null=True, blank=True)
city = models.CharField(max_length=255)
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 = 'email'
REQUIRED_FIELDS = ['username', 'phone', 'deliveryAddress', 'postalCode', 'city']
objects = MyAccountManager()
def __str__(self):
return self.email + ' : ' + self.username
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
When I create an account, I automaticaly encrypt the user password with set_password()
Now, I want to make a view to edit an account.
Of course I want the password to be encrypted too.
This is my code:
serializer.py:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = memberArea
fields = ['username', 'email', 'phone', 'password', 'deliveryAddress', 'postalCode', 'city']
extra_kwargs = {
'password': {'write_only': True},
}
views.py:
#Edit account
#api_view(['PUT', ])
def edit_account(request, pk):
try:
account = memberArea.objects.get(pk=pk)
except memberArea.DoesNotExist:
return HttpResponse(status=404)
if request.method == 'PUT':
serializer = AccountSerializer(account, data=request.data)
data = {}
if serializer.is_valid():
serializer.save()
data['response'] = 'Account updated with success !'
return Response(data)
return Response(serializer.errors)
I don't know where and how I can encrypt the password before updating the profile.
Maybe I can do that in my serializer file by finding the account that we want to edit but I don't know how to do that in this file...
Thanks by advance for your help
You can do Field-level validation in your serializer to encrypt the raw password to a hashed one.
Here is an example of encrypting the raw password in your AccountSerializer. Then, every raw password from a request's json payload will be encrypted to a hashed one.
from django.contrib.auth.hashers import make_password
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = memberArea
fields = ['username', 'email', 'phone', 'password', 'deliveryAddress', 'postalCode', 'city']
extra_kwargs = {
'password': {'write_only': True},
}
def validate_password(self, raw_password):
return make_password(raw_password)
Related
My authentication doesn't seem to work. I got registration and everything, its just the log in and authenticate aspect that doesnt work. I'm not sure why.
I'm not sure as to why my django auth returns none.
I have this in my settings:
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'UniLinkedApp.auth.MyAuthBackEnd',
)
I have my models as:
class Register(models.Model):
username = models.CharField(max_length = 200)
email = models.EmailField(max_length = 200)
password = models.CharField(max_length = 200)
university = models.CharField(max_length=50)
major = models.CharField(max_length = 200)
def __str__(self):
return self.user
class MyAccountManager(BaseUserManager):
def create_user(self, username, email, password, university, major):
if not email:
raise ValueError("Users must have an email address")
if not username:
raise ValueError("Users must have an username")
user = self.model(
username=username,
email=self.normalize_email(email),
password = password,
university = university,
major = major,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, password):
user = self.create_user(
username=username,
email=self.normalize_email(email),
password=password,
)
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 = 200)
email = models.EmailField(max_length = 200)
password = models.CharField(max_length = 200)
university = models.CharField(max_length=50)
major = models.CharField(max_length = 200)
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'
objects = MyAccountManager()
def __str__(self):
return self.username
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
I have my forms like:
class RegisterForm(forms.ModelForm):
password = forms.CharField(label='Password', widget=forms.PasswordInput)
class Meta:
model = Account
fields = ['username', 'email', 'password', 'university', 'major']
class AccountAuthenticationForm(forms.ModelForm):
password = forms.CharField(label='Password', widget=forms.PasswordInput)
class Meta:
model = Account
fields = ('username', 'email','password', 'university', 'major')
def clean(self):
if self.is_valid():
email = self.cleaned_data['email']
password = self.cleaned_data['password']
if not authenticate(email=email, password=password):
raise forms.ValidationError("Invalid login")
My auth is:
class MyAuthBackEnd(ModelBackend):
def authenticate(self, **kwargs):
username = kwargs['username']
password = kwargs['password']
try:
account = Account.objects.get(username=username)
if account.check_password(password) is True:
return account
except Account.DoesNotExist:
pass
It doesn't matter what authentication method I use, it still returns none despite having correct username and password.
I tried all sorts of things but not sure how to fix it.
This is my login as method:
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user = MyAuthBackEnd.authenticate(request, username=username, password = password)
#print(user)
#print(username, password)
if user is not None:
print('Test')
login(request, username)
return redirect('home')
else:
messages.info(request, 'Username or Password is incorrect')
I'm currently working on a django project and I have a custom user model in my django app. Custom user authentication is working perfectly, but the issue I'm facing is whenever I'm logging into admin account in the django admin site, it logs out the previous user(let say, user2) and admin being logged in.
How Can I separate their login, so that admin site logins don't interfere with my website login?
Here is my code attached:
Custom User model and its manager:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class CustomerManager(BaseUserManager):
def create_user(self, email, username, name, password=None):
if not email:
raise ValueError('Users must have an email address to register')
if not username:
raise ValueError('Users must have an username address to register')
if not name:
raise ValueError('Users must enter their name to register')
user = self.model(
email = self.normalize_email(email),
username = username,
name=name,
)
user.set_password(password)
user.save(using = self._db)
return user
def create_superuser(self, email, username, name, password=None):
user = self.create_user(
email = self.normalize_email(email),
username = username,
name=name,
password=password,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class Customer(AbstractBaseUser):
# user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
email = models.EmailField(max_length=254, null=True, unique=True)
username = models.CharField(max_length=40, unique=True)
name = models.CharField(max_length=200)
phone = models.CharField(max_length=10, null=True)
address = models.CharField(max_length=500, null=True)
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(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 = 'email'
REQUIRED_FIELDS = ['username', 'name']
objects = CustomerManager()
def __str__(self):
return self.name
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
Login View:
def loginUser(request):
if request.user.is_authenticated:
return redirect('home')
else:
if request.method == 'POST':
email = request.POST.get('email')
password = request.POST.get('password')
user = authenticate(request, email=email, password=password)
if user is not None:
login(request, user)
return redirect('home')
else:
messages.info(request, 'Email or Password didn\'t match!')
context = {}
return render(request, 'accounts/login.html', context)
Logout View:
#login_required(login_url='login')
def logoutUser(request):
logout(request)
return redirect('login')
User Profile View:
#login_required(login_url='login')
def userProfile(request, email):
customer = Customer.objects.filter(email=email).first()
context = {'customer':customer}
return render(request, 'accounts/profile.html', context)
CreateUserForm and LoginForm:
class CreateUserForm(UserCreationForm):
class Meta:
model = Customer
fields = ['username', 'email', 'name', 'password1', 'password2']
# fields = '__all__'
class LoginForm(forms.ModelForm):
password = forms.CharField(label='password', widget=forms.PasswordInput)
class Meta:
model = Customer
fields = ['email', 'password']
def clean(self):
email = self.cleaned_data['email']
password = self.cleaned_data['password']
if not authenticate(email=email, password=password):
raise forms.ValidationError('Incorrect Login')
When User3 is logged in and admin is not logged in:
As soon as admin logged in:
User3 automatically logs out and admin logs in..
i have a custom user model that looks like this
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.base_user import BaseUserManager
# user manager code
class MyUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
"""
Creates and saves a User with the given email, first name,
last name and password.
"""
if not email:
raise ValueError("Users must have an email address")
user = self.model(
email=self.normalize_email(email),
**extra_fields,
)
user.set_password(password)
user.save(using=self._db)
return user
# Create your models here.
class CustomUser(AbstractUser):
email = models.EmailField(unique=True)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name']
def __str__(self):
return self.email
my serializer.py
class RegisteSerializer(serializers.Serializer):
password = serializers.CharField(style={"input_type": "password"},
write_only=True)
password2 = serializers.CharField(style={"input_type": "password"},
write_only=True)
email = serializers.EmailField(required=allauth_settings.EMAIL_REQUIRED)
first_name = serializers.CharField(min_length=2, max_length=50)
last_name = serializers.CharField(min_length=2, max_length=50)
USERNAME_FIELD = 'email'
class Meta:
model = User
fields = [
'id',
'first_name',
'last_name',
"email",
"password",
"password2",
]
extra_kwargs = {'password': {'write_only': True}}
def validate_email(self, email):
email = get_adapter().clean_email(email)
if allauth_settings.UNIQUE_EMAIL:
if email and email_address_exists(email):
raise serializers.ValidationError(
("A user is already registered with this e-mail address."))
return email
def validate_password(self, password):
return get_adapter().clean_password(password)
def validate(self, data):
if data['password'] != data['password2']:
raise serializers.ValidationError(
("The two password fields didn't match."))
return data
def get_cleaned_data(self):
return {
'first_name': self.validated_data.get('first_name', ''),
'last_name': self.validated_data.get('last_name', ''),
'password': self.validated_data.get('password', ''),
'password2': self.validated_data.get('password', ''),
'email': self.validated_data.get('email', ''),
}
def save(self, request):
adapter = get_adapter()
user = adapter.new_user(request)
self.cleaned_data = self.get_cleaned_data()
adapter.save_user(request, user, self)
setup_user_email(request, user, [])
user.save()
return user
when i register using endpoint http://127.0.0.1:8000/api/dj-rest-auth/registration/
i am greeted with all fields the way i want it
but when i try to login http://127.0.0.1:8000/api/dj-rest-auth/login/
i still see username
even after configuring my django allauth
# django-allauth configuarations
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_SIGNUP_PASSWORD_ENTER_TWICE = True
i am new to django rest framework i dont want to rewrite everything i dont even know how
I have a wishlist app with a custom user model. I added the user as the foreign key to each wishlist item. However, I am only able to add the foreign key by specifying a default user, even after deleting the existing db files and running makemigrations and migrate. The default user is associated with the wishlist item regardless of which user is logged in, and if I don't include a default user I get the "NOT NULL constraint failed: wishlist_wish.user_id" error.
How can I update the code so that the wishlist item is associated with the logged-in user creating the item?
A related question is whether I need to include a user id in my custom user model? I tried doing this as well and ran into the same problem. Thanks in advance.
Wish Model:
class Wish(models.Model):
name = models.TextField()
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, default=1)
def __str__(self):
return self.name
Wish View:
def add_wish(request):
user = request.user
wishes = Wish.objects.filter(user=request.user)
if request.method == 'POST':
form = WishForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
else:
form = WishForm()
context = {'form' : form, 'wishes' : wishes}
return render(request, 'wishlist/add_wish.html', context)
Wish Form:
class WishForm(ModelForm):
class Meta:
model = Wish
fields = ('name', )
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['name'].widget.attrs.update({'class' : 'textarea', 'placeholder' : 'Enter wishlist item'})
Custom User (Account) Model:
class MyAccountManager(BaseUserManager):
def create_user(self, email, username, first_name, last_name, password=None):
if not email:
raise ValueError("Users must provide an email to create an account.")
if not first_name:
raise ValueError("Users must provide full name to create an account.")
if not last_name:
raise ValueError("Users must provide full name to create an account.")
user = self.model(
email = self.normalize_email(email),
username = username,
first_name = first_name,
last_name = last_name,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, first_name, last_name, password):
user = self.create_user(
email = self.normalize_email(email),
username = username,
first_name = first_name,
last_name = last_name,
password = password
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class Account(AbstractBaseUser):
email = models.EmailField(max_length=100, unique=True)
username = models.CharField(max_length=100, unique=False, blank=True, null=True)
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(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)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'first_name', 'last_name']
objects = MyAccountManager()
def __str__(self):
return self.first_name + " " + self.last_name
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
You simply need to provide a value for the .user for the Wish you are creating:
from django.contrib.auth.decorators import login_required
#login_required
def add_wish(request):
wishes = Wish.objects.filter(user=request.user)
if request.method == 'POST':
form = WishForm(request.POST)
if form.is_valid():
form.instance.user = requst.user
form.save()
return redirect('home')
else:
form = WishForm()
context = {'form' : form, 'wishes' : wishes}
return render(request, 'wishlist/add_wish.html', context)
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
I'm trying to build super user using a custom user model and a custom user manager. I did exactly the same thing than the django doc about the create_superuser method and in my shell, I'm able to create a superuser with an email and a password. But when I try to log in on the django admin page, I have this wierd error :
Please enter the correct email and password for a staff account. Note
that both fields may be case-sensitive.
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
from django.db import models
from multiselectfield import MultiSelectField
class UserManager(BaseUserManager):
#custom create_user method
def create_user(self, email, password=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email = self.normalize_email(email)
)
user.set_password = password
user.save(using=self._db)
return user
#Custom create_super_user method
def create_superuser(self, email, password=None):
user = self.create_user(
email = self.normalize_email(email),
password = password
)
user.admin = True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
#setting up Choices for interest, Must add other fields ...
MATHS = 'mat'
PHYSICS = 'phy'
HISTORY = 'his'
BIOLOGIE = 'bio'
ECONOMICS = 'eco'
POLITICS = 'pol'
MUSIC = 'mus'
ENGLISH = 'eng'
FRENCH = 'fra'
SPANISH = 'spa'
LAW = 'law'
COMPUTER_SCIENCE = 'cs'
COMMUNICATION = 'com'
MARKETING = 'mar'
SPORT = 'spo'
INTERESTS_CHOICES = (
(MATHS, 'Maths'),
(PHYSICS, 'Physics'),
(HISTORY, 'History'),
(BIOLOGIE, 'Biologie'),
(ECONOMICS, 'Economics'),
(POLITICS, 'Politics'),
(MUSIC, 'Music'),
(ENGLISH, 'English'),
(FRENCH, 'French'),
(SPANISH, 'Spanish'),
(LAW, 'Law'),
(COMPUTER_SCIENCE, 'Computer Science'),
(COMMUNICATION, 'Communication'),
(MARKETING, 'Marketing'),
(SPORT, 'Sport')
)
interests = MultiSelectField(
max_length = 2,
choices = INTERESTS_CHOICES
)
#Setting up a Ranking System
RANKING_CHOICES = [
('silver', 'Silver'),
('gold', 'Gold'),
('platinium', 'Platinium'),
('diamond', 'Diamond')
]
email = models.EmailField(
max_length=50,
unique=True
)
username = models.CharField(
max_length=25,
unique=True,
null=True,
blank=True
)
date_joined = models.DateTimeField(auto_now_add=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=70)
birth_date = models.DateField(null=True, blank=True)
reputation = models.PositiveIntegerField(default=0)
active = models.BooleanField(default=True)
rank = models.CharField(choices=RANKING_CHOICES, max_length=1)
staff = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
bio = models.TextField(
max_length=300,
default="",
blank=True
)
objects = UserManager()
#Setting email to be the main source of authentication
USERNAME_FIELD = 'email'
#Super User Only
REQUIRED_FIELDS = ['password']
#def get_absolute_url(self):
#use reverse + nom de l'url de view
def __str__(self):
return self.email
def get_full_name(self):
return f"{self.first_name} {self.last_name}"
def get_short_name(self):
return self.first_name
def get_username(self):
return self.username
def set_user_league(self):
if 15 <= self.reputation < 40:
self.rank = "gold"
elif 40 <= self.reputation < 80:
self.rank = "platinium"
else:
self.rank = "diamond"
You set a password by calling .set_password(..), not assigning a new value:
class UserManager(BaseUserManager):
#custom create_user method
def create_user(self, email, password=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email = self.normalize_email(email)
)
user.set_password(password)
user.save(using=self._db)
return user
The default create_superuser will set is_staff and is_superuser to True as well:
#Custom create_super_user method
def create_superuser(self, email, password=None):
user = self.create_user(
email = self.normalize_email(email),
password = password
)
user.admin = user.is_superuser = user.is_staff = True
user.save(using=self._db)
return user
We need to set the flag is_superuser to True, in order to make user a superuser in system. Please find the below code:
def create_superuser(self, email, password):
"""
create and save superuser
"""
user = self.create_user(
self.normalize_email(email), password=password)
user.is_staff = True
user.is_superuser = True
user.admin = True
user.save(using=self._db)
return user