Django Model design for train routes - django

I would like to store multiple stations and multiple trains in my database. I was planning to have each station as one model and each train as one model.
But i would like to understand how should we store each train route in a dynamic way using the station models.
For Example, we have Stations A, B , C , D, E
And Train t1 route is A-C-B-D-E
And Train t2 route is A-B-E
So i would like to store these train route under each row of train model. Could someone help me with this?
Thanks

Something like this should work for you from a data model stand point.
class Station(models.Model):
pass
class Route(models.Model):
class Meta:
# Specify that the train and index are unique together to prevent
# any duplicate stations at the same index value at the db level.
# You'll probably want to validate this in the application logic as well.
unique_together = ('station', 'index')
station = models.ForeignKey('train.Station')
train = models.ForeignKey('train.Train')
index = models.IntegerField()
class Train(models.Model):
stations = models.ManyToManyField('train.Station', through=Route)

With your approach you think of stations as if they were all connected. For each station you could have a many2many field, that allows you to "connect" stations with each other.
You then could use three models:
Trains
Routes
Stations
Stations are connected to stations. Routes have a starting and an ending point. Trains are related to routes (since one train can run on multiple routes, or one route can transport multiple trains).
You also could programmatically calculate (graphs) how many stations which train has to take between start and goal.

Related

how to build a model on top of the other on django

