How do i use user_passes_test view specific page? - python

My User Model
SELLER = "SELLER"
CUSTOMER = "CUSTOMER"
USER_TYPE_CHOICES = (
('SELLER' , 'Seller'),
('CUSTOMER' , 'Customer'),
)
class User(AbstractBaseUser,PermissionsMixin):
email = models.EmailField( max_length=255, unique=True)
user_type = models.CharField(max_length=200,choices=USER_TYPE_CHOICES,null=True)
last_login = models.DateTimeField( blank=True, null=True)
is_staff = models.BooleanField( default=False)
is_superuser = models.BooleanField( default=False)
is_active = models.BooleanField( default=True)
date_joined = models.DateTimeField(default=timezone.now)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
ordering = ['email']
def clean(self):
super().clean()
self.email = self.__class__.objects.normalize_email(self.email)
def get_full_name(self):
return self.email
def get_short_name(self):
return self.email
I have two user_types one seller and one customer how i can use user_passes_test decorator to see if the user.user_type is seller so he can see the seller view only seller can see the seller view
def seller_home(request,pk):
try:
seller = Seller.objects.get(id=pk)
except User.DoesNotExist:
raise Http404("Seller Does Not Exisit")
sellerproducts = Product.objects.filter(seller=seller)
totalsellerproducts = sellerproducts.count()
context = {'seller':seller,'sellerproducts':sellerproducts,"totalsellerproducts":totalsellerproducts }
return render(request,"seller_home.html",context)

I think that you can't, because user_passes_test is for authenticated users only, so the seller or customer cannot be sent by URL to the view, because it will be insecure, anyone will be able to test any pk, You must use the authenticated user in request.user to do this, then the decorator will be easy. Something like this:
def seller_check(user):
return user.user_type == User.SELLER
#user_passes_test(seller_check)
def seller_home(request):
pass

Related

Django | set the default value of a model field to be the email of the logged in user

I'm trying to display user specific content in my django website and I am one step away from completing this task. In models.py I need the contact_email field to have its default value to be the email of the logged in user. I've tried many methods of doing this but nothing has worked yet.
models.py
class Account(AbstractUser):
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
name = models.CharField(max_length=45, unique=False)
username = models.CharField(max_length=100, default='')
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)
is_employee = models.BooleanField(default=True, verbose_name='Are you using FilmLink as an employee?')
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name', 'is_employee']
objects = MyAccountManager()
class Meta:
permissions = [
("post_jobs", "Can post jobs"),
]
def __str__(self):
return self.name
def has_perm(self, perm, obj=None):
return True
def has_perms(self, perm):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.is_admin
class Job(models.Model):
company = models.CharField(max_length=40, null=True, verbose_name="Company/Employer")
description = models.TextField(null=True)
role = models.CharField(max_length=25)
area_of_filming = models.CharField(max_length=50, verbose_name="Area Of Filming", default="")
contact_email = models.EmailField(verbose_name='Contact Email', max_length=60, default='')#stuck on setting this default
created = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, on_delete=models.CASCADE)
def __str__(self):
return self.company
views.py
#login_required(login_url='login')
def manage_jobs(request):
if request.user.is_employee:
return redirect('home')
else:
form = JobForm(request.POST)
if form.is_valid():
form.save()
jobs = Job.objects.filter(contact_email = request.user.email)
context = {"form":form, "jobs":jobs}
return render(request, 'employer/manage-jobs.html', context)
forms.py
class JobForm(ModelForm):
class Meta:
model = Job
fields = ('company', 'description', 'role', 'area_of_filming', 'contact_email')
I don't believe you can set a default that way.
What you should do instead is, when creating a Job object and saving it to database, provide the value of contact_email yourself.
You would then be able to later filter the Job entries based on contact_email field.
# Creating a Job object
job = Job()
job.column1 = value
job.contact_email = request.user.email
# In other view, where you need to filter
jobs = Job.objects.filter(contact_email=request.user.email)
A random thought:
if the only reason you want that contact_email field there is to be able to apply the filter to get all Job objects for that particular user, then you can just filter with user field too.
jobs = Job.objects.filter(user=request.user)
context = {"form":form, "jobs":jobs, 'contact_email': request.user.email}
return render(request, 'employer/manage-jobs.html', context)

