How to retrieve related instances without FK using one query in django - 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.

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.

use manytomany field in both the models Django

I have two models named Profile and Controversy. My requirement is many people can be involved in a controversy and a single person can have multiple Controversies. With that said, I feel like I should a ManyToMany field in both the models but I'm guessing that violates ManyToMany fields documentation as it should be used in only model.
my models are as follows :
class Profile(models.model):
name = models.CharField(max_length=200)
Controversy = models.ManyToManyField(Controversy) # As one person can have multiple controveries
class Controversy(models.Model):
year = models.Datefield()
other_people_involved = models.ManytoManyField(profile) # As multiple people can be involved in a controversy
description = models.TextField()
This obviously will throw error.
I'm not able to understand as to how to tackle such a scenario
You can try this way:
Create another model to store the person and controvery connection.
class Profile(models.model):
name = models.CharField(max_length=200)
class Controversy(models.Model):
year = models.Datefield()
description = models.TextField()
class PeopleInvolved(models.Model):
controversy = models.ManyToManyField(Controversy)
person = models.ManytoManyField(profile)
So to list the controversies of a person do this:
controversies = [i.controversy for i in PeopleInvolved.objects.filter(person=[profile_id])] #pass the profile id of the person.
And to list the people involved in a controversy do this:
peoples = [i.person for i in PeopleInvolved.objects.filter(controversy=[controversy_id])] #pass the controversy id.

Django better join

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)

How to call a a field of one model A into another model B so that b can work as a view

I have created a model called Department, Course. Models are as follow
This is the model for departments and course
class Departments(models.Model):
Department_Id = models.IntegerField(primary_key=True)
Department_Name = models.CharField(max_length=200)
Department_Code = models.CharField(max_length=200)
class Course(models.Model):
Course_Id = models.IntegerField(primary_key=True)
Department_Id = models.ForeignKey(Departments, on_delete=models.CASCADE)
Course_Name = models.CharField(max_length=200)
Course_Code = models.CharField(max_length=200)
I want to create a model called view which can be later on called for search. I want a view model in a such a way that it consit of the data in concat form i.e. name= Department_name+ Course_Name
class View (models.model):
view_id= models.IntegerField(primary_key=True)
Name= Department_name(I want this from Departments table)
+ Course_Name(I want this from Course table)
I try using one to one relation . I would really appricate the help
It's not clear why you'd want to do that. It's never a good idea to duplicate data from one model into another one, as it can lead to inconsistencies.
You can add a ForeignKey in View to your Course model and then when you do f"{view.course.name} {view.course.department.name}" you already have your string:
class View(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
def name(self):
return f"{self.course.name} {self.course.department.name}"
Notes:
Don't call your foreign key Department_id because it's not referring to the id but to the object itself in the Django ORM: department = models.ForeignKey(Department, on_delete=models.CASCADE). As you can see, this makes reading the code much simpler: self.course.Department_id is a Department object not an integer, so self.course.department makes more sense.
Don't prefix your field names with the class, it just makes the code so much less readable: Do you prefer department.name or department.Department_name?
The View model is still a mystery to me, as you can search without it. You can search for example for courses with a matching department name like this:
Course.objects.filter(department__name__icontains="maths")
which will return all courses with "maths" in their department name.
Remove all the ids from your models, they are created automatically by Django anyway (and called id). Again, department.id is much easier to read than department.Department_id. Also in your code, you have to generate the ids yourself since you don't set them to auto-populate.

Manytomany django using existing key

I hope this is not a duplicate question. I am trying to setup models in django.
In model 1 I have one kind items (parts), these can together form item type 2 (car).
I get the prices for all of these from outside interface to a model prices.
How can I setup the relationship between price - > part and price - > car.
I do not know when I get the prices if the ident belongs to car och part.
class parts(models.Model):
ident = models.CharField("IDENT", max_length = 12, unique = True, primary_key = True)
name = models.CharField(max_length=30)
class car(models.Model):
ident = models.CharField("IDENT", max_length = 12, unique = True)
start_date = models.DateField()
end_date = models.DateField()
parts= models.ManyToManyField(parts)
class Prices(models.Model):
ident= models.CharField(max_length=12)
price = models.DecimalField(max_digits=10, decimal_places= 4)
date = models.DateField()
def __unicode__(self):
return self.ident
class Meta:
unique_together = (("ident", "date"),)
I would imagine you would not store price in your model since you need this to be 100% real time. So you have;
car models.py
from parts.models import parts
name = models.CharField(max_length=100)
parts = models.ManyToManyField(parts)
Hopefully you're not trying to develop like a full scale autozone type deal, but if it's simply a car model object that is comprised of many parts than this is the basic setup you would want. having the many to many relationship to parts allows one car to have many parts. parts can belong to many cars. You don't have to specify a manytomany relationship in the parts model as the two way communication will already be handled in your cars model.
As far as price is concerned you could have a price database field in your parts model, but once again if this needs to be real time, you probably want to request that price via an api and display it directly in your webpage.