Django Query including a table where no relation can be followed - python

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)

Related

Reference multiple foreign keys in Django Model

I'm making a program that helps log missions in a game. In each of these missions I would like to be able to select a number of astronauts that will go along with it out of the astronauts table. This is fine when I only need one, but how could I approach multiple foreign keys in a field?
I currently use a 'binary' string that specifies which astronauts are to be associated with the mission (1 refers to Jeb, but not Bill, Bob, or Val and 0001 means only Val), with the first digit specifying the astronaut with id 1 and so forth. This works, but it feels quite clunky.
Here's the model.py for the two tables in question.
class astronauts(models.Model):
name = models.CharField(max_length=200)
adddate = models.IntegerField(default=0)
experience = models.IntegerField(default=0)
career = models.CharField(max_length=9, blank=True, null=True)
alive = models.BooleanField(default=True)
def __str__(self):
return self.name
class Meta:
verbose_name_plural = "Kerbals"
class missions(models.Model):
# mission details
programid = models.ForeignKey(programs, on_delete=models.SET("Unknown"))
missionid = models.IntegerField(default=0)
status = models.ForeignKey(
missionstatuses, on_delete=models.SET("Unknown"))
plan = models.CharField(max_length=1000)
# launch
launchdate = models.IntegerField(default=0)
crewmembers = models.IntegerField(default=0)
# recovery
summary = models.CharField(max_length=1000, blank=True)
recdate = models.IntegerField(default=0)
def __str__(self):
return str(self.programid) + '-' + str(self.missionid)
class Meta:
verbose_name_plural = "Missions"
I saw a post about an 'intermediate linking table' to store the crew list but that also isn't ideal.
Thanks!
This is the use case for Django's ManyToManyField. Change the appropriate field on the missions:
class missions(models.Model):
crewmembers = models.ManyToManyField('astronauts')
You can access this from the Astronaut model side like so:
jeb = astronaut.objects.get(name='Jebediah Kerman')
crewed_missions = jeb.missions_set.all()
Or from the mission side like so:
mission = missions.objects.order_by('?')[0]
crew = mission.crewmembers.all()
This creates another table in the database, in case that is somehow a problem for you.

Django - Using 'exclude' to query a many-to-many relationship

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)

Django - How to link tables

Hello to the stackoverflow team,
I have the following two django tables:
class StraightredFixture(models.Model):
fixtureid = models.IntegerField(primary_key=True)
soccerseason = models.IntegerField(db_column='soccerSeason') # Field name made lowercase.
hometeamid = models.IntegerField()
awayteamid = models.IntegerField()
fixturedate = models.DateTimeField()
fixturestatus = models.CharField(max_length=24)
fixturematchday = models.IntegerField()
hometeamscore = models.IntegerField()
awayteamscore = models.IntegerField()
class Meta:
managed = False
db_table = 'straightred_fixture'
class StraightredTeam(models.Model):
teamid = models.IntegerField(primary_key=True)
teamname = models.CharField(max_length=36)
teamcode = models.CharField(max_length=5)
teamshortname = models.CharField(max_length=24)
class Meta:
managed = False
db_table = 'straightred_team'
In the views.py I know I can put the following and it works perfectly:
def test(request):
fixture = StraightredFixture.objects.get(fixtureid=136697)
return render(request,'straightred/test.html',{'name':fixture.hometeamid})
As I mentioned above, this all works well but I am looking to return the teamname of the hometeamid which can be found in the StraightredTeam model.
After some looking around I have been nudged in the direction of "select_related" but I am unclear on how to implement it in my existing tables and also if it is the most efficient way for this type of query. It feels right.
Please note this code was created using "python manage.py inspectdb".
Any advice at this stage would be greatly appreciated. Many thanks, Alan.
See model relationships.
Django provides special model fields to manage table relationships.
The one suiting your needs is ForeignKey.
Instead of declaring:
hometeamid = models.IntegerField()
awayteamid = models.IntegerField()
which I guess is the result of python manage.py inspectdb, you would declare:
home_team = models.ForeignKey('<app_name>. StraightredTeam', db_column='hometeamid', related_name='home_fixtures')
away_team = models.ForeignKey('<app_name>. StraightredTeam', db_column='awayteamid', related_name='away_fixtures')
By doing this will, you tell the Django ORM to handle the relationship under the hood, which will allow you to do such things as:
fixture = StraightredFixture.objects.get(fixtureid=some_fixture_id)
fixture.home_team # Returns the associated StraightredTeam instance.
team = StraightredTeam.objects.get(team_id=some_team_id)
team.home_fixtures.all() # Return all at home fixtures for that team.
I am not sure if this makes sense for Managed=False, but I suppose the sane way of doing it in Django would be with
home_team = models.ForeignKey('StraightRedFixture', db_column='fixtureid'))
And then just using fixture.home_team instead of doing queries by hand.

Filtering a QuerySet With another QuerySet

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.

Getting many to many fields of many to many association in django model

I have two levels of many to many associations in django. A player can belong to one or many teams. And a team can play one or many tournaments. Given a player i want to know in which all tournaments he has played.
Following is the simplified model:
class Tournament(models.Model):
name = models.CharField(max_length=100, blank=True, null=True)
class Team(models.Model):
team_name = models.CharField(max_length=100, blank=True, null=True)
tournaments_played = models.ManyToManyField(Tournament)
class Player(models.Model):
player_name = models.CharField(max_length=100, blank=True, null=True)
belongs_to_team = models.ManyToManyField(Team)
In my views i tried the following:
pl = Player.objects.get(player_name = "Andrew Flintoff")
ts = pl.belongs_to_team()
this gives me more than one team, now for each of the team i want to know which tournaments they have played.
qs_list = []
for t in ts:
team_qs = Team.objects.get(team_name = t)
tourn = team_qs.tournaments_played.all()
qs_list.append(tourn)
and then in my context i can pass the queryset list qs_list. Is there a better/simpler way of doing it??
p1_tournaments = Tournament.objects.filter(team__player=p1)
There's an implicit lookup created for every reverse foreign key or m2m field. It's either the lowercased model class or the related_name argument, if specified.
So, essentially, that filter says get the tournaments related to teams that are related to the player, p1.

Categories