Hay guys, I'm writing a simple app which logs recipes.
I'm working out my models and have stumbled across a problem
My Dish models needs to have many Ingredients. This is no problem because i would do something like this
ingredients = models.ManyToManyfield(Ingredient)
No problems, my dish now can have many ingrendients.
However, the problem is that the ingredient needs to come in different quantities.
I.E 4 eggs, 7 tablespoons sugar
My Ingredient Model is very simple at the moment
class Ingredient(models.Model):
name = models.TextField(blank=False)
slug = models.SlugField(blank=True)
How would i go about work out this problem? What fields would i need to add, would i need to use a 'through' attribute on my ManyToManyfield to solve this problem?
I think you got the right answer with a "through" table ( http://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany )
Model
class Recipe(models.Model):
name = models.TextField(blank=False)
ingredients = models.ManyToManyField(Ingredient, through='Components')
class Ingredient(models.Model):
name = models.TextField(blank=False)
slug = models.SlugField(blank=True)
class Components(models.Model):
recipe = models.ForeignKey(Recipe)
ingredient = models.ForeignKey(Ingredient)
quantity = models.DecimalField()
You can put unit of quantity (gram, kilo, tablespoon, etc) on Ingredient level, but I think it is better on Ingredients level (for example you can have 1 recipe with 10 Cl of milk but one other with 1L ... So "different" units for a same ingredient.
Data Creation
By Dish you mean Recipe right ? If you have a look to previous link (http://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany), they give you a good example (based on the beatles).
Basically :
1.Create a Recipe:
cake=Recipe.objects.create(name="Simple Cake")
2.Create several Ingredient (if they doesn't already exist from a previous recipe ;)):
egg = Ingredient.objects.create(name="Egg")
milk = Ingredient.objects.create(name="milk")
3.Create the relationship:
cake_ing1 = Components.objects.create(recipe=cake, ingredient=egg,quantity = 2)
cake_ing2 = Components.objects.create(recipe=cake, ingredient=milk,quantity = 200)
and so on. Plus, I'm now quite sure that unit should go to Components level, with a default unit as "piece" (that would be for yours eggs ...), and would be something like "mL" for milk.
Data Access
In order to get ingredients (Components) of a recipe just do :
cake = Recipe.objects.get(name = "Simple Cake")
components_cake = Components.objects.get(recipe = cake)
Related
I am trying to figure out the best method to add multiple instances of the same field for a Recipe class I have created.
When creating the new Recipe, I need to be able to add multiple instances of Ingredient, Measurement Unit, Unit Value. For example:
ingredient = Lemon
measurement_unit = ml
unit_value = 100
I would then need to add another Ingredient and do the exact same thing. I would then be able to save the Recipe.
What would be the best method to use to achieve this?
UPDATE
Got loads of great suggestions, but perhaps I'm not understanding the context or I'm not explaining things correctly - I am talking specifically about a form repeater - see here: https://themesbrand.com/skote-django/layouts/form-repeater.html?
I want to be able to add another row that would allow me to save multiple instances of ingredients.
The section should look something like this:
Form Repeater
I would create a model for Ingredient and then set a many to many relationship between ingredients and recipes.
Like This:
class Ingredient(models.Model):
name = models.CharField(max_length=150, unique=True)
measurement_unit = models.CharField(max_length=150, unique=True)
unit_value = models.IntegerField()
recipe = models.ManyToManyField(Recipe)
Then from any recipe you could access all the ingredients.
I don't know about the best, but the obvious one is a RecipeIngredient model.
This is a bit more complex than Scrolen's suggestion, but allows multiple recipes to use different amounts of the same ingredient. This becomes useful if there is a fair bit of information you need to attach to an ingredient. Things like supplier, sub-ingredients, allergens, nutritional info, ... you can edit the ingredient, and all the recipes that use it immediately have updated ingredient information.
class Recipe( models.Model):
name = models.CharField( ...)
status = models.CharField( choices = STATUS_CHOICES, ...)
...
class Ingredient( models.Model):
name = models.CharField( unique=True, ...)
...
class RecipeIngredient( models.Model):
recipe = models.ForeignKey( Recipe, models.PROTECT, related_name='ingredients', ...)
ingredient = models.ForeignKey( Ingredient, models.PROTECT, ...)
unit = models.CharField( choices=UNIT_CHOICES, ...)
value = models.FloatField( ...)
usage:
recipe = Recipe( name = 'Lemon Cheesecake', status=Recipe.ON_HOLD )
recipe.save()
# ON_HOLD stops anybody using a recipe only half populated with ingredients
ingredient = Ingredient.objects.get( name='lemon juice')
item = RecipeIngredient(
ingredient=ingredient,
recipe = recipe,
unit='ml',
value=100 )
item.save()
# repeat until all the ingredients are attached to the recipe
# and other stuff such as instructions are also filled in
recipe.status = Recipe.READY
recipe.save()
# now it's ready for somebody to try to cook it!
To get the list:
recipe = Recipe.objects.get( name = 'Lemon Cheesecake')
for item in recipe.ingerdients.all():
item.ingredient.field ... # refers to data in the related Ingredient
item.unit
item.value
I'm doing the CS50 Web programming course, learning to use Django. The learning exercise basically has you recreating this pizza restaurant menu with django.
I've created some models for the data, and now I'm trying to use Django templating to create a menu page for the pizzas.
Here are my models:
from django.db import models
class intToppings(models.Model):
name = models.CharField(max_length=16)
intToppings = models.IntegerField() # 0 Cheese, 1/2/3, 5 Special
def __str__(self):
return f"{self.name}"
class Size(models.Model):
size = models.CharField(max_length=16)
def __str__(self):
return f"{self.size}"
class PizzaBase(models.Model):
base = models.CharField(max_length=16)
def __str__(self):
return f"{self.base}"
class Toppings(models.Model):
topping = models.CharField(max_length=32)
def __str__(self):
return f"{self.topping}"
class Pizza(models.Model):
size = models.ForeignKey(Size, on_delete=models.CASCADE) # CASCADE will delete all Regular Pizzas if their size is deleted (as opposed to .SET_NULL)
base = models.ForeignKey(PizzaBase, on_delete=models.CASCADE)
intToppings = models.ForeignKey(intToppings, on_delete=models.CASCADE)
price = models.IntegerField() # price in cents
def __str__(self):
return f"{self.size} {self.base} {self.intToppings} Pizza"
There's an entry "small" and "large" in the Size db, and for intToppings there is one entry with name "cheese" and an int of 0, another for "1 topping" with an int of 1, etc.
And for the Pizza model, I made an entry for every combo on the menu, ie:
<QuerySet [<Pizza: small Regular Cheese Pizza>, <Pizza: small Regular 1 Topping Pizza>, <Pizza: small Regular 2 Toppings Pizza>, ...
... <Pizza: large Sicilian 2 Toppings Pizza>, <Pizza: large Sicilian 3 Toppings Pizza>, <Pizza: large Sicilian Special Pizza>]>
On my views.py, I can't really pass that whole data set to the django template because it's not sensible/possible to loop through it to create an html table. (my html table is identical to the one on their website, one table for regular pizza, one for sicilian.)
I'm trying to solve this issue by first constructing a list/array or dict object that will pass data to the django template in a structure that is easy to loop through. And to do this I want to query the Pizza model.
Essentially, all I'm looking to do is (pseudo code: SELECT Pizza WHERE size="small" base="Regular", intToppings=0 and get the price for that pizza.
I don't seem to be able to query the foreign keys though;
Pizza.objects.all().filter(price=1220)
works but isn't what I need. What I need is;
p = Pizza.objects.all().filter(base="Regular", size="small", intToppings=0)
print(p.price)
which doesn't work.
Have you tried to use the field names of the related models? Like this:
p = Pizza.objects.filter(
base__base="Regular",
size__size="small",
intToppings__intToppings=0)
print(p)
Like the docs say,
you first access the related model (say base) and then you access the field of that related model (__base) and compare that to the string you want, resulting in base__base='something'.
Maybe you even could rename the field PizzaBase.base to PizzaBase.name to make it less confusing.
Try this:
p = Pizza.objects.filter(
base__base = "Regular",
size__size = "small",
intToppings_id = 0,
)
Note that I changed intToppings to intToppings_id. If you need to filter by a foreign key, you can pass in the intToppings object, or you can add _id to the end of the column name and simply insert the pk value.
Let's say I have an app that's supposed to allow (fashion designers) to post a "Design with Customizations"
The wanted result in the template is like this :
Dress:
Please select material : 1- wool, 2-cotton, 3-cashmere (only one can be selected)
What colours would you like : black $10, blue, red, yellow (multiple selections)
I'd like to allow designers to add options with choices and decide if (customers) can select one choice (radio button group) or multiple choices (checkboxes) with extra charge and decide default ones...
** Models.py **
class Choice(models.Model):
# e.g red
name = models.CharField(max_length=500)
extra_charge = models.DecimalField(default=0, max_digits=10, decimal_places=2)
class Option(models.Model):
# what colours?
name = models.CharField(max_length=500)
choice = models.ForeignKey(Choice)
class Dress(models.Model):
options = models.ManyToManyField(Choice, related_name='Dress')
name = models.CharField(max_length=500)
price = models.DecimalField(max_digits=10, decimal_places=2)
I have been working on Django for a while now but I have no idea how to go about this....
According to my idea, Your Dress Model should not have an option field, also, you should create a foreign key called dress # related to Dress Model in your Option Model.
Each time when you need designers to add an option with choices, just show him the form page created from Option Model, I think this is your solution!
here is the deal, this is my model:
class Health_plan(models.Model):
a = models.IntegerField ()
b = models.IntegerField ()
c = models.IntegerField ()
class Doctors_list(models.Model):
specialty = models.CharField(max_length=15)
name = models.CharField(max_length=30)
hp_id = models.ManyToManyField(Health_plan)
location = models.CharField(max_length=15)
def __unicode__(self):
return self.name
So, i have a table named Doctors_list, a doctor has one specialty, one location, one name, and a list of health plans covered.
To manage this, i have a table with the health plans on the columns (a,b,c). The doctors are identified in this list by their id, and the rows contain 1 or 0, 1 for health plan covered, 0 for not covered. like this:
ID A B C
1 0 0 1
2 1 0 0
3 1 0 1
Is there a better way to make this relation???
The user first chooses the specialty, my form:
class SpecForm(ModelForm):
a = Doctors_list.objects.values_list('specialty', flat=True)
unique = [('---------------','---------------')] + [(i,i) for i in set(a)]
specialty = forms.ChoiceField(choices=unique)
class Meta:
model = Doctors_list
The big thing is: a smart select for the relation specialty/health_plans.
The user chooses the specialty.
The specialty is covered by one or more doctors.
I use those doctor(s) id, and go check on health_plan table wich plans are available.
The user select's the plan.
I will keep researching but any tip is gratefully welcomed.
I hope i made myself clear.
What you describe is a misuse of the ManyToMany relation.
If you want to create a many-to-many relation between A and B, all you have to do is add a ManyToMany field in the definion of one of the models (A or B) and django will take care of the rest. Specifically, it will create a 3rd table where it will store the associations in the form of (A.id, B.id). This is standard rational database procedure for this type of relations, and Django is implementing it.
See http://en.wikipedia.org/wiki/Junction_table for the general definition of a many to many relation.
https://docs.djangoproject.com/en/1.5/ref/models/fields/#manytomanyfield - for the Django implementation.
I currently have a set of models that look similar to this contrived code:
class Pizza(models.Model):
price = models.FloatField()
topping = models.ManyToManyField(Topping, through="PizzaToppings")
class Topping(models.Model):
name = models.CharField(max_length=50)
class PizzaToppings(models.Model):
class Meta:
ordering=["order_to_add_topping"]
pizza = models.ForeignKey(Pizza)
topping = models.ForeignKey(Topping)
order_to_add_topping = models.IntegerField()
My problem is that what happens when I attempt to access the toppings of a pizza in the order specified in the PizzaToppings ManyToMany extra fields table. Assume the pizza has cheese and ham, with the order_to_add_topping in the PizzaToppings data set to 0 and 1 respectively:
>>> pizza = Pizza.objects.get(pk=490)
>>> pizza.toppings.all()[0].name
'Ham'
That should say 'Cheese'. I would have thought the RelationManager would have respected the ordering Meta class field, but it appears it doesn't. So I guess accessing the name of the first topping added to the pizza shouldn't be done with pizza.toppings.all()[0].name.
How should it be accessed? Is the problem with my model query or is it how I have my models set up?
Your model is fine you just need to query the relationship since now you have a "through" relationship with extra fields. The relationship is created automatically as topping_relationship in your case, so your query should be:
pizza.toppings.order_by('topping_relationship__order_to_add_topping')