I have a User model
class User(AbstractBaseUser):
username = None
first_name = models.CharField(max_length=100, null=True, blank=True)
last_name = models.CharField(max_length=200, null=True, blank=True)
phone_regex = RegexValidator(regex=r'^09(\d{9})$',
message="Phone number must be entered in the format: '09111111111'")
phone = models.CharField(validators=[phone_regex], max_length=11, unique=True)
email = models.EmailField(max_length=255, null=True, blank=True)
# cart_number = models.PositiveBigIntegerField(null=True, blank=True) # shomare cart banki
birth_day = models.DateField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'phone'
REQUIRED_FIELDS = []
def __str__(self):
return self.phone
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.is_admin
in view I want to have a class to get a User and update it
class UserRetrieveUpdateView(generics.RetrieveUpdateAPIView):
queryset = User.objects.filter(is_active=True)
serializer_class = UserSerializer
permission_classes = (IsOwner,)
when I want to test it with post man I give this error:
AttributeError at /account/1/
'User' object has no attribute 'user'
this is my url:
path('<int:pk>/', views.UserRetrieveUpdateView.as_view(), name='dashboard'),
You can not use IsOwner as permission_classes, since that will look for a .user attribute. You can implement a custom user model that will only allow to retrieve the logged in user:
from rest_framework import permissions
class IsThatUserPermission(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return request.user == obj
and then use that IsThatUserPermission:
class UserRetrieveUpdateView(generics.RetrieveUpdateAPIView):
queryset = User.objects.filter(is_active=True)
serializer_class = UserSerializer
permission_classes = (IsThatUserPermission,)
Related
I am trying to get a list of all pathologists in my system. I need to filter the user on 2 basis i-e is_pathologist and Lab_Id=request.data[email]
I have tried switching between filter and get but then I get
Authentication.models.User.MultipleObjectsReturned: get() returned more than one User -- it returned 12!
Error traceback here
This is the code of my view
#api_view(['POST'])
def getAllPathologists(request):
user = get_user_model().objects.get(is_pathologist=True)
# If user exists, get the employee
print("user is: ", user)
pathologist = Employee.objects.get(user=user.email, Lab_Id=request.data['email'])
pathologistSerializer = EmployeeSerializer(pathologist, many=True)
return Response(pathologistSerializer.data)
This is user model
class User(AbstractUser):
# Add additional fields here
id = None
email = models.EmailField(max_length=254, primary_key=True)
name = models.CharField(max_length=100)
password = models.CharField(max_length=100)
contact_number = models.CharField(max_length=100)
is_patient = models.BooleanField(default=False)
is_doctor = models.BooleanField(default=False)
is_homesampler = models.BooleanField(default=False)
is_pathologist = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_lab = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now=True,editable=False)
last_login = models.DateTimeField(auto_now=True)
first_name = None
last_name = None
username = None
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name', 'password']
objects = CustomUserManager()
def __str__(self):
return self.email
# Ensure that the password is hashed before saving it to the database
def save(self, *args, **kwargs):
self.password = make_password(self.password)
super(User, self).save(*args, **kwargs)
def has_perm(self, perm, obj=None):
return self.is_superuser
This is Employee model
class Employee(models.Model):
user = models.OneToOneField(
get_user_model(), on_delete=models.CASCADE, primary_key=True)
CNIC = models.CharField(max_length=100, unique=True)
Lab_Id = models.ForeignKey(Lab, on_delete=models.CASCADE)
def __str__(self):
return self.user.name
This is employee serializer
class EmployeeSerializer(serializers.ModelSerializer):
userData = UserSerializer(read_only=True, source='user')
email = serializers.EmailField(write_only=True)
password = serializers.CharField(write_only=True)
name = serializers.CharField(write_only=True)
contact_number = serializers.CharField(write_only=True)
is_homesampler = serializers.BooleanField(write_only=True)
class Meta:
model = Employee
# fields = " __all__"
fields = ["CNIC", "Lab_Id", "userData",
"name", "contact_number", "email", "password", "is_homesampler"]
def create(self, validated_data):
print("validated data = ", validated_data)
email = validated_data.pop("email")
password = validated_data.pop("password")
name = validated_data.pop("name")
contact_number = validated_data.pop("contact_number")
is_homesampler = validated_data.pop("is_homesampler")
user = get_user_model().objects.create_user(
email=email, password=password, name=name, contact_number=contact_number)
if (is_homesampler):
user.is_homesampler = True
else:
user.is_pathologist = True
user.save()
EmployeeObj = Employee.objects.create(user=user, **validated_data)
return EmployeeObj
You are getting objects and querysets conflated, filter() will return a queryset whereas get() tries to return an object. Below are the reasons for your errors:
The reason for your error with filter() is that a queryset is essentially a group of user objects. The queryset itself has no attribute email, but each user object within the group would. You therefore need to extract a single user from the queryset using first() or last(), for example.
Your error with get() is that your parameters are too broad and thus 12 users are returned. You need to adjust your code to handle this, it's usually done with either a try/except block or using the get_object_or_404 Django shortcut. Once you successfully get the user object, you can call user.email without issue.
I am trying to customize get_queryset() in my DocumentViewSet so the GET method will return all Document objects created by request.user (currently logged in user).
However, I am stuck in this error:django.core.exceptions.ValidationError: ['“AnonymousUser” is not a valid UUID.']
I assume this is caused by getting AnonymousUser as my self.request.user. The weird part is that my other APIView that deals with request.user are working flawlessly; The only difference I could find between the two is type of viewset: ModelViewSet vs APIView.
Would appreciate any help!
document.views
class DocumentViewSet(viewsets.ModelViewSet):
model = Document
serializer_class = DocumentSerializer
list_serializer_class = DocumentListSerializer
permission_classes = (AllowAny,)
def get_queryset(self):
user = self.request.user
return Document.objects.filter(user=user)
def get_serializer_class(self):
if self.action == "list":
if hasattr(self, "list_serializer_class"):
return self.list_serializer_class
return super(DocumentViewSet, self).get_serializer_class()
def perform_create(self, serializer):
print(self.request.user)
serializer.save(user=self.request.user)
document.serializers
class DocumentSerializer(serializers.ModelSerializer):
id = HashidSerializerCharField(source_field="documents.Document.id", read_only=True)
question_blocks = QuestionBlockSerializer(many=True)
outline_blocks = OutlineBlockSerializer(many=True)
source_cards = SourceSerializer(many=True, required=False)
user = serializers.PrimaryKeyRelatedField(
read_only=True, default=serializers.CurrentUserDefault()
)
class Meta:
model = Document
fields = "__all__"
def create(self, validated_data):
question_blocks = validated_data.pop("question_blocks")
outline_blocks = validated_data.pop("outline_blocks")
source_cards = validated_data.pop("source_cards")
document = Document.objects.create(**validated_data)
for qBlock in question_blocks:
QuestionBlock.objects.create(document=document, **qBlock)
for oBlock in outline_blocks:
OutlineBlock.objects.create(document=document, **oBlock)
for sCard in source_cards:
Source.objects.create(document=document, **sCard)
document.save()
return document
class DocumentListSerializer(serializers.ModelSerializer):
id = HashidSerializerCharField(source_field="documents.Document.id", read_only=True)
class Meta:
model = Document
fields = ("id", "title", "template", "updated")
document.models
class Document(models.Model):
id = HashidAutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
title = models.CharField(max_length=100, default="Untitled")
template = models.CharField(max_length=100, default="")
editorState = models.JSONField(default=[])
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
user.models
class User(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
username = None
first_name = models.CharField(max_length=100, default="unknown")
last_name = models.CharField(max_length=100, default="unknown")
profile_pic = models.CharField(max_length=200, default="unknown")
email = models.EmailField(unique=True, db_index=True)
secret_key = models.CharField(max_length=255, default=get_random_secret_key)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
class Meta:
swappable = "AUTH_USER_MODEL"
users.api & selectors
This is the APIView which returns information of the user currently logged-in; It is working flawlessly.
# users.api
class UserMeApi(APIView):
def get(self, request, *args, **kwargs):
return Response(user_get_me(user=request.user))
# users.selectors
def user_get_me(*, user: User):
return {
"id": user.id,
"name": user.name,
"email": user.email,
"first_name": user.first_name,
"last_name": user.last_name,
"profile_pic": user.profile_pic,
}
EDIT: added document.serializer and rest of the viewset code
My mistake! The origin of the problem was on the frontend; I forgot to include withCredentials:true in axios GET request.
axios
.get<DocumentList>(
`${process.env.NEXT_PUBLIC_API_URL}/drafts/?format=json`,
{
withCredentials: true, //forgot this part!
}
)
.then(function (response) {
setDrafts(response.data.results);
});
I want to check that the card number is exists and then get the associated user to that card number. A user can have multiple card numbers. How do I filter to get the user from the card number entered?
Models:
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(
verbose_name="Email Field", max_length=60, unique=True)
dateJoined = 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_superuser = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_verified = models.BooleanField(default=False)
# Parameters that we want to know about the user
first_name = models.CharField(verbose_name="First Name", max_length=100)
last_name = models.CharField(verbose_name="Lasst Name", max_length=100)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name']
objects = CustomUserManager()
def __str__(self):
return self.email
def tokens(self):
refresh = RefreshToken.for_user(self)
return {
'refresh': str(refresh),
'access': str(refresh.access_token)
}
def has_perm(self, perm, obj=None):
return self.is_superuser
def has_module_pers(self, app_label):
return True
class cardModel(models.Model):
user = models.ForeignKey(CustomUser, related_name='card_numbers',null = True, blank=True, on_delete=models.CASCADE)
card_number = models.IntegerField(
verbose_name="Card Number", blank=True, null=True, default=None, unique=True)
def __int__(self):
return self.card_number
Serializer:
class CheckCard(serializers.Serializer):
card_number = serializers.IntegerField(write_only=True)
class Meta:
fields = ['card_number','user']
read_only_fields = ['user']
Views:
class CheckCardAPI(APIView):
permission_classes = [AllowAny]
serializer_class = CheckCard
def post(self,request,*args,**kwargs):
serializer = self.serializer_class(data=request.data)
card_number = request.data.get('card_number','')
if cardModel.objects.filter(card_number=card_number).exists():
user = User.objects.filter(card_numbers=card_number)
tokens, created = Token.objects.get_or_create(user=user)
return Response({'token':tokens.key},status=status.HTTP_200_OK)
else:
return Response({'error':'card is not registered'},status=status.HTTP_404_NOT_FOUND)
You are looking for a single user based on card number, so your query
user = User.objects.filter(card_numbers=card_number)
returns a list. Maybe you would need to use
user = User.objects.get(card_numbers=card_number)
to get an object or use
value_list(id, flat=True)
with filter.
I'm trying to get all users who are employers.
So what I did was I filter the users where the id can be found in the "employer" field of any (other) user.
However this gives me the following error:
TypeError: int() argument must be a string, a bytes-like object or a number, not 'builtin_function_or_method'
View:
# Get all employers
class Employers(viewsets.ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = CustomUserSerializer
def list(self, request):
#queryset = CustomUser.objects.all();
queryset = self.queryset.filter(id__in=CustomUser.objects.filter(employer=id)) #this gives me an error
serializer = CustomUserSerializer(queryset, many=True)
return Response(serializer.data)
Model (standard stuff):
# CustomUser model
class CustomUser(AbstractBaseUser):
username = None
email = models.EmailField(verbose_name='email address', max_length=255, 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)
employer = models.ForeignKey("self", blank=True, null=True, on_delete=models.DO_NOTHING)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = MyUserManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(selfself, app_label):
return True;
I'm not sure what I'm doing wrong. Any suggestions?
You can filter with an F-expression [Django-doc] to refer to another column:
from django.db.models import F
class Employers(viewsets.ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = CustomUserSerializer
def get_queryset(self, *args, **kwargs):
return CustomUser.objects.filter(employer=F('pk'))
This thus makes a query that looks like;
SELECT customuser.*
FROM customuser
WHERE customuser.employer = customuser.id
or you can filter the relation in reverse to get CustomUsers that employ at least one person:
class Employers(viewsets.ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = CustomUserSerializer
def get_queryset(self, *args, **kwargs):
return CustomUser.objects.filter(customuser__isnull=False).distinct()
This constructs a query that looks like:
SELECT DISTINCT customuser.*
FROM customuser
JOIN customuser u2 ON u2.employer = customuser.id
Trying to make a password reset view. I'm using the auth_views built in views ie PasswordResetView and PasswordResetConfirmView for resetting password. However I was getting this error
Cannot resolve keyword 'is_active' into field. Choices are: active, admin, email, first_name, id, last_login, last_name, logentry, password, staff, timetables
. Tried changing active to is_active and getting this error.
django.core.exceptions.FieldError: Unknown field(s) (active) specified for User
Not able to make migrations
models.py
class User(AbstractBaseUser):
first_name = models.CharField(max_length=50, blank=True, null=True)
last_name = models.CharField(max_length=50, blank=True, null=True)
email = models.EmailField(max_length=254, unique=True)
is_active = models.BooleanField(default=True)
staff = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
def __str__(self):
return self.email
def get_first_name(self):
if self.first_name:
return self.first_name
return self.email
def get_last_name(self):
return self.last_name
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.is_active
forms.py
class UserAdminChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = ('email', 'first_name', 'last_name',
'password', 'active', 'admin')
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
Try to change is_active = models.BooleanField(default=True) to active = models.BooleanField(default=True) in your User class, and is_active property
see below
class User(AbstractBaseUser):
first_name = models.CharField(max_length=50, blank=True, null=True)
last_name = models.CharField(max_length=50, blank=True, null=True)
email = models.EmailField(max_length=254, unique=True)
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
#property
def is_active(self):
return self.active