I'm new in Django rest_framework. I'm using a custom user model and djoser as my authentication system. I want to use my custom user model in the djoser register view and I don't know how to identify that in the rest_framework settings?
settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSIONS_CLASSES':(
'rest_framework.permissions.IsAuthenticated',
),
}
models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class MyAccountManager(BaseUserManager):
def create_user(self, email, username, phone, 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")
user = self.model(
email=self.normalize_email(email),
username=username,
phone=phone
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self,email, username, phone, password):
user = self.create_user(
email=self.normalize_email(email),
username=username,
phone=phone,
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(verbose_name="email",max_length=60, unique=True)
username = models.CharField(max_length=60,unique=True)
phone = models.CharField(max_length=60,unique=True)
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)
first_name = models.CharField(max_length=60,null=True)
last_name = models.CharField(max_length=60,null=True)
wilaya = models.CharField(max_length=60,null=True)
city = models.CharField(max_length=60,null=True)
address = models.CharField(max_length=200,null=True)
store_coordinates = models.CharField(max_length=60,null=True)
documents1 = models.CharField(max_length=60,null=True)
documents2 = models.CharField(max_length=60,null=True)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email','phone']
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
What should I add to use my custom user model in djoser register view?
You're doing almost everything right, but you need to tell Django in the settings what user model it should use.
In models.py use something like this
from django.contrib.auth.models import AbstractUser
from .managers import UserManager
class User(AbstractUser):
# Add whatever fields you want
# Use your custom manager
objects = UserManager()
In settings.py
# Tell Django what user model should be used
AUTH_USER_MODEL = 'auth.User' # app_label.model
make sure you use python manage.py makemigrations && python manage.py migrate to create your custom user model.
Enjoy!
Related
I am trying to access the Id of current logged in User. but i am getting the below error.
models.py of derived model
from django.db import models
from django.urls import reverse, reverse_lazy
from django.utils import timezone
from accounts.models import CustomUser
# Create your models here.
class PostProblem(models.Model):
problem_type_choices = (
('c','Confidential'),
('sc','Semi-confidential'),
('p','Public')
)
problem_category_choices = (
('agriculture','Agriculture'),
('computer_science','Computer Science'),
('social_studies','Social Studies'),
('environment','Environmental Science'),
('mathematics','Mathematics'),
('engineering','Engineering'),
('physics','physics'),
('chemistry','chemistry'),
('other','Other')
)
author = models.ForeignKey("accounts.CustomUser", verbose_name= "Creater", default = CustomUser.get_username ,on_delete=models.CASCADE)
problem_title = models.CharField(max_length=200, verbose_name="Problem's title")
problem_type = models.CharField(choices=problem_type_choices,max_length=5, verbose_name='Confidentiality of the problem ')
problem_category = models.CharField(choices=problem_category_choices, max_length=50, verbose_name="Catrgory of the problem")
problem_brief = models.CharField(max_length=1000, verbose_name='Breif description of the problem ')
problem_description = models.TextField(verbose_name='Problem complete description ')
problem_reward = models.IntegerField(verbose_name='Prize money for providing the solution ')
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
def publish(self):
self.published_date = timezone.now
self.save()
def __str__(self):
return self.problem_title
def get_absolute_url(self):
return reverse("problem_detail", kwargs={"pk": self.pk})
def approve_solutions(self):
return self.solutions.filter(approved_solutions = True)
views.py
from django.shortcuts import render
from django.urls import reverse_lazy
from django.utils import timezone
from django.contrib.auth.mixins import LoginRequiredMixin
from problems.models import PostProblem, Solutions
from problems.forms import PostProblemForm, SolutionsForm
from django.views.generic import TemplateView, CreateView, DetailView, DeleteView, UpdateView, ListView
# Create your views here.
class PostProblemCreateView(CreateView, LoginRequiredMixin):
login_url = 'login/'
redirect_field_name = 'problems/problem_detail.html'
form_class = PostProblemForm
model = PostProblem
forms.py
from django import forms
from problems.models import PostProblem, Solutions
class PostProblemForm(forms.ModelForm):
class Meta:
model = PostProblem
fields = ("problem_title","problem_type","problem_category","problem_brief","problem_description","problem_reward")
widgets = {
'problem_title':forms.TextInput(attrs={'class':'textinputclass'}),
'problem_type': forms.TextInput(attrs={'class':'choice_input'}),
'problem_category':forms.TextInput(attrs={'class':'choice_input'}),
'problem_brief': forms.Textarea(attrs={'class':'editable medium-editor-textarea post_brief'}),
'problem_description': forms.Textarea(attrs={'class':'editable medium-editor-textarea post_complete'}),
'problem_reward': forms.TextInput(attrs={'class':'textinputclass'})
}
model.py of base model
from django.db import models
from django.contrib import auth
from django.urls import reverse
# Create your models here.
# for custom user
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, User
from .managers import CustomUserManager
class CustomUser(AbstractBaseUser, PermissionsMixin):
'''Model representation for user'''
user_type_choices = (
('ps','Problem Solver'),
('pp','Problem Provider')
)
account_type_choices = (
('o','Organization'),
('i','Individual')
)
user_type = models.CharField(max_length=5, choices=user_type_choices, default='pp', verbose_name="Who you are? ")
account_type = models.CharField(max_length=5, choices= account_type_choices, default='o', verbose_name="Account Type ")
email = models.EmailField(max_length=50, unique=True, blank=False, verbose_name="Your Email ")
is_active = models.BooleanField(default=True) # anyone who signs up for thsi application is by default an active user
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False) # the person who has highest level of control over database
# need to specify manager class for this user
objects = CustomUserManager()
# we are not placing password field here because the password field will always be required
REQUIRED_FIELDS = ['user_type', 'account_type']
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
I searched the web for answers but they have mentioned only about accessing current user id in function based views. How can I resolve this kind of error? I am new to Django.
This my models.py file
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
class UserAccountManager(BaseUserManager):
def create_user(self, name, email, password, **other_fields):
if not email:
raise ValueError('Users must have an email adress')
email = self.normalize_email(email)
user = self.model(name=name, email=email, password=password)
user.set_password(password)
user.save()
return user
def create_superuser(self, name, email, password = None, **other_fields):
other_fields.setdefault('is_staff', True)
other_fields.setdefault('is_superuser', True)
other_fields.setdefault('is_active', True)
return self.create_user(name=name, email=email, password = password, is_superuser=True)
class UserAccount(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=355, unique=False)
is_superuser = models.BooleanField(default=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=True)
objects = UserAccountManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
def __str__(self):
return str(self.id)
I have a foreign key on my comment model, I tested this on django admin and it works fine, but with my comment form, the foreign key isn't populating, i just get "null value in column "user_id" violates not-null constraint", I dont know what im doing wrong
class Comment(models.Model):
comment = models.CharField(max_length=250)
user = models.ForeignKey(UserAccount, on_delete=models.CASCADE)
def __str__(self):
return str(self.user.id)
serializers.py
from djoser.serializers import UserCreateSerializer
from django.contrib.auth import get_user_model
from rest_framework.serializers import ModelSerializer
from accounts.models import Comment
User = get_user_model()
class UserCreateSerializer(UserCreateSerializer):
class Meta(UserCreateSerializer.Meta):
model = User
fields = ('id', 'name', 'email', 'password')
I am reffering my foreign key user as a field, i'm not sure if that is correct.
class CommentSerializer(ModelSerializer):
class Meta:
model = Comment
fields=('id', 'comment', 'user')
viewsets.py
from rest_framework import viewsets
from . import models
from . import serializers
class CommentViewset(viewsets.ModelViewSet):
queryset = models.Comment.objects.all()
serializer_class = serializers.CommentSerializer
router.py
from accounts.viewsets import CommentViewset
from rest_framework import routers
router = routers.DefaultRouter()
router.register('comment', CommentViewset)
You need to add user_id field for writing in the serializer.
class CommentSerializer(ModelSerializer):
class Meta:
model = Comment
fields=('id', 'comment', 'user')
extra_kwargs = {
'user': { 'read_only': True }
}
def create(self, validated_data):
new_comment = Comment(**validated_data)
new_comment.user_id = self.context['request'].user.id
new_comment.save()
return new_comment
I am following Django rest_framework tutorial to build my app but and I'm using a custom user model (Account) which inherits AbstractBaseUser.
I have another model - Product - and each product is owned by an Account.
My models.py is:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.conf import settings
class Product(models.Model):
owner = models.ForeignKey(Account, related_name='account', on_delete=models.CASCADE, default=1)
name = models.CharField(max_length=71)
product = models.CharField(max_length=20, blank=True)
price = models.IntegerField(null=True, blank=True)
quantity = models.IntegerField(default=0)
image = models.ImageField(upload_to='images', blank=True)
display = models.BooleanField(default=False)
created = models.DateTimeField('date added', auto_now=True)
modified = models.DateTimeField('date modified', auto_now_add=True)
def __str__(self):
return self.name
class MyAccountManager(BaseUserManager):
def create_user(self, email, username, password=None):
if not email:
raise ValueError("Please enter a valid email address")
if not username:
raise ValueError("Please enter a username")
user = self.model(
email = self.normalize_email(email),
username = username,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, password):
user = self.create_user(
email = self.normalize_email(email),
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):
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last_login', 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)
is_merchant = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = MyAccountManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
My settings.py includes:
AUTH_USER_MODEL = 'accounts.Account'
My serializers.py is:
from rest_framework import serializers
from inventory.models import Product
from accounts.models import Account
class AccountSerializer(serializers.ModelSerializer):
products = serializers.PrimaryKeyRelatedField(many=True, queryset=Product.objects.all())
password2 = serializers.CharField(style={'input_type': 'password'}, write_only=True)
class Meta:
model = Account
fields = ['products', 'email', 'username', 'password', 'password2']
extra_kwargs = {
'password': {'write_only': True}
}
def save(self):
account = Account(
email = self.validated_data['email'],
username = self.validated_data['username'],
)
password = self.validated_data['password']
password2 = self.validated_data['password2']
if password != password2:
raise serializers.ValidationError({'password': 'Passwordss must match.'})
account.set_password(password)
account.save()
return account
class ProductSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.email')
class Meta:
model = Product
fields = [
'id', 'owner', 'name', 'product', 'price', 'quantity', 'image', 'display'
]
My views.py is:
from accounts.api.serializers import AccountSerializer
from inventory.api.serializers import ProductSerializer
from inventory.models import Product
from accounts.models import Account
from rest_framework import permissions
from rest_framework import generics
class AccountList(generics.ListAPIView):
queryset = Account.objects.all()
serializer_class = AccountSerializer
class AccountDetail(generics.RetrieveAPIView):
queryset = Account.objects.all()
serializer_class = AccountSerializer
class ProductList(generics.ListCreateAPIView):
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
queryset = Product.objects.all()
serializer_class = ProductSerializer
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class ProductDetail(generics.RetrieveUpdateDestroyAPIView):
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
queryset = Product.objects.all()
serializer_class = ProductSerializer
I am able to view my ProductList and ProductDetail however, I get the following error when I try to view AccountList and AccountDetail:
**Exception Type:** AttributeError
**Exception Value:** 'Account' object has no attribute 'products'
Just change your serailzier like this
class AccountSerializer(serializers.ModelSerializer):
products = serializers.SerializerMethodField()
password2 = serializers.CharField(style={'input_type': 'password'}, write_only=True)
def get_products(self, instance):
return Product.objects.all().values_list('id', flat=True)
class Meta:
model = Account
fields = ['products', 'email', 'username', 'password', 'password2']
extra_kwargs = {
'password': {'write_only': True}
}
def save(self):
account = Account(
email = self.validated_data['email'],
username = self.validated_data['username'],
)
password = self.validated_data['password']
password2 = self.validated_data['password2']
if password != password2:
raise serializers.ValidationError({'password': 'Passwordss must match.'})
account.set_password(password)
account.save()
return account
PrimaryKeyRelatedField may be used to represent the target of the relationship using its primary key. The queryset used for model instance lookups when validating the field input. Your field is read_only field. Your should use SerializerMethodField for this.
I am trying to grasp Python Django. I'm trying to make a bank system web application. I can register users. These users then are automatically logged in. However, after logout I cannot login the same user again. The page tells me the user does not exist
I have tried to play around with my backends.py in the terminal. when i run
$ user=User.objects.get(pk=1)
$ user
it returns the user with the id in the database. However it doesnt work with the login page. Kindly help, I have been stuck for a week.
models.py:
class UserManager(BaseUserManager):
def create_user(self, account_no, password=None, **extra_fields):
"""
Create and save a user with the given account_no and password.
"""
user = self.model(account_no=account_no, **extra_fields)
user.set_password(password)
user.save(using=self._db)
extra_fields.setdefault('is_staff', False)
extra_fields.setdefault('is_superuser', False)
return user
def create_superuser(self, email, password, **extra_fields):
"""
Creates and saves a superuser with the given email and password.
"""
user = self.create_user(email, password=password, **extra_fields)
user.is_admin = True
user.save(using=self._db)
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('account_no', False)
extra_fields.setdefault('is_superuser', True)
return user
class User(AbstractUser):
username = models.CharField(
('username'), max_length=30, unique=True, null=True, blank=True)
email = models.EmailField(unique=True, blank=True, null=True)
contact_no = models.IntegerField(unique=False, null=True,blank=True)
account_no = models.PositiveIntegerField(
unique=True,
validators=[
MinValueValidator(1000000000),
MaxValueValidator(9999999999)
])
balance = models.DecimalField(
default=0,
max_digits=12,
decimal_places=2
)
GENDER_CHOICE = (
("M", "Male"),
("F", "Female"),
)
gender = models.CharField(max_length=1, choices=GENDER_CHOICE)
birth_date = models.DateField(null=True, blank=True)
city = models.CharField(max_length=256, blank=True, null=True)
postal_code = models.PositiveSmallIntegerField(blank=True, null=True)
country = models.CharField(max_length=256, blank=True, null=True)
picture = models.ImageField(
null=True,
blank=True,
upload_to='account_pictures/',
)
objects = UserManager()
USERNAME_FIELD = 'account_no'
REQUIRED_FIELDS = ['first_name', 'last_name', ]
def __str__(self):
return str(self.full_name)
views.py:
def login_view(request):
if request.user.is_authenticated:
return redirect('home')
else:
form = UserLoginForm(request.POST)
if form.is_valid():
account_no = form.cleaned_data.get('account_no')
password = form.cleaned_data.get('password')
user = authenticate(account_no=account_no, password=password)
login(request, user, backend='accounts.backends.ModelBackend')
messages.success(request, 'Welcome, {}!'.format(user.full_name))
return redirect("home")
context = {"form": form,
"title": "Load Account Details",
}
return render(request, "accounts/login.html", context)
backends.py:
from django.contrib.auth import get_user_model
User = get_user_model()
class ModelBackend(object):
def authenticate(self, request, account_no=None, password=None):
try:
user = User.objects.get(account_no=account_no)
if user and user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
forms.py:
class UserLoginForm(forms.Form):
account_no = forms.IntegerField(label="Account Number")
password = forms.CharField(widget=forms.PasswordInput)
def clean(self, *args, **kwargs):
account_no = self.cleaned_data.get("account_no")
password = self.cleaned_data.get("password")
if account_no and password:
user = authenticate(account_no=account_no, password=password)
if not user:
raise forms.ValidationError("Account Does Not Exist.")
if not user.check_password(password):
raise forms.ValidationError("Password Does not Match.")
if not user.is_active:
raise forms.ValidationError("Account is not Active.")
return super(UserLoginForm, self).clean(*args, **kwargs)
The user that has been registered should be able to login. The program keeps denying registered users from logging in.
I need to add a custom field called phone_number to the default django user table
Everything work fine but the phone_number field and value does not save in Table Django User.
Here is my custom form code
class SignUpForm(UserCreationForm):
username = forms.EmailField(label="Email Address", max_length=254, help_text='Required a valid email address.')
phone_number = forms.CharField(max_length=30, help_text='Required.')
class Meta:
model = User
fields = ('first_name', 'last_name', 'username', 'phone_number', 'password1', 'password2')
Here is my view code for user registration
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.is_active = False
user.save()
current_site = get_current_site(request)
mail_subject = 'Activate Your Account.'
message = render_to_string('app/account_activation_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
'token': account_activation_token.make_token(user),
})
to_email = form.cleaned_data.get('username')
email = EmailMessage(
mail_subject, message, to=[to_email]
)
email.send()
return render(request, 'app/account_confirm_message.html')
else:
form = SignUpForm()
return render(request, 'app/signup.html', {'form': form})
My Model is here
class Profile(models.Model):
STUDENT = 1
TEACHER = 2
ROLE_CHOICES = (
(STUDENT, 'Student'),
(TEACHER, 'Teacher'),
)
user = models.OneToOneField(User, on_delete=models.CASCADE)
email_confirmed = models.BooleanField(default=False)
role = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, null=True, blank=True)
# this method called for admin panel
class Meta:
verbose_name = 'profile'
verbose_name_plural = 'profiles'
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()