I'm new to Django, so I apologize a head of time if my verbiage is off. But I'll try my best!
I have two models :
PlayerProfile - this is updated once a day.
PlayerListing - this is updated every 5 minutes.
Here are simplified versions of those models.
class PlayerProfile(models.Model):
listings_id = models.CharField(max_length=120)
card_id = models.CharField(max_length=120)
first_name = models.CharField(max_length=120)
last_name = models.CharField(max_length=120)
overall = models.IntegerField()
class PlayerListing(models.Model):
listings_id = models.CharField(max_length=120, unique=True)
buy = models.IntegerField()
sell = models.IntegerField()
Currently, we just make queries based on the matching listings_id - but I'd like to have a more traditional relationship setup if possible.
How do you relate two models that have the same value for a specific field (in this case, the listings_id)?
Some potentially relevant information:
Data for both models is brought in from an external API, processed and then saved to the database.
Each PlayerListing relates to a single PlayerProfile. But not every PlayerProfile will have a PlayerListing.
When we create PlayerListings (every 5 minutes), we don't necessarily have access to the correct PlayerProfile model. listings_id's are generated last (as we have to do some extra logic to make sure they're correct).
Related
I have a website with different kinds of activities:
Lessons ;
Exercises ;
Quizzes.
So far, each type of activity corresponds to a specific Model and a table in the database. I would like to create an ordered path through these activities. For instance:
Lesson 1
then Exercise 1
then Lesson 2
then Quizz 1
etc.
I am considering to create a model named Activity that would store the following data:
A number: the number of the activity in the path ;
A One-To-One relationship to one given activity (lesson, exercise, quizz etc.).
(1) I have seen that Django offers a GenericForeignKey to handle many-to-one relationship to different kinds of models, like many comments associated to a single lesson or a single exercise. Is there something similar for Generic OneToOne relationship?
(2) I would like to track the progress of my users. To do so, I am considering having a many-to-many relationship called "done_activities" built in my User model and linked to my Activity model. Do you think this is an efficient way of approaching the problem ?
I'm not sure you would need or want self-referential fields in this case. Consider the following structure as an example. I do not propose this 'in stone' as THE solution, but more to spur your own ideas about the solution you need. Please note that I'm leaving out __str__ methods and such for brevity:
ACTIVITY_TYPE = ['Lesson', 'Exercise', 'Quiz']
class Activity(models.Model):
activity_name = models.CharField(max_length=200, blank=True)
activity_type = models.CharField(max_length=100, choices=ACTIVITY_TYPE, blank=True, db_index=True)
activity_desc = models.CharField(max_length=200, blank=True) #description of the lesson, exercise, or quiz
class Program(models.Model):
program_name = models.CharField(max_length=200, blank=True, db_index=True)
description = models.Charfield(max_length=200, blank=True)
class ProgramActivity(models.Model):
program = models.ForeignKey(Program, on_delete=models.CASCADE, your args etc...)
activity = models.ForeignKey(Activity, on_delete=models.CASCADE, your args here etc...)
path_order = models.PositiveSmallIntegerField() # stores a number for the order in the program path
class UserProgram(models.Model):
student = models.ForeignKey(User, etc...) # FK to the user
program = models.ForeignKey(Program, etc...) # connects users to programs
progress = models.DecimalField(max_digits=5, decimal_places=2) # stores percentage of program completed (for example)
In this schema scenario, the following are true:
Activitys are all tracked and stored together on a single table,
organized by type, and each one can have its own description.
Programs are stored on their own model, and
represent a named object that unites all their constituent activities.
ProgramActivity connects activities to specific programs, and
allows you to set the order in the path for that activity relative to the program, and change it easily if you have to. You can easily query activities = ProgramActivity.objects.filter(program=some_program).order_by('path_order') and get a very usable list of a Program's activities.
Finally the UserProgram model records a User's "enrollments" and
progress in each, in this example, by percentage of the program completed.
This is just one possible approach. You may, for example, want to create an activity type table instead of a list dropdown, which may be a more robust way of managing activities over time.
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.
I want to know the most efficient way for structuring and designing a database with several relations. I will explain my problem with a toy example which is scaled up in my current situation
Here are the Models in the Django database
1.) Employee Master (biggest table with several columns and rows)
class Emp_Mast():
emp_mast_id = models.AutoField(primary_key=True)
first_name = models.CharField(max_length=50)
middle_name = models.CharField(max_length=50, blank=True)
last_name = models.CharField(max_length=50, blank=True)
desgn_mast = models.ForeignKey("hr.Desgn_Mast", on_delete=models.SET_NULL, null=True)
qual_mast = models.ForeignKey("hr.Qualification_Mast", on_delete=models.SET_NULL, null=True)
office_mast = models.ManyToManyField("company_setup.Office_Mast", ref_mast = models.ForeignKey("hr.Reference_Mast", on_delete=models.SET_NULL, null=True)
refernce_mast = models.ForeignKey("hr.Refernce_Mast", on_delete=models.SET_NULL, null=True)
This is how the data is displayed in frontend
2.) All the relational field in the Employee Master have their corresponding models
3.) Crw_Movement_Transaction
Now I need to create a table for Transaction Data that that stores each and every movement of the employees. We have several Offshore sites that the employees need to travel to and daily about 50 rows would be added to this Transaction Table called Crw_Movement_Transaction
The Crw_Movement Table will have a few additional columns of calculations of itself and rest of the columns will be static (data would not be changed from here) and will be from the employee_master such as desgn_mast, souring_mast (so not all the fields from emp_mast either)
One way to do this is just define a Nested Relation for Emp_Mast in the serializer for Crw_Movement and optimize it using select_related and prefetch_related to reduce the queries to the database. However that is still very slow, as any number of queries to Emp_Mast are unnecessary. Would it be better design to just store the fields from Emp_Mast in Crw_Movement and update them when Emp_Mast is updated as well. If yes, what is a good way of doing that. Or should I stick to using Nested Serializer?
Some background
I am considering rebuilding an existing Laravel website with Django. It's a website that allows sharing benchmark data from drone/UAV propulsion components. Some benchmarks are done while testing multiple motors and propellers at the same time, which means a battery would be under the load of multiple motors, but it also means the airflow from one propeller has an impact on the data captured on the other propeller. This means the data is physically coupled. Here is an example. Right now I am trying to structure this project to allow upcoming features, and to see if Django ORM is a good fit.
Simplified Django models
class Benchmark(models.Model):
title = models.CharField()
private = models.BooleanField(default=False)
hide_torque = models.BooleanField(default=False)
class AbstractComponent(models.Model):
brand = models.CharField()
name = models.CharField()
class Meta:
abstract = True
class Motor(AbstractComponent):
shaft_diameter_mm = models.FloatField()
class Propeller(AbstractComponent):
diameter_in = models.FloatField()
class Battery(AbstractComponent):
capacity_kwh = models.FloatField()
class Powertrain(models.Model):
benchmark = models.ForeignKey(Benchmark, on_delete=models.CASCADE, related_name='powertrains')
motor = models.ForeignKey(Motor, on_delete=models.CASCADE)
propeller = models.ForeignKey(Propeller, on_delete=models.CASCADE, blank=True, null=True)
battery = models.ForeignKey(Battery, on_delete=models.CASCADE, blank=True, null=True)
class DerivedDataManager(models.Manager):
def get_queryset(self):
return super().get_queryset()\
.annotate(electrical_power_w=F('voltage_v') * F('current_a'))\
.annotate(mechanical_power_w=F('torque_nm') * F('rotation_speed_rad_per_s'))\
.annotate(motor_efficiency=F('mechanical_power_w') / F('electrical_power_w'))
class DataSample(models.Model):
powertrain = models.ForeignKey(Powertrain, on_delete=models.CASCADE, related_name='data')
time_s = models.FloatField()
voltage_v = models.FloatField(blank=True, null=True)
current_a = models.FloatField(blank=True, null=True)
rotation_speed_rad_per_s = models.FloatField(blank=True, null=True)
torque_nm = models.FloatField(blank=True, null=True)
thrust_n = models.FloatField(blank=True, null=True)
objects = models.Manager()
derived = DerivedDataManager()
class Meta:
constraints = [
models.UniqueConstraint(fields=['powertrain', 'time_s'], name='unique temporal sample')
]
Question
I was able to add "derived" measurements, like electrical_power_w to each row of the data, but I have no clue on how can I add derived measurements that combines the data of multiple drive trains within the same benchmark:
Assuming 3 powertrains, each with their own voltage and current data, how can I do:
Total_power = powertrain1.power + powertrain2.power + powertrain3.power
for each individual timestamp (time_s)? A total power is only meaningul if the Sum is made on simultaneously taken samples.
Goal
Without loading all the database data in Django, I would eventually want to get the 5 top benchmarks in terms of maximum total power, taking into account some business logic:
benchmarks marked as private are automatically excluded (until auth comes in)
benchmarks that opt to hide the torque automatically make the torque data, along as all the derived mechanical power and motor efficiency values go to None.
I would like to recreate this table, but with extra columns appended, like 'maximum thrust', etc... This table is paginated from within the database itself.
Hmmmm, this is quite a tricky one to navigate. I am going to start by adding the following annotation model method:
from django.db.models import Sum
I guess then it would be a case of adding:
.annotate(total_power=Sum(electrical_power_w))
But I think the issue is that each row in your DerivedDataManager queryset represents one DataSample which in turn links to one Powertrain via the ForeignKey field.
It would be better to do this in the business logic layer, grouping by the powertrain's UUID (you need to add this to your Powertrain model - see https://docs.djangoproject.com/en/3.0/ref/models/fields/#uuidfield for details of how to use this. Then, because you have grouped by, you can then apply the Sum annotation to the queryset.
So, I think you want to navigate down this path:
DataSample.objects.order_by(
'powertrain'
).aggregate(
total_price=Sum('electrical_power_w')
)
I've searched around for a while, but can't seem to find an existing question for this (although it could be an issue of not knowing terminology).
I'm new to Django, and have been attempting to take a design which should be very expandable over time, and make it work with Django's ORM. Essentially, it's a series of many-to-many relationships using a shared junction table.
The design is a generic game crafting system, which says "if you meet [require], you can create [reward] using [cost] as materials." This allows items to be sold from any number of shops using the same system, and is generic enough to support a wide range of mechanics - I've seen it used successfully in the past.
Django doesn't support multiple M2M relationships sharing the same junction table (apparently since it has no way to work out the reverse relationship), so I seem to have these options:
Let it create its own junction tables, which ends up being six or more, or
Use foreign keys to the junction table in place of a built-in MTM relationship.
The first option is a bit of a mess, since I know I'll eventually have to add additional fields into the junction tables. The second option works pretty well. Unfortunately, because there is no foreign key from the junction table BACK to each of the other tables, I'm constantly fighting the admin system to get it to do what I want.
Here are the affected models:
class Craft(models.Model):
name = models.CharField(max_length=30)
description = models.CharField(max_length=300, blank=True)
cost = models.ForeignKey('Container', related_name="craft_cost")
reward = models.ForeignKey('Container', related_name="craft_reward")
require = models.ForeignKey('Container', related_name="craft_require")
class ShopContent(models.Model):
shopId = models.ForeignKey(Shop)
cost = models.ForeignKey('Container', related_name="shop_cost")
reward = models.ForeignKey('Container', related_name="shop_reward")
require = models.ForeignKey('Container', related_name="shop_require")
description = models.CharField(max_length=300)
class Container(models.Model):
name = models.CharField(max_length=30)
class ContainerContent(models.Model):
containerId = models.ForeignKey(Container, verbose_name="Container")
itemId = models.ForeignKey(Item, verbose_name="Item")
itemMin = models.PositiveSmallIntegerField(verbose_name=u"min amount")
itemMax = models.PositiveSmallIntegerField(verbose_name=u"max amount")
weight = models.PositiveSmallIntegerField(null=True, blank=True)
optionGroup = models.PositiveSmallIntegerField(null=True, blank=True,
verbose_name=u"option group")
Is there a simpler, likely obvious way to get this working? I'm attempting to allow inline editing of ContainerContent information from each related column on the Craft edit interface.
It sounds like you have a sort of "Transaction" that has a name, description, and type, and defines a cost, reward, and requirement. You should define that as a single model, not multiple ones (ShopContent, Craft, etc.).
class Transaction(models.Model):
TYPE_CHOICES = (('Craft', 0),
('Purchase', 1),
)
name = models.CharField(max_length=30)
description = models.CharField(max_length=300, blank=True)
cost = models.ForeignKey('Container')
reward = models.ForeignKey('Container')
require = models.ForeignKey('Container')
type = models.IntegerField(choices = TYPE_CHOICES)
Now Shop etc. can have a single ManyToManyField to Transaction.
Whether or not you use this particular model, the cost, reward and require relationships should all be in one place -- as above, or in OneToOne relationships with Craft, ShopContent etc. As you guessed, you shouldn't have a whole bunch of complex Many-To-Many through tables that are all really the same.
You mention at the bottom of your post that you're
attempting to allow inline editing of ContainerContent information from each related column on the Craft edit interface.
If you're modeling several levels of relationship, and using the admin app, you'll need to either apply some sort of nested inline patch, or use some sort of linking scheme like the one I use in my recent question, How do I add a link from the Django admin page of one object to the admin page of a related object?
I am smelling something is too complicated here, but I might be wrong. As a start,
is this any better? (ContainerContent will be figured out later)
class Cost(models.Model):
name = models.CharField(max_length=30)
class Reward(models.Model):
name = models.CharField(max_length=30)
class Require(models.Model):
name = models.CharField(max_length=30)
class Craft(models.Model):
name = models.CharField(max_length=30)
description = models.CharField(max_length=300, blank=True)
cost = models.ForeignKey(Cost)
reward = models.ForeignKey(Reward)
require = models.ForeignKey(Require)
class Shop(models.Model):
name = models.CharField(max_length=30)
crafts = models.ManyToMany(Craft, blank=True)