I have two models
Job Position: It's the first object I create and represent a position in a company. `
Job offer: It is related to Job Position through a foreign key and represent a job offer sent out for a specific Job Position
Each job position can have multiple job offers associated as you can send multiple job offers out.
Now, the Job Position model has some data such as "Salary" that I would like each Job Offer instance to inherit automatically BUT I would also like to be able to change at the Job Offer level (after negotiations).
For example:
A jobposition is open with salary=50k
10 joboffers are sent out, each with salary 50k
After some negotiations, some joboffers are changed to salary 80k
Should joboffers have a salary field that I simply set equal to the salary jobposition when I create the object, or should I find a way to tie it initially within the model definition through some sort of foreign key but then make it flexibile?
class JobPosition(models.Model):
..
salary=models.Integer()
class JobOffer(models.Model):
position=models.ForeignKey(JobPosition, on_delete=models.CASCADE)
...
Your JobOffer models should have another field named salary as you said sometimes salary value can be different from JobPosition`
or you can some something like this:
class JobPosition(models.Model):
..
salary=models.Integer()
class JobOffer(models.Model):
position=models.ForeignKey(JobPosition, on_delete=models.CASCADE)
salary=models.Integer()
def job_position_salary(self):
return self.position.salary
...

Creating New Model Form Fields in Django Admin

I have a product model that has a manytomany relationship to a locations model. I am creating an app for my clients business that has hundreds of products and services, but each product/service have different prices base on the delivery location and can deliver to multiple locations. Right now my client delivers to 4 locations.
Solution #1
Hard code all 4 locations into the product model - this works, but is not preferred since they want to expand and hard coding more locations is just gross..
Solution #2 (current solution - code listed below)
Create a manytomany relationship to locations - this works, but is getting way out of hand having location options of varying charges an rates for - multiplied by every product....
Solution #3 - This is the help I need, if a solution exists.
I would like to build a hybrid of sort of the above two options. Id like to keep the manytomany with the location model so its easy to add locations as they grow, but once added, I would like to have an empty 'price' object that they can fill-in when adding or updating a product, yet remain assigned to that product only.
Not sure if this makes sense, so after my current code below (solution 2 above) I included a sample image to help illustrate my question. Thank you for your help.
Product Model
class Product(models.Model):
...
locations = models.ManyToManyField('Location', related_name='deliver_to')
...
Location Model
LOCATIONS = (
('Los Angeles', 'Los Angeles'),
('Orange County', 'Orange County'),
('Riverside', 'Riverside'),
('San Diego', 'San Diego')
)
class Location(models.Model):
l_title = models.CharField(
max_length=255,
choices=LOCATIONS,
verbose_name='Service Location'
)
...
Using https://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany will allow for extra fields.

Django How to retrieve relating data with hitting database much less in situation of two tables with m2m relationship

Let's say there are two tables.
#table A : Category
class Category
title = models.CharField()
#table B : Devices
class Devices
device_category = models.ManyToManyField(Category)
name = models.CharField()
If I want to see table like above.
simply I can make code using category = Category.objects.get(id=From A to E) category.devices_set.all(), then show each devices by Forloop.
but problem is that you have to query individually for A, B, C, D, E. If you have more category, it seems you need to hit database more to retrieve devices relating to each category.
I think the best way is retrieve all data from two tables at once. And then make table like above with JavaScripts.
Is there any easy way to do that without hitting database many times?
Probably prefetch-related is what you are looking for.
Pizza.objects.all().prefetch_related('toppings') now each time self.toppings.all() is called, instead of having to go to the database for the items, it will find them in a prefetched QuerySet cache that was populated in a single query.
So you can do this:
categories = Category.objects.filter(id__in=[A, B, C, D, E]).prefetch_related('devices_set')
for category in categories:
devices = category.devices_set.all()
for device in devices:
do_something

How to sort by annotated Count() in a related model in Django

I'm building a food logging database in Django and I've got a query related problem.
I've set up my models to include (among other things) a Food model connected to the User model through an M2M-field "consumer" via the Consumption model. The Food model describes food dishes and the Consumption model describes a user's consumption of Food (date, amount, etc).
class Food(models.Model):
food_name = models.CharField(max_length=30)
consumer = models.ManyToManyField("User", through=Consumption)
class Consumption(models.Model):
food = models.ForeignKey("Food")
user = models.ForeignKey("User")
I want to create a query that returns all Food objects ordered by the number of times that Food object appears in the Consumption table for that user (the number of times the user has consumed the food).
I'm trying something in the line of:
Food.objects.all().annotate(consumption_times = Count(consumer)).order_by('consumption_times')`
But this will of course count all Consumption objects related to the Food object, not just the ones associated with the user. Do I need to change my models or am I just missing something obvious in the queries?
This is a pretty time-critical operation (among other things, it's used to fill an Autocomplete field in the Frontend) and the Food table has a couple of thousand entries, so I'd rather do the sorting in the database end, rather than doing the brute force method and iterate over the results doing:
Consumption.objects.filter(food=food, user=user).count()
and then using python sort to sort them. I don't think that method would scale very well as the user base increases and I want to design the database as future proof as I can from the start.
Any ideas?
Perhaps something like this?
Food.objects.filter(consumer__user=user)\
.annotate(consumption_times=Count('consumer'))\
.order_by('consumption_times')
I am having a very similar issue. Basically, I know that the SQL query you want is:
SELECT food.*, COUNT(IF(consumption.user_id=123,TRUE,NULL)) AS consumption_times
FROM food LEFT JOIN consumption ON (food.id=consumption.food_id)
ORDER BY consumption_times;
What I wish is that you could mix aggregate functions and F expression, annotate F expressions without an aggregate function, have a richer set of operations/functions for F expressions, and have virtual fields that are basically an automatic F expression annotation. So that you could do:
Food.objects.annotate(consumption_times=Count(If(F('consumer')==user,True,None)))\
.order_by('consumtion_times')
Also, just being able more easily able to add your own complex aggregate functions would be nice, but in the meantime, here's a hack that adds an aggregate function to do this.
from django.db.models import aggregates,sql
class CountIf(sql.aggregates.Count):
sql_template = '%(function)s(IF(%(field)s=%(equals)s,TRUE,NULL))'
sql.aggregates.CountIf = CountIf
consumption_times = aggregates.Count('consumer',equals=user.id)
consumption_times.name = 'CountIf'
rows = Food.objects.annotate(consumption_times=consumption_times)\
.order_by('consumption_times')

Query for a ManytoMany Field with Through in Django

I have a models in Django that are something like this:
class Classification(models.Model):
name = models.CharField(choices=class_choices)
...
class Activity(models.Model):
name = models.CharField(max_length=300)
fee = models.ManyToManyField(Classification, through='Fee')
...
class Fee(models.Model):
activity = models.ForeignKey(Activity)
class = models.ForeignKey(Classification)
early_fee = models.IntegerField(decimal_places=2, max_digits=10)
regular_fee = models.IntegerField(decimal_places=2, max_digits=10)
The idea being that there will be a set of fees associated with each Activity and Classification pair. Classification is like Student, Staff, etc.
I know that part works right.
Then in my application, I query for a set of Activities with:
activities = Activity.objects.filter(...)
Which returns a list of activities. I need to display in my template that list of Activities with their Fees. Something like this:
Activity Name
Student Early Price - $4
Student Regular Price - $5
Staff Early Price - $6
Staff Regular Price - $8
But I don't know of an easy way to get this info without a specific get query of the Fees object for each activity/class pair.
I hoped this would work:
activity.fee.all()
But that just returns the Classification Object. Is there a way to get the Fee Object Data for the Pair via the Activities I already queried?
Or am I doing this completely wrong?
Considering michuk's tip to rename "fee" to "classification":
Default name for Fee objects on Activity model will be fee_set. So in order to get your prices, do this:
for a in Activity.objects.all():
a.fee_set.all() #gets you all fees for activity
There's one thing though, as you can see you'll end up doing 1 SELECT on each activity object for fees, there are some apps that can help with that, for example, django-batch-select does only 2 queries in this case.
First of all I think you named your field wrong. This:
fee = models.ManyToManyField(Classification, through='Fee')
should be rather that:
classifications = models.ManyToManyField(Classification, through='Fee')
as ManyToManyField refers to a list of related objects.
In general ManyToManyField, AFAIK, is only a django shortcut to enable easy fetching of all related objects (Classification in your case), with the association table being transparent to the model. What you want is the association table (Fee in your case) not being transparent.
So what I would do is to remove the ManyToManyField field from Activity and simply get all the fees related with the activity. And thenm if you need a Classification for each fee, get the Classification separately.