This question already has an answer here:
How to query related models in django models.py
(1 answer)
Closed 3 years ago.
I have a model called StudentProfile:
class StudentProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
class_advisor = models.CharField(max_length=50)
year = models.OneToOneField(YearLevel, on_delete=models.SET_NULL, null=True)
section = models.OneToOneField(Section, on_delete=models.SET_NULL, null=True)
what I want to happen is, class_advisor to only return and accpet User with is_teacher = True.
by the way here's my User model:
class User(AbstractUser):
email = models.EmailField(
max_length=254,
unique=True,
verbose_name='Email Address',
blank=True
)
is_student = models.BooleanField(default=False, verbose_name='Student')
is_superuser = models.BooleanField(default=False, verbose_name='Administrator')
is_teacher = models.BooleanField(default=False, verbose_name='Teacher')
is_staff = models.BooleanField(default=False, verbose_name='Staff')
is_registrar = models.BooleanField(default=False, verbose_name='Registrar')
Yes, however at the moment, something is wrong with your modeling. You should make class_advisor a ForeignKey to the user model. Imagine that you store the username (or whatever unique attribute of that user) in your model. If later that teacher changes that username, then it will refer to a non-existing user, or later to a different user that picked the username.
You can set the limit_choices_to=... parameter [Django-doc]:
from django.db.models import Q
from django.contrib.auth import get_user_model
class StudentProfile(models.Model):
user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE, primary_key=True, related_name='studentprofile')
class_advisor = models.ForeignKey(get_user_model(), limit_choices_to=Q(is_teacher=True), related_name='students')
year = models.OneToOneField(YearLevel, on_delete=models.SET_NULL, null=True)
section = models.OneToOneField(Section, on_delete=models.SET_NULL, null=True)
If you use forms, etc. It will limit the options to Users that are teachers, and do validation on this.
It is better to use get_user_model() [Django-doc] here to refer to your user model, since if you later alter it, the ForeignKey (and OneToOneField will refer to the new model).
Try this:
StudentProfile.objects.filter(user__is_teacher=True)
StudentProfile.objects.filter(user__is_teacher=True).values('class_advisor')
Related
I have the following custom user model arrangement.
```
class User(AbstractUser):
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
class StudentProfile(models.Model):
student = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
location = models.CharField(max_length=8, blank=False, default='')
class TeacherProfile(models.Model):
teacher = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
location = models.CharField(max_length=8, blank=False, default='')
gender = models.CharField(max_length=8, choices=GENDER_CHOICES, default='')
```
I am able to a query the students based on the location of their teacher (current user).
Student.objects.filter(location=request.user.teacher.location)
I can also query the user model & find all teachers/students
User.objects.filter(is_teacher=True)
QUESTION:
Without relying on the profile models (Student & Teacher) How can I extend the query on abstractuser using profile attributes.
[X]-This is wrong but the idea is something like;
User.objects.filter(is_teacher=True).filter(is_teacher.location=newyork)
You can follow the OneToOneField in reverse:
User.objects.filter(teacherprofile__location='newyork')
You thus do not need to store is_teacher and is_student explicitly. You can simply filter Students with:
# Users with a related StudentProfile record
User.objects.filter(studentprofile__isnull=False)
What is the User model we are importing here? What does it do
here?
from django.contrib.auth.models import User
class Customer(models.Model):
user=models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE)
name=models.CharField(max_length=200, null=True)
phone=models.CharField(max_length=200, null=True)
email=models.CharField(max_length=200, null=True)
profile_pic=models.ImageField(default="profile2.png",null=True,blank=True)
def __str__(self):
return self.name
user=models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE)
Above line is making a one-to-one relationship with the default Django User model with the customer model. This means, every User instance in your database can be associated with atmost 1 Customer instance.
The default User model contains standard user fields like username, email, first_name, last_name etc. Take a look here to learn more about the User model.
Read this to learn more about one-to-one relationships.
i am trying to filter a data set based on a custom user model and having some difficulty with the data.
Basically, i have a registration form in which i am making user select the company they are associated with. So i have created a custom user model with a foreign key association to the company table.
Now, i am trying to query a second dataset so when user logs in, the application looks up the users company association and filters the data to only show results that are associated to the user's company choice.
any suggestion on how i can do this?
my user model is below:
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True, blank=True)
the table that i am trying to query on has model below:
class Order(models.Model):
customer = models.ForeignKey(Customer, on_delete= models.SET_NULL, null=True)
product = models.ForeignKey(Product, on_delete= models.SET_NULL, null=True)
date_created = models.DateTimeField(auto_now_add=True, null=True, blank=True)
requestorname = models.CharField(max_length=100, null=True)
requestorage = models.CharField(max_length=2,null=True, blank=True)
child_id = models.ForeignKey(ChildID, on_delete=models.SET_NULL, null=True, blank=True)
comments = models.CharField(max_length=100,null=True, blank=True)
requestdate_create = models.DateTimeField(auto_now_add=True)
note that both table has association to customer table using a foriegn key, so i want the user to only see the order associated to the company he/she belongs to.
appreciate any directions to help write the view. Thanks
So I was able to solve my own problem. I had to pass the request in as an argument. posting it here so folks with the same question can find answer. the view goes something like this.
def externalrequest(request):
args = request.user.customer_id
external = Order.objects.filter(customer=args)
context = {'external':external}
return render(request, 'accounts/external.html', context)
I have followed these [1,2,3] links to create a custom user model by extending AbstractBaseUser class. I am storing login information of three type of users lets say teacher, Admin and students in this table. USERNAME field is emailId.
I want to make emailId unique among one type of users. In other words, in my system student can register as teacher as well with same emailId. But since emailId is USERNAME field and hence unique, I am unable to achieve this.
Please suggest how can I do this in Django application.
UserModel :
class UserModel(AbstractBaseUser):
user_type_choices = (
(constants.USER_TYPE_ADMIN, 'Admin'),
(constants.USER_TYPE_INSTITUTE, 'Institute'),
(constants.USER_TYPE_STUDENT, 'Student')
)
sys_id = models.AutoField(primary_key=True, blank=True)
name = models.CharField(max_length=127, null=False, blank=False)
email = models.EmailField(max_length=127, unique=True, null=False, blank=False)
mobile = models.CharField(max_length=10, unique=True, null=False, blank=False)
user_type = models.PositiveSmallIntegerField(choices=user_type_choices, null=False, blank=True)
is_staff = models.BooleanField()
is_active = models.BooleanField(default=True)
objects = MyUserManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ['name', 'mobile', 'user_type','is_staff']
I am using other models like StudentsDetails, TeacherDetails with foreign key to UserModel to store extra information.
My task is for an administrator in my application to be able to create and update an employee's details. Given that django's user model simplifies authentication, I used it as a OnetoOneField in my Employee Model, representing the key as the employee ID (username).
My Model -
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50, unique=True)
date_of_join = models.DateField(blank=True, null=True)
date_of_birth = models.DateField(blank=True, null=True)
designation = models.CharField(max_length=255, null=True)
mobile = models.CharField(max_length=255, null=True)
personal_email = models.CharField(max_length=255, blank=True, null=True)
official_email = models.CharField(max_length=255, blank=True, null=True)
current_station = models.CharField(
max_length=255, default="Chennai", null=True)
def __str__(self):
return self.name
Serializers -
class EmployeeSerializer(serializers.ModelSerializer):
class Meta:
model = Employee
fields = ('user', 'name', 'date_of_join', 'date_of_birth',
'designation', 'mobile', 'landline', 'personal_email',
'official_email', 'current_station')
My Model View Set:
class EmployeeListSet(viewsets.ModelViewSet):
lookup_field = 'user'
serializer_class = EmployeeSerializer
queryset = Employee.objects.all()
Browsable API of a specific Employee filtered by user ID
As shown in the image, the user field shows me pk instead of user.username.
I am able to see the username in the HTML Form for POST in the browsable API, however the json does not return the username by default and rather returns pk.
I want to be able to lookup and update an employee's details based on the username (employee ID).
What I have tried -
I have tried redefining the user field as a SerializedMethodField that returns user.username, but lookup and POST method still requires the pk instead of username, so it doesn't solve the problem for me.
Nesting serialziers makes the nested serializer have to be read only, which again makes my task of updating employee details undesirable.
How can I lookup an employee object based on user.username instead of pk?
How can I associate an existing User object with an employee object during creation with the User object's username using modelviewsets? Is there a way to solve this without having to override or write my own create and update functions for the modelviewset?