django-rest-framework - How to create seperate profiles for users based on is_staff

I am working on a job portal project. I am using custom user model
class UserManager(BaseUserManager):
def create_user(self, email, name, password=None, **extra_fields):
if not email:
raise ValueError('Users must have an email address')
if not name:
raise ValueError('Users must have a name')
user = self.model(email=self.normalize_email(email), **extra_fields)
user.set_password(password)
user.name = name
user.save(using=self._db)
return user
def create_staffuser(self, email, password, name):
user = self.create_user(
email,
name,
password=password
)
user.is_staff = True
user.save(using=self._db)
return user
def create_superuser(self, name, email, password):
user = self.create_user(email, name, password=password)
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
And I have 2 separate models one for job seekers and other for employers.
class SeekerProfile(models.Model):
"""Seeker profile for job seekers"""
MALE = 'M'
FEMALE = 'F'
OTHERS = 'O'
GENDER_CHOICES = [
(MALE, 'Male'),
(FEMALE, 'Female'),
(OTHERS, 'Others'),
]
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
date_of_birth = models.DateField()
gender = models.CharField(
max_length=1,
choices=GENDER_CHOICES
)
address = models.TextField()
city = models.CharField(max_length=100)
pincode = models.CharField(max_length=50)
phone_number = models.CharField(
max_length=50, null=False, blank=False, unique=True)
disabled = models.BooleanField(default=False)
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
limit_choices_to={'is_staff': False},
on_delete=models.CASCADE
)
def __str__(self):
return self.first_name+" "+self.last_name
class BusinessStream(models.Model):
"""Business Stream dataset database"""
business_stream_name = models.CharField(max_length=50)
user = models.ForeignKey(settings.AUTH_USER_MODEL, limit_choices_to={
'is_staff': True}, on_delete=models.CASCADE)
class CompanyProfile(models.Model):
"""company profile"""
user = models.OneToOneField(settings.AUTH_USER_MODEL, limit_choices_to={
'is_staff': True}, on_delete=models.CASCADE)
company_name = models.CharField(max_length=100)
profile_description = models.TextField()
business_stream = models.ManyToManyField(
BusinessStream)
established_date = models.DateTimeField()
company_url = models.URLField()
My doubt is how to restrict one user from creating a profile on other type of user based on is_staff field in User model.
I am new to django, please help me.
views.py
class UserProfileViewSet(ModelViewSet):
queryset = SeekerProfile.objects.all()
serializer_class = serializers.ProfileSerializer
authentication_classes = (JWTAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self):
"""Return objects for the current authenticated user only"""
queryset = SeekerProfile.objects.filter(user=self.request.user)
return queryset
def perform_create(self, serializer):
return serializer.save(user=self.request.user)
serializers.py
class ProfileSerializer(serializers.ModelSerializer):
"""Serializer for user Profile"""
class Meta:
model = SeekerProfile
fields = '__all__'
read_only_fields = ('id', 'user')
This allows employer to create seeker profile.
You would have to check the role of the authenticated user in your view and proceed accordingly - s.th. like
class UserProfileViewSet(ModelViewSet):
queryset = SeekerProfile.objects.all()
serializer_class = serializers.ProfileSerializer
authentication_classes = (JWTAuthentication,)
permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self):
"""Return objects for the current authenticated user only"""
queryset = SeekerProfile.objects.filter(user=self.request.user)
return queryset
def perform_create(self, serializer):
# Check here
if self.request.user.is_staff:
# do something if requesting user is staff
else:
# do s.th. else
return serializer.save(user=self.request.user)

