I have two models joined by a many-to-many relationship:
class Room(models.Model):
id = models.CharField(max_length=50, primary_key=True)
name = models.CharField(max_length=50)
class Event(models.Model):
id = models.CharField(max_length=50, primary_key=True)
start = models.DateTimeField()
end = models.DateTimeField()
room = models.ManyToManyField(Room)
I'm trying to exclude all Rooms which have an Event that starts before a particular date and ends after a different date. I can get all rooms which fit this criteria using filter:
Room.objects.filter(event__start__lt=date1, event__end__gt=date2)
and that works fine, though it returns all the Rooms I want not those I don't. If however I do exactly the same thing, but replace filter with exclude:
Room.objects.exclude(event__start__lte=date1, event__end__gte=date2)
then it excludes more Rooms than it found using filter. Does anyone know why this is? I'm currently having to do a bit of a silly workaround, namely:
badRooms = Room.objects.filter(event__start__lt=date1, event__end__gt=date2)
badRooms = [x.id for x in badRooms]
return Room.objects.filter(id__in=badRooms)
but this is both silly and inefficient, so if anyone knows what I'm doing wrong with exclude, that would be much appreciated!
I assume the problem lies in the many-to-many relationship, as I need to remove all Rooms which have at least one single Event fitting both criteria, but not Rooms which have two different events which each fit one of the criteria.
The events has the rooms, but the room do not have events
try :
Event.objects.filter(Q(start__lt=date1) | Q(end__gt=date2))
or:
Event.objects.filter(start__lt=date1, end__gt=date2)
if you want to filter by end/start the rooms you have to added to the model:
class Room(models.Model):
id = models.CharField(max_length=50, primary_key=True)
name = models.CharField(max_length=50)
start = models.DateTimeField()
end = models.DateTimeField()
And then u can filter like this:
Event.objects.filter(Q(room__start__lt=date1) | Q(room__end__gt=date2))
or:
Event.objects.filter(room__start__lt=date1, room__end__gt=date2)
Related
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)
I have three models:
Course
Assignment
Term
A course has a ManyToManyField which accesses Django's default User in a field called student, and a ForeignKey with term
An assignment has a ForeignKey with course
Here's the related models:
class Assignment(models.Model):
title = models.CharField(max_length=128, unique=True)
points = models.IntegerField(default=0, blank=True)
description = models.TextField(blank=True)
date_due = models.DateField(blank=True)
time_due = models.TimeField(blank=True)
course = models.ForeignKey(Course)
class Course(models.Model):
subject = models.CharField(max_length=3)
number = models.CharField(max_length=3)
section = models.CharField(max_length=3)
professor = models.ForeignKey("auth.User", limit_choices_to={'groups__name': "Faculty"}, related_name="faculty_profile")
term = models.ForeignKey(Term)
students = models.ManyToManyField("auth.User", limit_choices_to={'groups__name': "Student"}, related_name="student_profile")
When a user logs in to the page, I would like to show them something like this bootstrap collapse card where I can display each term and the corresponding classes with which the student is enrolled.
I am able to access all of the courses in which the student is enrolled, I'm just having difficulty with figuring out the query to select the terms. I've tried using 'select_related' with no luck although I may be using it incorrectly. So far I've got course_list = Course.objects.filter(students = request.user).select_related('term'). Is there a way to acquire all of the terms and their corresponding courses so that I can display them in the way I'd like? If not, should I be modeling my database in a different way?
https://docs.djangoproject.com/en/1.11/ref/models/querysets/#values
You could use values or values_list here to get the fields of the related model Term.
For example expanding on your current request:
To retrieve all the Terms' name and duration for the Courses in your queryset
Course.objects.filter(students = request.user).values('term__name', 'term__duration')
I am not sure what the fields are of your Term model, but you would replace name or duration with whichever you are trying to get at.
I think it helps you
terms = Terms.objects.filter(....) # terms
cources0 = terms[0].course_set.all() # courses for terms[0]
cources0 = terms[0].course_set.filter(students=request.user) # courses for terms[0] for user
I have three models: Assets, AssetTypes and Services. Assets need to get serviced every n months, and have a many-to-one relation with services.
class AssetType(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(verbose_name="Asset Type", max_length=100)
service_period = models.PositiveSmallIntegerField(verbose_name="Service Period (in months)", null=True, blank=True, default=12)
class Asset(models.Model):
id = models.AutoField(primary_key=True)
type = models.ForeignKey(AssetType, on_delete=models.PROTECT)
def service_period(self):
return AssetType.objects.get(pk=self.type.id).service_period
def service_history(self):
return self.service_set.all().order_by('-date')
def service_due_date(self):
if self.service_period()==None:
return None
elif self.service_history().count()==0:
return datetime.strptime('2017-01-01', '%Y-%m-%d').date()
else:
last_service_date = self.service_history().latest('date').date
return last_service_date + timedelta(self.service_period()*30)
def service_overdue(self):
return ((self.service_due_date()!=None) and self.service_due_date() < date.today())
class Service(models.Model):
id = models.AutoField(primary_key=True)
date = models.DateField()
asset = models.ForeignKey(Asset, on_delete=models.CASCADE)
I'm trying to work out how to make a query set that would return a list of assets that are overdue for their service. I feel like using a model method is a red herring, and that I would be better off defining a query set filter?
I need the list of overdue assets to be a query set so I can use further query set filters on it.
Any assistance would be greatly appreciated!
So this is a bit tricky.
To put the query in words, you are looking for all Assets whose latest Service date is earlier than today minus the Type's service period multiplied by 30.
To be honest, I would be tempted to denormalize this; you could add a next_service_due field on Asset which is updated when you add a new Service. Then the query is simply all assets with that field less than today.
i'm trying to 'join' this 4 models in a query. My starting point is a Team.id.
I am trying to get the SkillRecord into the result but i am completly lost.
class Team(models.Model):
user = models.ForeignKey(User)
id = models.IntegerField(primary_key=True, null=False, unique=True)
...
class Player(models.Model):
id = models.IntegerField(primary_key=True)
...
class Transfer(models.Model):
player = models.ForeignKey(Player)
seller = models.ForeignKey(Team, related_name='transfer_seller')
buyer = models.ForeignKey(Team, related_name='transfer_buyer')
date = models.DateTimeField()
...
class SkillRecord(models.Model):
player = models.ForeignKey(Player)
date = models.DateTimeField(default=datetime.datetime.now)
...
Here is my humble approach so far
def list_players(request, teamid):
team = get_object_or_404(Team, id=teamid)
players_transfers = Transfer.objects.filter(buyer=team).select_related('player')
I'm not really sure what would be my next step to get the SkillRecord model into the game.
I seem to lack the basic gist of those kind of problems so i will need a poke i guess.
Also, feel free to give me further ideas how to do this, i'm more or less sure i could also solve this whole Transfer thing using manytomanyfields or so.
Thanks a lot
To grab SkillRecord as well you need to add related_name:
class SkillRecord(models.Model):
player = models.ForeignKey(Player, related_name='skills')
date = models.DateTimeField(default=datetime.datetime.now)
then make the query:
qt = Transfer.objects.filter(...).select_related('player').prefetch_related('player__skills')
then retrieve them like so:
qt[0].player.skills.all()
Making some assumptions each Player has a Team so we can add.
class Player(models.Model):
team = models.ForeignKey(Team)
Then if you want the skillrecord start by there
SkillRecord.objects.filter(player__team=team)
Hi i'm not very good at English but i'll try to explain myself the best i could. I'm using python and Django to create a web project.
I have this 4 models (this is the best translation i can do of the tables and fields):
class Humans (models.Model):
name = models.CharField(max_length=15)
surname = models.CharField(max_length=15)
doc_num = models.CharField(max_length=11)
...
class Records (models.Model):
closing_state = models.CharField(max_length=2)
...
humans = models.ManyToManyField(Humans, through='Reco_Huma')
class Reco_Huma (models.Model):
id_record = models.ForeignKey(Records)
id_human = models.ForeignKey(Humans)
categorys = models.CharField(max_length=2)
reserv_identity = models.CharField(max_length=2)
repre_entity = models.CharField(max_length=2)
class Observations (models.Model):
id_record = models.ForeignKey(Records)
text = models.CharField(max_length=80)
category = models.CharField(max_length=2, choices=CAT)
Now given a doc_num from Humans, a text from Observations i want to get a QuerySet Of all the Records.
To clarify i first do this:
q1 = Reco_Huma.objects.filter(id_human.doc_num=x)
q2 = Observations.objects.filter(text=y)
both query-sets give me a list of id_record and then i want to connive that lists and filter the Records table with that id_record's
I hope you can understand me
Thanks in advance
To rephrase your query, you want all the Records associated with a certain Human and which have a certain Observation. So it should be:
result = Records.objects.filter(observations__text=y, humans__doc_num=x)
As a general rule, if you want to end up with a certain type of object, it helps to start from there in your query.