Django better join - django

Here is my models. This is like a sports team org app. Event model is the sports event like a baseball game. Anyone can belong to multiple teams. So, the team member represents the membership to team.
class Team(models.Model):
name = models.CharField(max_length=100, blank=True)
class TeamMember(models.Model):
member = models.ForeignKey(User, on_delete=models.CASCADE)
team = models.ForeignKey(Team, on_delete=models.CASCADE)
class Event(models.Model):
team = models.ForeignKey(Team, on_delete=models.CASCADE)
I want to get the list of events my teams have.
def get_queryset(self):
teams = TeamMember.objects.filter(member=self.request.user).values('team')
return Event.objects.filter(team__in=teams)
This does work, but I want to make it to a single join. My ORM-fu is not that great.

As Docs says
Django offers a powerful and intuitive way to “follow” relationships
in lookups, taking care of the SQL JOINs for you automatically, behind
the scenes. To span a relationship, use the field name of related
fields across models, separated by double underscores, until you get
to the field you want.
...
It works backwards, too. To refer to a “reverse” relationship, use the
lowercase name of the model.
Event.objects.filter(team__teammember__member=self.request.user)

Related

Public Transportation Webapp in DJANGO : models (many-to-many relationship) for transportation systems and routes

This webapp would allow users to create alerts about controlers in public transportation in a big city. It would include mostly trains and buses.
I'm quite stuck with how to create the model. I've already created the Alert that has a station attribute with a one-to-one relationship, and a line attribute also.
I have two models : a model Stations, and a model Line.
Now each transportation mode (bus/train) has a line, stations and a schedule.Each line has several stations (or bus stops), and each stations receives many lines. I used a many-to-many fields in the Line model, but I don't know how to order the stations, since a bus will go through each of its stations in an orderly fashion, neither how to link that to a schedule. I thought about making another model "Line_Station" with each instance having the attributes Line, Station and Order, but that doesn't seem optimal for routes that have many stations, since a Route would be each instance of Line_Station for the same attribute Line. I'm new at Django and haven't really had the chance to manipulate the database relationships, but I feel like this problem could be solved with a many-to-many relationship.
(Transportations/models.py)
class Station(models.Model):
Station_name = models.CharField(max_length=200)
Station_adress = models.CharField(max_length=300)
Station_vehicule = models.ForeignKey(Vehicule, on_delete=models.CASCADE)
class Line(models.Model):
Line_number = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(100)])
Line_name = models.CharField(max_length=200, blank=True, null=True)
Line_vehicule = models.ForeignKey(Vehicule, on_delete=models.CASCADE)
Line_stations = models.ManyToManyField(Station)
class Line_station(models.Model):
line = models.ForeignKey(Line, on_delete=models.CASCADE)
station = models.ForeignKey(Station, on_delete=models.CASCADE)
order = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(60)])
Is there a more optimal way to resolve this ? The point is that I would like to create lines in my django admin and from there, add stations and select the order. If I were to think that this app would attract many users, I feel like creating two more models (routes and schedules) might create too many queries.
Here's the Alert model if it is of any interest :
(Alerts/models.py)
class Alert(models.Model):
alert_whistleblower = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
alert_timestamp = models.DateTimeField(auto_now_add=True)
alert_station = models.ForeignKey(Station, on_delete=models.CASCADE)
alert_line = models.ForeignKey(Line, on_delete=models.CASCADE)
alert_remarks = models.TextField(blank=True, null=True)
def get_absolute_url(self):
return reverse('alerts:detail', kwargs={'pk':self.pk})
Here's a diagram of the models, but I don't really know how to connect Schedule to route, since the model Route wouldn't be "one route" but many instances (one route would be each instance of the same line attribute, and an order).
Diagram
How can I make my model more optimized ?
As of now, I've used the relationship Many-to-Many on the model Line, using through = 'routes'.
class Line(models.Model):
Line_number = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(100)])
Line_stations = models.ManyToManyField(Station, through="Route")
class Route(models.Model):
line = models.ForeignKey(Line, on_delete=models.CASCADE)
station = models.ForeignKey(Station, on_delete=models.CASCADE)
order = models.IntegerField()
I'm still not sure about this. Should the many-to-many field go to Station ? Should both have one ? I still don't know how to make a model schedule on top of this. Ordering each instance of Route is quite a pain in the ass by the way, since I'd like it to auto-increment for a line instance.

