Represent a Mixture with a Django Model - django

I'm trying to represent a mixture in Django. Something like:
Chemical #1 - 50%
Chemical #2 - 30%
Chemical #3 - 20%
I figured I would use a wrapper called composition as follows:
class Composition(models.Model):
""" Just a Wrapper """
def save(...):
#Validate ingredients add up to 100% and such
class Ingredient(models.Model):
composition = models.ForeignKey('Composition',related_name='ingredients')
name = models.CharField(max_length = 10)
percentage = models.IntegerField()
I'm pretty sure there's a better way to do this. Keep in mind that I'm doing it like this so I can later use inlines in the Django admin. What do you guys recommend? Thanks a lot =)

It seems to me as though it would be preferable to keep a list of ingredients then reference those when you create your compositions, rather than entering the ingredient names each time. You could do it using a many to many relationship and a through table, like so:
class Ingredient(models.Model):
name = models.CharField(max_length=10)
class Composition(models.Model):
name = models.CharField(max_length=255)
ingredients = models.ManyToManyField(Ingredient, through='CompositionIngredient')
def save(...):
#Validate ingredients add up to 100% and such
class CompositionIngredient(models.Model):
composition = models.ForeignKey(Composition)
ingredient = models.ForeignKey(Ingredient)
proportion = models.DecimalField()
See the Django docs for more information.
EDIT: Here's the documentation on how to deal with through tables in the admin interface.

Related

Where and how put my business logic in django

A friend recommended that I read the book two scoops Django and I was amazed at the recommendations he makes for a robust and well-designed Django project. This reading created a doubt in me and it is where I put the business logic, I give an example. Suppose I have two models:
models.py
class Sparks(models.Model):
flavor = models.CharField(max_length=100)
quantity = models.IntegerField(default=0)
class Frozen(models.Model):
flavor = models.CharField(max_length=100)
has_cone = models.BooleanField()
quantity_sparks = models.IntegerField(default=0)
Let's suppose that every time I add a frozen, if it has sparks, I have to subtract it from the Sparks model and check that there is an available quantity. In the book they recommend putting this logic in models.py or forms.py. If create some model required modify data from another model where should I do it?
Your data model is lacking, that's the likely source of uneasiness.
class Flavor(models.Model):
name = models.CharField(max_length=100)
class Sparks(model.Model):
flavor = models.ForeignKeyField(Flavor, on_delete=models.CASCADE)
quantity = models.IntegerField(default=0)
class Frozen(model.Model):
# This maybe should be a OneToOne, can't tell from your description.
sparks = models.ForeignKeyField(Sparks)
has_cone = models.BooleanField()
Then you'd do
frozen_instance = Frozen.objects.get()
frozen.sparks.quantity # This has replaced frozen_instance.quantity_sparks

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.

Django - Model with more than two foreign keys

I want to give a classification to every recipe and I need 3 levels (subject -> category -> subcategory). I have the following models:
class Recipe(models.Model):
content = HTMLField()
...
class Subject(models.Model):
name = models.CharField()
class Category(models.Model):
subject = models.ForeignKey(Subject)
name = models.CharField()
class Subcategory(models.Model):
category = models.ForeignKey(Category)
name = models.CharField()
Initially I was thinking to add a ForeignKey to the Recipe model, something like:
subcategory = models.ForeignKey(Subcategory)
So I could be able to go from the subcategory to the subject, doing a simple join.
But maybe is better to create a new table to improve performance and to have a scalable system, this is my thought:
class Classification(models.Model):
recipe = models.ForeignKey(Recipe)
subject = models.ForeignKey(Subject)
category = models.ForeignKey(Category)
subcategory = models.ForeignKey(Subcategory)
Using this last solution, I want to select the subcategory from the Recipe admin panel and then automatically fill the other fields (category and subject). My question is: how can I do that?
Thank you!
Your first design is actually the best. It is a completely denormalized database design. The second design has the possibility of putting your recipe in a subcategory unrelated to your category which is unrelated to your subject. So, what you gain in performance might be lost in data integrity.
The classes Subject, Category, Subcategory and Recipe (with ForeignKey) creates fully normalized database design adding Classification is a part of denormalizing database (for example for performance issues).
Answering your question:
recipe = Recipe.objects.get(pk=1) # just assume that you have object instance under recipe
r_subcategory = recipe.subcategory
r_category = r_subcategory.category
r_subject = r_category.subject
new_classification = Classification(subject=r_subject, category=r_category, subcategory=r_subcategory, recipe=recipe)
new_classification.save()
I would really like to know if there is a way to create it in one database request (I could easily produce sql request for that, but I do not know how to achieve the same with Django ORM)

Django: Editing a manytomany model field referenced by another model through a form

I am trying to create a model instance that includes a list of model via many-to-many field via ModelForm. However when this occurs, I need to be able to change one of the fields being referenced.
Here is the stripped code:
class AllAtt(models.Model):
weighting = models.IntegerField(null=True,blank=True)
mass = models.IntegerField(null=True,blank=True)
required_Power = models.IntegerField(null=True,blank=True)
memory = models.IntegerField(null=True,blank=True)
class Mission(AllAtt):
name = models.CharField(max_length=50)
def __unicode__(self):
return self.name
class Scenario(models.Model):
name = models.CharField(max_length=50)
creation_date = models.DateTimeField(default=datetime.now)
creator = models.ForeignKey(User,null=True,blank=True)
mission = models.ManyToManyField(Mission)
def __unicode__(self):
return self.name
class ScenarioForm(ModelForm):
class Meta:
model = Scenario
fields = ('name','mission',)
Where the Missions instances are imported from a database. Currently this allows me to pick Mission instances from the multiplechoicefield, however this isn't what I need. I want to be able to include all of the Mission instances in the Scenario and then change the "weighting" field through the form.
A simple example of what I am trying to do:
I have a certain number of tasks (Missions) and when combined they accomplish something (Scenario).
A human has a lot of task functions. If my Scenario is "Getting ready for a date" then these functions may be weighted in importance as:
Make coffee - 0, Feed dog -2, Shower - 3, Get dressed - 5. Whereas if the Scenario is "Working on Django code" these functions are weighted as: Make coffee - 5, Feed dog - 2, Shower - 0, Get dressed - 1. And each time I make a new Scenario I need to be able to change the weights of all the possible tasks.
Any help or insight on how to accomplish this would be greatly appreciated. Thanks!
As I understand you need to specify weight on Mission relations in Scenario.
Basically what you need is through Model (with weight). You can see it documented here: https://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany