Django ORM Get users not assigned to the Team - python

models.py
from django.db import models
class UserGroup(models.Model):
members = models.ManyToManyField(User, related_name='members', through='UserGroupMember')
class UserGroupMember(models.Model):
user = models.ForeignKey(User)
usergroup = models.ForeignKey(UserGroup)
class Cohort(models.Model):
user_groups = models.ManyToManyField(UserGroup)
class Team(models.Model):
cohort = models.ForeignKey(Cohort)
members = models.ManyToManyField(User, related_name='team_members', through='TeamMembers', blank=True)
class TeamMembers(models.Model):
team = models.ForeignKey(Team)
user = models.ForeignKey(User)
Single user can be part of only one team within a cohort.
Query #1
I need to write the query to get the users for a given cohort that are not assigned to any team.
I tried this:
User.objects.filter(
members__cohort=cohort
).filter(
team_members__isnull=True
)
but that does not give me the user if he is part of the team in another cohort.
Query #2
I want to annotate the new field (boolean) which tells you is the user assigned to some team in the cohort, something like:
User.objects.filter(
members__cohort=cohort
).annotate(
is_team_member=...
)
I am using Python 2.7.13 and Django 1.9.8. Thanks.

Try constructing the queryset by excluding all the members that are assigned to a team in the cohort:
User.objects.filter(
members_cohort=cohort,
).exclude(
team_members__cohort=cohort,
)

Related

How to use values and distinct on different field on Django ORM?

currently I have terms on my applications and one user can have a lot of terms registered, and my current model is like this
class Term(models.Model):
id = models.UUIDField("id", default=uuid.uuid4, editable=False, primary_key=True)
user_id = models.PositiveIntegerField("user id", default=None)
name = models.CharField()
sometimes I need to do a query to get all the users who have terms registered, so I do the following query:
Term.objects.filter(active=True)
.order_by("user_id")
.values("user_id")
.distinct()
and this is enough to solve my problems, but now I'll change my model and it will look like this:
class Term(models.Model):
id = models.UUIDField("id", default=uuid.uuid4, editable=False, primary_key=True)
user_id = models.PositiveIntegerField("user id", default=None)
name = models.CharField()
shared_with = ArrayField(models.PositiveIntegerField("id do usuario"), blank=True) # New
How you can see, I've added a new field named shared_with, that basically is a array of user ids which I want to share terms, So now I need to make a query who will return all ids who can have terms registered (shared_with included). So if i register a Term with user_id = 1 and shared_with = [2,3], my query need to return [1,2,3].
I've solved this problem today with the following code, but I think I can do this just using django ORM and one query:
users = set()
for user in (
Term.objects.filter(active=True)
.order_by("user_id")
.values("user_id")
.distinct()
):
users.add(user["user_id"])
for user in (
Term.objects.filter(active=True)
.order_by("user_id")
.values("shared_with")
):
for user_id in user["shared_with"]:
users.add(user_id)
print(users) # {1,2,3}
If someone knows how to do it and can share the knowledge, I will be grateful.
I don't recommend using the PositiveIntegerField and ArrayField as relations between tables, you can use ForeignKey and ManyToManyField instead, in your case what I understand is a user can have many Terms and a Term can be shared among many users, so the perfect solution is to add ManyToManyField in your User model
class User(AbstarctUser):
... (your fields)
terms = models.ManyToManyField(Term, related_name="users")
and Term model will be like:
class Term(models.Model):
id = models.UUIDField("id", default=uuid.uuid4, editable=False, primary_key=True)
name = models.CharField(max_length=200)
active = models.BooleanField(default=True)
... (other fields)
in that case, if you want to extract user ids with active terms, you can get it as following :
users = User.objects.filter(terms__active=True).distinct().values_list("id", flat=True)

A Model is linked to two other models. How do I access the properties of that two other models in django