How to retrieve related instances without FK using one query in django

Imagine there are three models named Movie, Actor, and Participation.
class Movie(models.Model):
identifier = models.CharField()
class Actor(models.Model):
name = models.CharField()
class Participation(models.Model):
movie_identifier = models.CharField()
actor = models.ForgeinKey(Actor, on_delete=models.CASCADE)
Let's assume that I can't use ForgeinKey for the movie in the Participation model.
how can I retrieve all the participation records of a movie with only one query?
Here is the solution if I had a foreign key for the movie in the participation table:
qs = Movie.objects.filter(identifier="an_identiier").prefetch_related("participations_set")
How can I do this without having a Movie foreign key in the Participation model?
Thanks!
One of the most important things when designing a database (hence when designing your models) is database normalization [Wikipedia].
You talk about Participation being related to multiple models like Movie, Series, Episode, etc. this means that Movie, Series, Episode all can be said to have something in common or they can be said to be a specialization of another entity let us say Participatable for the lack of a better word, or we can say Participatable is a generalization of Movie, Series, Episode, etc.
How do we model these? Well we will just have an extra model that our other models will have a OneToOneField with:
class Participatable(models.Model):
# Any common fields here
MOVIE = 'M'
SERIES = 'S'
TYPE_CHOICES = [
(MOVIE, 'Movie'),
(SERIES, 'Series'),
]
subject = models.CharField(max_length=1, choices=TYPE_CHOICES)
class Movie(models.Model):
# uncommon fields
participatable = models.OneToOneField(
Participatable,
on_delete=models.CASCADE,
related_name='movie',
)
class Series(models.Model):
# uncommon fields
participatable = models.OneToOneField(
Participatable,
on_delete=models.CASCADE,
related_name='series',
)
class Participation(models.Model):
participatable = models.ForgeinKey(Participatable, on_delete=models.CASCADE)
actor = models.ForgeinKey(Actor, on_delete=models.CASCADE)
Other than this solution which I find is the best for such modelling you can go with using the content-types framework which will essentially do what you do currently. That is it will use a field that stores the related id and also a foreign key that points to an entry in a table that will simply describe which table this id is for.

Stack Inline Multiple Django Models in Admin with indirect relationship

I have the following three models
class Participant(models.Model):
participant_id = models.AutoField(primary_key=True)
pin = models.CharField(unique=True, max_length=4,
validators=[RegexValidator(r'^\d{1,10}$')])
class Teacher(models.Model):
teacher_id = models.AutoField(primary_key=True)
participant_id = models.OneToOneField(Participant, on_delete=models.CASCADE)
email = models.EmailField()
compensation_id = models.OneToOneField(Compensation, on_delete=models.CASCADE)
class Compensation(models.Model):
compensation_id = models.AutoField(primary_key=True)
wage = models.DecimalField(max_digits=6, decimal_places=2)
To summarize,
Participant has different types, one of them is Teacher (OneToOne
relation).
Teacher is one type of employee that is compensated and it's related (OneToOne relation) with Compensation Model
I want to create an admin form by stacking
Participant
Teacher
Compensation
The problem:
I am using Participant as a primary model and stacking teacher to it. However, when I try to stack compensation to it, it apparently doesn't work due to missing foreign key relation between Participant and Compensation models.
An easy way out would be to have the fields of the Compensation model in the Teacher Model. However, it would create redundancy when I want to associate other types of Participants to it.
What could potentially be a solution to this? I am open to altering the model if it makes thing any easier or less complicated.
P.S. There are also other types of participants (Child, Parent) that I have not mentioned.
P.S.S. There are other fields in the above-mentioned models that I have not mentioned for the sake of simplicity.

Django - How to build an intermediate m2m model that fits? / best practice

