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.
Related
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 have a registration system that works on otp.
I have a custom user model
class User(AbstractUser):
password = models.CharField(max_length=128, blank=True, null=True)
email = models.EmailField(max_length=254, unique=True)
dial_code_id = models.CharField(max_length=100)
mobile_number = models.CharField(max_length=100, blank=True, null=True)
username = models.CharField(max_length=150, unique=True, blank=True, null=True)
is_resource = models.BooleanField(default=False)
is_customer = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
skills = models.ManyToManyField(Skills)
class Meta:
db_table = "my_user"
def __str__(self):
return self.mobile_number
I have created an 'otp' model to save otp.
class Otp(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
otp = models.IntegerField()
created_on = models.DateTimeField(default=django.utils.timezone.now)
class Meta:
db_table = "otp"
My views looks like this
class UserCreateResponseModelViewSet(viewsets.ModelViewSet):
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
serializer.save()
custom_data = {
"status": True,
"message": 'Successfully registered your account.',
"data": serializer.data
}
generate_otp(serializer.data['id'])
return Response(custom_data, status=status.HTTP_201_CREATED)
else:
custom_data = {
"status": False,
"message": serializer.errors,
}
return Response(custom_data, status=status.HTTP_200_OK)
class UserCreateViewSet(UserCreateResponseModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
I have a function to generate and save otp
def generate_otp(user_id):
try:
otp_obj = Otp.objects.get(user_id=user_id)
except Otp.DoesNotExist:
otp_obj = None
if otp_obj is None:
otp = random.randrange(1000, 9999)
otp_obj = Otp(user=user_id, otp=otp)
otp_obj.save()
Serializer looks like
class UserSerializer(serializers.ModelSerializer):
mobile_number = serializers.CharField(
required=True,
validators=[UniqueValidator(queryset=User.objects.all())]
)
class Meta:
model = User
fields = ['id', 'first_name', 'last_name', 'email', 'dial_code_id','mobile_number', 'is_resource', 'is_customer']
The user is being registered successfully, but when it comes to saving otp in 'generate_otp()' I'm getting an error like
raise ValueError(ValueError: Cannot assign "2": "Otp.user" must be a "User" instance.
How can I overcome this?
Is this the right way to do it?
It looks like the problem is here:
otp_obj = Otp(user=user_id, otp=otp)
you're assigning an id (int) to the user field. not the user_id field
After creating a custom user model in my app, I have a studentProfile that inherits from the user model, which also contains avatar, semester, and dept_name. which works fine. However, when I was trying to display this studentProfile data using django-tables2, all rows keeps showing "-" and the ID been captured is from user model instead of studentProfile.
The weirdiest thing is i can get all the values from user model
correctly even when studentProfile is my table model for
django-tables2
I don't know what I am doing wrongly. Any help is really appreciated
my model definitions are as follow
class DepartmentData(models.Model):
fid = models.ForeignKey(FacultyData, on_delete=models.CASCADE)
dept_name = models.CharField(max_length=50)
created_on = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.dept_name
class User(AbstractBaseUser):
# add additional fields here
user_id = models.CharField(max_length=15, unique=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
active = models.BooleanField(default=True)# can login
staff = models.BooleanField(default=False) # staff user non superuser
admin = models.BooleanField(default=False) # superuser
USER_TYPE_CHOICES = (
(1, 'student'),
(2, 'lecturer'),
(3, 'bursary'),
(4, 'system'),
(5, 'admin'),
)
user_type = models.PositiveSmallIntegerField(choices=USER_TYPE_CHOICES)
USERNAME_FIELD = 'user_id'
REQUIRED_FIELDS = ['first_name', 'last_name', 'user_type']
objects = UserManager()
def __str__(self):
return self.user_id
def get_full_name(self):
return self.first_name + " " + self.last_name
def get_user_type(self):
return self.user_type
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
class StudentProfile(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
semester = models.ForeignKey(SemesterData, on_delete=models.SET_NULL, null=True)
dept_name = models.ForeignKey(DepartmentData, on_delete=models.SET_NULL, null=True)
avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
def __str__(self):
return self.user.first_name
class SemesterData(models.Model):
sid = models.ForeignKey(SessionData, on_delete=models.CASCADE)
semester_name = models.CharField(max_length=50)
def __str__(self):
return self.semester_name
def current(self):
if SettingsData.objects.all().count():
st = SettingsData.objects.get(id=1)
if self.id == st.current_id:
return "Current Session-Semester"
else:
return format_html('{}', reverse('system:current_session_semester', args=[self.id]),
'Set Current')
else:
return format_html('{}', reverse('system:current_session_semester', args=[self.id]),
'Set Current')
here is my table.py
class StudentTable(tables.Table):
user_id = tables.Column(attrs = {'th': {'class': 'danger'}})
first_name = tables.Column(attrs = {'th': {'class': 'danger'}})
last_name = tables.Column(attrs = {'th': {'class': 'danger'}})
avatar = tables.Column(accessor ="user", verbose_name = "ass" )
active = tables.Column(attrs = {'th': {'class': 'danger'}})
last_login = tables.Column(attrs = {'th': {'class': 'danger'}})
edit_Action = tables.LinkColumn('system:semester_edit', text='Edit', args=[A('pk')],attrs={'a':{'class':'btn btn-info btn-sm'}, 'td':{'align': 'center'}, 'th': {'class': 'danger'}}, orderable=False)
class Meta:
model = StudentProfile
attrs = {'class':'table table-hover table-bordered table-responsive'}
sequence = ('user_id', 'first_name', 'last_name', 'avatar')
exclude = {'id', 'user', 'password', 'staff', 'admin'}
empty_text = _("There are no students yet")
template_name = 'django_tables2/bootstrap4.html'
I would love to get the department_name, semester_name as well as fields in the studentProfile which is serving as my table model
You are seeing empty values for all fields with your current configuration because you're trying to access fields user_id, first_name and last_name which are not fields of the StudentProfile model, but rather fields of the User model (to which StudentProfile is related by user field).
That being said, you should access those fields via the user relation, something like this:
class StudentTable(tables.Table):
user_id = tables.Column(accessor='user.user_id', ...)
first_name = tables.Column(accessor='user.first_name', ...)
last_name = tables.Column(accessor='user.last_name', ...)
...
As far as the DepartmentData and SemesterData relations go, I'm not sure why aren't they displayed by default, since they are fields of the StudentProfile model, and they aren't excluded via the exclude property on the Meta. You can maybe try to explicitly list them in the fields property and see if that helps.
Why does the following print(owner) return a different value that what's in my model? Is it possible to get the formattedusername defined below? I've simplified my def profile(request) and took out my other arguments till I can figure out the solution to getting formattedusername.
def profile(request):
owner = User.objects.get (formattedusername=request.user.formattedusername)
args = {'user':request.user.formattedusername}
print (owner)
return render(request, 'accounts/profile.html', args)
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
#3-alphas4numeric
[06/Nov/2017 16:18:11] "GET /account/profile/ HTTP/1.1" 200 1416
formattedusername in my model is stored in the database as HCA\3-alphas4numeric, it's also defined by the following, it's also the key field in all my other models and there isn't a way around using an integer for the key since it's a pre-existing database:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
username = models.CharField(max_length=7, unique=True)
formattedusername = models.CharField(max_length=11, unique=True, primary_key = True)
first_name = models.CharField(max_length=40)
last_name = models.CharField(max_length=140)
date_joined = models.DateTimeField(default=timezone.now)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
facility = models.CharField(max_length=140)
jobdescription = models.CharField(max_length=140)
positiondescription = models.CharField(max_length=140)
coid = models.CharField(max_length=5)
streetaddress = models.CharField(max_length=140)
USERNAME_FIELD = 'username'
class Meta:
app_label = 'accounts'
db_table = "user"
def save(self, *args, **kwargs):
self.formattedusername = '{domain}\{username}'.format(
domain='HCA', username=self.username)
super(User, self).save(*args, **kwargs);
When you do print(owner), you will print out the value of USERNAME_FIELD. That's how AbstractBaseUser.__str__ is implemented.
def get_username(self):
"Return the identifying username for this User"
return getattr(self, self.USERNAME_FIELD)
def __str__(self):
return self.get_username()
Am having two model classes user and accounts linked by together or connected by another table called useraccounts.
What i want is for the useraccounts table to be automatically also be populated with the ids of the user and account table when i submit data to them(user and accounts).
here is my sample models code.
class Account(models.Model):
# fields
id = models.IntegerField(primary_key=True)
t_stamp = models.DateField(default=datetime.datetime.now())
acctno = models.TextField(null=False, unique =True)
acctname = models.TextField(null=False)
status = models.TextField(null=False, choices=STATUS)
accttype = models.TextField(null=False,choices=ACCT_TYPE)
acctclass = models.TextField(null=False, choices=ACCT_CLASS)
min_balance = models.FloatField(default=0)
cur_balance = models.FloatField(default=0)
ava_balance = models.FloatField(default=0)
#fundingsources = models.ManyToManyField(FundingSource)
class Meta:
managed = False
db_table = 'accounts'
def save(self, *args, **kwargs):
super(Account, self).save(*args, **kwargs)
try:
self.useraccount_set.all()[0]
except:
UserAccount.objects.bulk_create([UserAccount(account_id=self,user_id=user) for user in User.objects.all()])
class User(AbstractBaseUser, PermissionsMixin):
id = models.AutoField(primary_key=True)
username = models.TextField(unique=True, null=True)
fullname = models.TextField(null=False)
country = models.TextField(null=True)
email = models.EmailField( unique=True, db_index=True)
phone = models.TextField()
address = models.TextField()
activation_key = models.CharField(max_length=40)
key_expires = models.DateTimeField(null=True)
date_joined = models.DateTimeField(default=timezone.now)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=True)
#accounts = models.ManyToManyField(Account, through='UserAccount')
class Meta:
db_table = "users"
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = UserManager()
def get_short_name(self):
return self.fullname
def get_username(self):
return self.email
def is_authenticated(self):
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
signals.post_save.connect(create_auth_client, sender=User)
User._meta.get_field_by_name('email')[0]._unique=True
class UserAccount(models.Model):
user_id = models.ForeignKey(User)
account_id = models.ForeignKey(Account)
class Meta:
managed = False
db_table = 'useraccounts'
class UserAccount(models.Model):
user_id = models.ForeignKey(User)
account_id = models.ForeignKey(Account)
class Meta:
managed = False
db_table = 'useraccounts'
You have to do that in model save method:
class Account(models.Model):
id = models.IntegerField(primary_key=True)
def save(self, *args, **kwargs):
super(Account, self).save(*args, **kwargs)
try:
self.useraccount_set.all()[0]
except:
UserAccount.objects.bulk_create([UserAccount(account_id=self,user_id=user) for user in User.objects.all()])
class User(AbstractBaseUser, PermissionsMixin):
id = models.AutoField(primary_key=True)
def save(self, *args, **kwargs):
super(User, self).save(*args, **kwargs)
try:
self.useraccount_set.all()[0]
except:
UserAccount.objects.bulk_create([UserAccount(user_id=self,account_id=account) for account in Account.objects.all()])