Django save many to many relationship on custom many to many model

Trying to set values for a custom many to many model in Django. My User model has a many to many field named as dispatcher_county. I have created a model to handle many to many relationship between user's who are dispatchers and counties named as DispatcherCounty. Check the create method in UserPostSerializer mentioned below to see how I am creating users who are dispatchers and drivers.
Error Received:
AttributeError: 'ManyToManyField' object has no attribute
'_m2m_reverse_name_cache'
requirements:
Django==3.0.8
djangorestframework==3.11.0
mysqlclient==2.0.1
model.py
class User(AbstractBaseUser):
"""
This is a class for user table which overrides functionalities of default django user model.
Attributes:
name (CharField): Name of a user.
email (EmailField): Email address of a user.
mobile (CharField): Phone number of a user.
date_joined (CharField): When a user was added.
last_login (CharField): Last login date time of a user.
is_admin (CharField): If user is a admin or not.
is_active (CharField): If user is active or not.
is_staff (CharField): If user is staff or not.
is_superuser (CharField): If user is a superuser or not.
role (OneToOneField): One to one relationship with role table.
"""
name = models.CharField(max_length=80)
email = models.EmailField(max_length=255, unique=True)
mobile = models.CharField(
validators=[
RegexValidator(
regex=r"^\d{10,14}$",
message="Phone number must be entered in format: '+999999999'. Up to 14 digits allowed.",
)
],
max_length=15,
unique=True,
)
role = models.ForeignKey(Role, on_delete=models.SET_NULL, null=True)
dispatcher_counties = models.ManyToManyField(
"self",
through="DispatcherCounty",
symmetrical=False,
related_name="dispatcher_has_county",
)
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)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
USERNAME_FIELD = "mobile"
REQUIRED_FIELDS = ["email", "name"]
objects = UserManager()
class Meta:
db_table = "users"
def __str__(self):
return self.email + ", " + self.mobile + ", " + self.name
# For checking permissions. to keep it simple all admin have ALL permissons
def has_perm(self, perm, obj=None):
return self.is_admin
# Does this user have permission to view this app? (ALWAYS YES FOR SIMPLICITY)
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)
class DispatcherDriver(models.Model):
dispatcher = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="dispatcher_driver"
)
driver = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="driver_dispatcher"
)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
class Meta:
db_table = "dispatcher_driver"
def __str__(self):
return self.dispatcher.name + ", " + self.driver.name
class DispatcherCounty(models.Model):
dispatcher = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="dispatcher_county"
)
county = models.ForeignKey(
County, on_delete=models.CASCADE, related_name="county_dispatcher"
)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
class Meta:
db_table = "dispatcher_county"
def __str__(self):
return self.dispatcher.name + ", " + self.county.name
serializer.py
class UserPostSerializer(serializers.ModelSerializer):
name = serializers.CharField(required=True, max_length=80)
email = serializers.EmailField(required=True)
mobile = serializers.CharField(required=True, max_length=15,)
role = serializers.CharField(required=True)
dispatcher = serializers.IntegerField(required=False, allow_null=True)
counties = serializers.ListField(
required=False,
child=serializers.IntegerField(),
error_messages={"required": "Counties field is required."},
)
class Meta:
model = User
exclude = ["password"]
def validate(self, data):
# if role is driver
if data["role"].name == "Driver":
# dispatcher is required
if "dispatcher" not in data.keys() or data["dispatcher"] is None:
raise serializers.ValidationError(
"Dispatcher field is required if role is Driver."
)
else:
try:
dispatcher = User.objects.filter_superuser().get(
pk=data["dispatcher"]
)
if dispatcher.role.name != "Dispatcher":
raise serializers.ValidationError("Invalid dispatcher.")
data["dispatcher"] = dispatcher
except User.DoesNotExist:
raise serializers.ValidationError("Dispatcher not found.")
# if role is dispatcher
elif data["role"].name == "Dispatcher":
# counties are required
if (
"counties" not in data.keys()
or data["counties"] is None
or len(data["counties"]) == 0
):
raise serializers.ValidationError(
"Counties field is required if role is Dispatcher. Min 1 county is required."
)
return data
def validate_role(self, value):
role = Role.objects.filter(name=value).exclude(name__iexact="Superuser").first()
if role is None:
raise serializers.ValidationError("Not a valid role.")
return role
def validate_email(self, value):
user = User.objects
if self.instance:
user = user.exclude(pk=self.instance.pk)
if user.filter(email__iexact=value):
raise serializers.ValidationError("User with this email already exists.")
return value
def validate_mobile(self, value):
if validate_phone_number(value) is None:
user = User.objects
if self.instance:
user = user.exclude(pk=self.instance.pk)
if user.filter(mobile__iexact=value):
raise serializers.ValidationError(
"User with this phone number already exists."
)
return value
def create(self, validated_data):
try:
with transaction.atomic():
dispatcher = None
if validated_data["role"].name == "Driver":
dispatcher = validated_data.pop("dispatcher")
counties = None
if validated_data["role"].name == "Dispatcher":
counties = validated_data.pop("counties")
instance = User.objects.create(**validated_data)
if dispatcher is not None:
DispatcherDriver.objects.create(
dispatcher=dispatcher, driver=instance
)
if counties is not None:
counties = County.objects.filter(id__in=counties).all()
if len(counties) == 0:
raise serializers.ValidationError("Invalid counties.")
instance.dispatcher_counties.set(*counties)
return instance
except DatabaseError as database_error:
return None