First of all I have to admit that I'm quite new to all this coding stuff but as I couldn't find a proper solution doing it myself and learning to code is probably the best way.
Anyway, I'm trying to build an app to show different titleholders, championships and stuff like that. After reading the Django documentation I figured out I have to use intermediate models as a better way. My old models.py looks like this:
class Person(models.Model):
first_name = models.CharField(max_length=64)
last_name = models.CharField(max_length=64)
[...]
class Team(models.Model):
name = models.CharField(max_length=64)
team_member_one = models.ForeignKey(Person)
team_member_two = models.ForeignKey(Person)
class Championship(models.Model):
name = models.CharField(max_length=128)
status = models.BooleanField(default=True)
class Titleholder(models.Model):
championship = models.ForeignKey(Championship)
date_won = models.DateField(null=True,blank=True)
date_lost = models.DateField(null=True,blank=True)
titleholder_one = models.ForeignKey(Person,related_name='titleholder_one',null=True,blank=True)
titleholder_two = models.ForeignKey(Person,related_name='titleholder_two',null=True,blank=True)
Championships can be won by either individuals or teams, depending if it's a singles or team championship, that's why I had to foreign keys in the Titleholder class. Looking at the Django documentation this just seems false. On the other hand, for me as a beginner, the intermediate model in the example just doesn't seem to fit my model in any way.
Long story short: can anyone point me in the right direction on how to build the model the right way? Note: this is merely a question on how to build the models and displaying it in the Django admin, I don't even talk about building the templates as of now.
Help would be greatly appreciated! Thanks in advance guys.
So I will take it up from scratch. You seem to be somewhat new to E-R Database Modelling. If I was trying to do what you do, I would create my models the following way.
Firstly, Team would've been my "corner" model (I use this term to mean models that do not have any FK fields), and then Person model would come into play as follows.
class Team(models.Model):
name = models.CharField(max_length=64)
class Person(models.Model):
first_name = models.CharField(max_length=64)
last_name = models.CharField(max_length=64)
team = models.ForeignKey(to=Team, null=True, blank=True, related_name='members')
This effectively makes the models scalable, and even if you are never going to have more than two people in a team, this is good practice.
Next comes the Championship model. I would connect this model directly with the Person model as a many-to-many relationship with a 'through' model as follows.
class Championship(models.Model):
name = models.CharField(max_length=64)
status = models.BooleanField(default=False) # This is not a great name for a field. I think should be more meaningful.
winners = models.ManyToManyField(to=Person, related_name='championships', through='Title')
class Title(models.Model):
championship = models.ForeignKey(to=Championship, related_name='titles')
winner = models.ForeignKey(to=Person, related_name='titles')
date = models.DateField(null=True, blank=True)
This is just the way I would've done it, based on what I understood. I am sure I did not understand everything that you're trying to do. As my understanding changes, I might modify these models to suit my need.
Another approach that can be taken is by using a GenericForeignKey field to create a field that could be a FK to either the Team model or the Person model. Or another thing that can be changed could be you adding another model to hold details of each time a championship has been held. There are many ways to go about it, and no one correct way.
Let me know if you have any questions, or anything I haven't dealt with. I will try and modify the answer as per the need.

How to create classes in Django model

Since Django is mapping each model to a table. I am not able to create packages in my code. Where I can wrap sections of the class to make it more logical and increase the coupling.
For example
class Employee(models.Model):
#personal information
first_name = models.CharField(max_length=20)
middle_initial = models.CharField(max_length=1)
last_name = models.CharField(max_length=20)
dob = models.DateField()
#job contract information
full_time = models.BooleanField()
hours_per_day = models.PositiveSmallIntegerField()
#.. and more
What I am trying to do is this
employee.job.is_full_time
employee.job.get_hours_per_day
# and more
However this means that I have to create a new model and connect it with the employee model using OneToOneField. I don't want to do that .. joins in the database are expensive. Is there anyway to create something like this ?
class Employee(models.Model):
class PersonalInformation:
first_name = models.CharField(max_length=20)
middle_initial = models.CharField(max_length=1)
last_name = models.CharField(max_length=20)
dob = models.DateField()
class Job:
full_time = models.BooleanField()
hours_per_day = models.PositiveSmallIntegerField()
#.. and more
The main key to the answer is to create a model that contain multiple classes which are going to be mapped to one table in the database.
There is no way to do that with just Django. Django models represent flat, relational databases. Extending the model framework to provide functionality beyond what its backend is capable of is unnecessary, and therefore not implemented in the default framework.
There are third-party packages that provide what you want, but as far as I know these packages use database backends that are capable of using such data structures.
Personally I would go with your first example, a flat, single model that represents all my Employee data. Prevent any disambiguity in your field names, and there will be no cost for using a flat model over a nested model.
And remember: premature optimization is a lot more expensive than an join statement.