I am in a process of creating a Room Booking Management System using Django. I have faced an issue in accessing models.
Here is my Room Model
class Room(models.Model):
name = models.CharField(max_length=30)
date = models.DateField()
defined_check_in_time = models.IntegerField()
defined_check_out_time = models.IntegerField()
booked = models.BooleanField(default = False)
USERNAME_FIELD = 'name'
class Meta:
ordering = ['date', 'defined_check_in_time']
def __str__(self):
return self.name
def is_booked(self):
return self.booked
def set_booked(self):
self.booked = True
Here is my Booking Model
class Booking(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
room = models.ForeignKey(Room, on_delete=models.CASCADE)
def __str__(self):
return f'{self.user} has booked {self.room} from {self.room.defined_check_in_time} to {self.room.defined_check_out_time} on {self.room.date}'
I have linked the User model and Room model in the Booking model using a foreign key when a user books a room. User model is defined in another file. I have not included that model code here.
When a user books a room, the corresponding room object and user object is linked to the booking object. To display the bookings of the user, I need to query the Booking model using a User object.
Here, my question is how i can access user and room object attributes inside the booking object?
To access information within your booking object, you must first select a booking object, whichever way you choose to identify a booking.. maybe by an id. Let's say booking id=100
booking = Booking.objects.get(id=100)
Now to find foreign key info you can just . lookup.
booking_user = booking.user.username
booking_room = booking.room.name
or to find any bookings on rooms booked:
booked_rooms = Booking.objects.filter(room.booked == True)

m2m 'through' field in django models throwing this error: 'M2M field' object has no attribute '_m2m_reverse_name_cache'

Hey guys I am trying to add a m2m through field to have assistants to my 'Department' model to call like department.assistants.all(), but while doing so, I am getting this error AttributeError: 'ManyToManyField' object has no attribute '_m2m_reverse_name_cache'.
This is my model:
class Department(models.Model):
id = models.BigAutoField(primary_key=True)
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
assistants = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Assistants', related_name='dep_assistants',
symmetrical=False)
class Assistants(models.Model):
id = models.BigAutoField(primary_key=True)
department = models.ForeignKey(Department, related_name='of_department', on_delete=models.CASCADE)
assistant = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='dt_assistant',
verbose_name="Department Assistant", on_delete=models.CASCADE)
added = models.DateTimeField(auto_now_add=True)
I am pretty new to this concept. Can someone tell me what I did wrong here?
Thanks
The way you have defined your models the queries seem too confusing. Try how models are defined below and then try the query.
You did not mention the through_field attribute in the many to many field definition. check the docs: https://docs.djangoproject.com/en/3.2/ref/models/fields/#django.db.models.ManyToManyField
class Department(models.Model):
# i think this is not needed. Also id is a protected keyword in python.
# id = models.BigAutoField(primary_key=True)
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
assistants = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Assistants',
related_name='departments', through_fields=("department", "assistant"))
# model name should never be prural. It is singluar becuase it is the name of the object.
class Assistant(models.Model):
# i think this is not needed. Also id is a protected keyword in python.
# id = models.BigAutoField(primary_key=True)
department = models.ForeignKey(Department, on_delete=models.CASCADE)
assistant = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name="Department Assistant", on_delete=models.CASCADE)
added = models.DateTimeField(auto_now_add=True)
# how to query assistants from departments
# you will get objects of User model
qs = department.assistants.all()
# how to query departments from assistants
# you will get objects of Department model
qs = user.departments.all()
# If you want to query the Assistant model
# from department object
qs = department.assistant_set.all()
# from assistant object
qs = user.assistant_set.all()
# in either case you will get the objects of Assistant model
for i in qs:
print(i.added, i.department, i.assistant)
Try this and let me know if you still get the error.
My suggestion is to name the assistant field on the Assistant model as user. This way you will not need to define through_field on the many to many field.
If one assistant relates to only one department - this is relation one-to-many. (One department has many assistants) In code would be:
class Assistant(models.Model):
...
department = models.ForeignKey(Department)
No need for a special reference on Department. To get all assistants:
assistants = models.Assistant.objects.filter(department=department)
Or create a property on a class Department:
#property
def assistants(self):
return models.Assistant.objects.filter(department=self)
If one assistant relates to many departments (and each department has many assistants), it is many-to-many relationship and there should be additional class between them:
class Assignment(models.Model):
assistant = models.ForeignKey(Assistant)
department = models.ForeignKey(Department)
class Department(models.Model):
...
assignment= models.ForeignKey(Assignment)
class Assistant(models.Model):
...
assignment = models.ForeignKey(Assignment)
So here to query assistants of the department:
assistants = models.Assistant.objects.filter(
assignment__in=models.Assignment.objects.filter(
department=department
)
)