Can't log in after updating User model details in Django

I have a user model that extended from AbstractBaseUser I've shown that below
class User(AbstractBaseUser,PermissionsMixin):
email = models.EmailField(verbose_name='email', max_length=80, unique=True)
username = models.CharField(max_length=30, unique=True)
first_name = models.CharField(max_length=100,null=True)
last_name = models.CharField(max_length=100,null=True)
phone_no = models.CharField(max_length=12, null=True)
date_joined = models.DateField(
verbose_name='date joined', auto_now_add=True)
last_login = models.DateField(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)
is_teacher = models.BooleanField(default=False)
address = models.CharField(max_length=500, null=True, blank=True)
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
Also, I need to update the User's details by using the view mentioned below
class UpdateUser(RetrieveUpdateAPIView):
permission_classes = (IsAuthenticated,)
serializer_class = UserSerializerAPI
queryset = User.objects.all()
After Changing user model details I can not log in. I'm using rest-auth login URL to log user in. When I try to log in it gives me an error saying
{
"non_field_errors": [
"Unable to log in with provided credentials."
]
}
What is the reason for that
class UpdateUser(RetrieveUpdateAPIView):
permission_classes = (IsAuthenticated,)
serializer_class = UserSerializerAPI
queryset = User.objects.all()
def perform_update(self, serializer):
instance = serializer.save()
instance.set_password(instance.password)
instance.save()
That's how I solved the problem

Dynamic Choices (Those that get updated for new values entered.)

In this project, I got three types of users: ChalkSlateAdmin (this is not a superuser, administrator or staff, etc.), Student and Teacher. All of these can be considered ChalkSlateUser as each have a OneToOne Relationship with the model. ChalkSlateAdmin can be considered an institute and any time someone registers as a ChalkSlateAdmin, there is a new institute as ChalkSlateAdmin has that attribute.
Teachers and Students can join institutes (ChalkSlateAdmin attribute) that are already registered. So, I need to create a form that has choices of institutes that are currently registered.
My question is, how can I define choices that change depending on what institutes (ChalkSlateAdmin attribute) are registered? Before this, I used constant string values for choices like male & female.
models.py,
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.db import models
class MyAccountManager(BaseUserManager):
def create_user(self, username, email, password=None):
if not email:
raise ValueError("Users must have an email address.")
if not username:
raise ValueError("Users must have 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.user_type = 1
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
class ChalkSlateUser(AbstractBaseUser):
# required to include
email = models.EmailField(verbose_name='email', unique=True, max_length=60)
username = models.CharField(max_length=60, unique=True)
date_joined = models.DateField(verbose_name='date joined', auto_now_add=True)
last_login = models.DateField(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)
# new
first_name = models.CharField(max_length=60, verbose_name='first name')
last_name = models.CharField(max_length=60, verbose_name='last name')
has_institute = 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
AUTHORITY = 1
INSTITUTE = 2
STUDENT = 3
TUTOR = 4
USER_TYPE_CHOICES = (
(AUTHORITY, 'Authority (superuser or admin)'),
(INSTITUTE, 'ChalkSlateAdmin'),
(STUDENT, 'Student'),
(TUTOR, 'Tutor'),
)
user_type = models.PositiveSmallIntegerField(choices=USER_TYPE_CHOICES, null=True, blank=True)
# user_type = models.PositiveSmallIntegerField(null=True, blank=True)
# is_admin = models.BooleanField(default=False)
# is_student = models.BooleanField(default=False)
# is_tutor = models.BooleanField(default=False)
class ChalkSlateAdmin(models.Model):
chalkslate_user = models.OneToOneField(ChalkSlateUser, on_delete=models.CASCADE, null=True)
# username_institute = models.CharField(max_length=100, unique=True)
institute_name = models.CharField(verbose_name='institute name', max_length=100, unique=True)
institute_details = models.CharField(verbose_name='institute details', max_length=100)
def __str__(self):
return self.chalkslate_user.email
class Student(models.Model):
chalkslate_user = models.OneToOneField(ChalkSlateUser, on_delete=models.CASCADE)
# username_student = models.CharField(max_length=100, unique=True)
# name = models.CharField(max_length=100)
student_details = models.CharField(verbose_name='student details', max_length=100)
picture = models.ImageField(verbose_name='picture', upload_to='student_pictures')
def __str__(self):
return self.chalkslate_user.email
class Tutor(models.Model):
chalkslate_user = models.OneToOneField(ChalkSlateUser, on_delete=models.CASCADE)
# username_tutor = models.CharField(max_length=100, unique=True)
# name = models.CharField(max_length=100)
tutor_details = models.CharField(verbose_name='tutor details', max_length=100)
picture = models.ImageField(verbose_name='picture', upload_to='tutor_pictures')
def __str__(self):
return self.chalkslate_user.email
# make the ins_tutor and ins_student models
class InsStudent(models.Model):
institute = models.ForeignKey(ChalkSlateAdmin, on_delete=models.CASCADE)
student = models.OneToOneField(Student, on_delete=models.CASCADE)
roll = models.IntegerField()
class_year = models.CharField(max_length=50)
section = models.CharField(max_length=50)
class Meta:
unique_together = ('roll', 'class_year', 'section',)
class InsTutor(models.Model):
institute = models.ForeignKey(ChalkSlateAdmin, on_delete=models.CASCADE)
tutor = models.OneToOneField(Tutor, on_delete=models.CASCADE)
class notice(models.Model):
name=models.CharField(max_length=50,null=False)
mail=models.CharField(max_length=50,null=False)
date=models.DateTimeField(null=False)
content=models.CharField(max_length=200,null=False)
per=models.CharField(max_length=50,default='no')
def __str__(self):
return self.name
For choices option, you can set a method that returns a list with what you want in it.
For instance, for a BankCard model I implemented in one of my projects, I did something similar to what you want to achieve, for the expiration_year. See below :
class BankCard(models.Model):
def _years(year):
return [(year, str(year)) for year in range(year, year + 10)]
expiration_year = models.IntegerField(choices=_years(datetime.datetime.now().year))
Maybe you could do something similar.

Categories