Django ORM Annotate boolean field that defines is user member of a team

models.py
from django.db import models
class UserGroup(models.Model):
members = models.ManyToManyField(User, related_name='members', through='UserGroupMember')
class UserGroupMember(models.Model):
user = models.ForeignKey(User)
usergroup = models.ForeignKey(UserGroup)
class Cohort(models.Model):
user_groups = models.ManyToManyField(UserGroup)
class Team(models.Model):
cohort = models.ForeignKey(Cohort)
members = models.ManyToManyField(User, related_name='team_members', through='TeamMembers', blank=True)
class TeamMembers(models.Model):
team = models.ForeignKey(Team)
user = models.ForeignKey(User)
Single user can be part of only one team within a cohort.
I want to annotate the new field (boolean) which tells you is the user assigned to some team in the cohort, something like:
User.objects.filter(
members__cohort=cohort
).annotate(
is_team_member=...
)
I am using Python 2.7.13 and Django 1.9.8. Thanks.
I managed to solve the problem by doing the join to the Cohort model and using conditional expressions:
from django.db.models import Case, When, Value, IntegerField
users = User.objects.filter(
members__cohort=cohort
).annotate(
is_team_member=Case(When(team_members__cohort=cohort, then=Value(1)), default=0, output_field=IntegerField())
)
Now I can easily filter, for example, users who are part of some team:
users.filter(is_team_member=1)

Searching by related fields in django admin

I've been looking at the docs for search_fields in django admin in the attempt to allow searching of related fields.
So, here are some of my models.
# models.py
class Team(models.Model):
name = models.CharField(max_length=255)
class AgeGroup(models.Model):
group = models.CharField(max_length=255)
class Runner(models.Model):
"""
Model for the runner holding a course record.
"""
name = models.CharField(max_length=100)
agegroup = models.ForeignKey(AgeGroup)
team = models.ForeignKey(Team, blank=True, null=True)
class Result(models.Model):
"""
Model for the results of records.
"""
runner = models.ForeignKey(Runner)
year = models.IntegerField(_("Year"))
time = models.CharField(_("Time"), max_length=8)
class YearRecord(models.Model):
"""
Model for storing the course records of a year.
"""
result = models.ForeignKey(Result)
year = models.IntegerField()
What I'd like is for the YearRecord admin to be able to search for the team which a runner belongs to. However as soon as I attempt to add the Runner FK relationship to the search fields I get an error on searches; TypeError: Related Field got invalid lookup: icontains
So, here is the admin setup where I'd like to be able to search through the relationships. I'm sure this matches the docs, but am I misunderstanding something here? Can this be resolved & the result__runner be extended to the team field of the Runner model?
# admin.py
class YearRecordAdmin(admin.ModelAdmin):
model = YearRecord
list_display = ('result', 'get_agegroup', 'get_team', 'year')
search_fields = ['result__runner', 'year']
def get_team(self, obj):
return obj.result.runner.team
get_team.short_description = _("Team")
def get_agegroup(self, obj):
return obj.result.runner.agegroup
get_agegroup.short_description = _("Age group")
The documentation reads:
These fields should be some kind of text field, such as CharField or TextField.
so you should use 'result__runner__team__name'.

Categories