I need an OneToMany-Relationship because I want to store Recipes. To do that I have two Models one is the Recipe and the other is the ingredient. When googling for this topic I always found using a foreign-key but I am not sure if its that what I am looking for. I wanted to test it but I found nowhere how to use this relationship.
The Models:
class Ingredient(models.Model):
ingredient_title = models.CharField(max_length=120)
amount = models.IntegerField()
unit = models.CharField(max_length= 10)
class Recipe(models.Model):
title = models.CharField(max_length=120)
ingredients = models.ForeignKey(Ingredient,on_delete=models.CASCADE) `#Here I am not sure if its right`
preperation = models.TextField(default='Here comes the preperation...')
I tried creating a recipe model but on the admin page I could select just one ingredient and in the shell, I didn't know how to do that.
Here is what I tried:
Recipe.objects.create(title='Essen1',ingredients=[(ingredient_title="ZutatTitel1",amount=2,unit='g'),(ingredient_title="ZutatTitel1",amount=2,unit='g')],preperation='prep1'))
you need to use ManytoMany Field. A recipe can have many ingredients.
class Recipe(models.Model):
title = models.CharField(max_length=120)
ingredients = models.ManyToManyField(Ingredient)
preperation = models.TextField(default='Here comes the preperation...')
recipe_obj = Recipe.objects.create(title='Essen1)
recipe_obj.ingredients.add(ingredient_obj1)
recipe_obj.ingredients.add(ingredient_obj2)
As Neeraj said you need ManyToManyField instead of ForeignKey. This is because one ingredient can have (or belong to) many recipes and one recipe can have many ingredients. ForeignKey is used for many-to-one relationships - for example, one author might have many books but if each book has only one author then it would be a many-to-one relationship so ForeignKey. If however each book also had many authors then it would be a many-to-many relationship (one book has many authors and one author has many books).
Related
I have models defined as follow:
class Employee(models.Model):
...
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
class Project(models.Model):
...
employees = models.ManyToManyField(Employee, null=True, blank=True)
I'm trying to retrieve all the projects that have at least one employee assigned to them, but I don't know how. I tried the following things:
projects.filter(employees__gt=0)
where projects = Project.objects.all() but I don't think this is the right query, because if I do projects.filter(employees_lte=0) it returns nothing, even if I have projects with no employees assigned. How can I retrieve what I'm looking for? Could you point to a page where I can find all the lookups I can use?
Thanks!
You can try like this using isnull:
Project.objects.filter(employees__isnull=False)
Update
If you want to check specific number of employees, maybe try like this
from django.db.models import Count
Project.objects.annotate(employee_count=Count('employees')).filter(employee_count__gt=5)
I know this is a very basic question. I am learning django and i see the most important part is ForeignKey field and ManyToManyField. They are used ubiquitously. Without understanding those two, a proper model cannot be designed. If i have to design a model with FK relation, i always have to see the example first and try to come with the solution. I cannot confidently design a model cause i have not understand this well. It would be great if someone make me understand so that the picture comes to my head what is FKField, how FKField and MTMField are generated in table with simple english(Language is one of the barrier for me to understand from the documentation).
Here is the model for foreign key
class Category(models.Model):
name = models.CharField()
class Product(models.Model):
name = models.CharField()
category = models.ForeignKeyField(Category, related_name="product")
In django, you can add one instance of a "variable" as a part of a table: That is a ForeignKey.
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=30)
category = models.ForeignKey(Category)
class Category(models.Model):
name = models.CharField(max_length=30)
Here, you will have a SQL table named "[NAME OF YOUR APP]_product" that will have two columns: "name" and "category_id".
You will have an other table named "[NAME OF YOUR APP]_category" that will contain one column "name".
Django will know that when you load a Product, it will have to get its category_id, and then get that element from the category table.
This is because you use a foreignkey: it is one "variable". And it is "Many to One" because you can have many Products having the same Category.
Then you have "Many to Many". Here you can have more than one "variable"
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=30)
category = models.ManyToManyField(Category)
class Category(models.Model):
name = models.CharField(max_length=30)
Here, the difference is that you will get a table named "[NAME OF YOUR APP]_product" with only one column: "name".
Next to that, you will have a table "[NAME OF YOUR APP]_product_category", that will have the columns "product_id" and "category_id".
And one last table that will be "[NAME OF YOUR APP]_category" that will have one column: "name".
The way it works is that Django will get the Product, and see that it have a ManyToMany field of Category.
It will go to "[NAME OF YOUR APP]_product_category" and get the list of ids for the product_id you need, and get them from "[NAME OF YOUR APP]_category".
This is Many to Many because you can have a lot of Products that have each lots of different Category.
If you still don't understand, I will edit this post to add a SQL example of what the database looks like.
(Sorry, this is not really pleasant to read and a really broad way to explain how Django handle things, but I tried to do short and simple statements.)
I have a semi complex model relationship in my django app.
I have a Group (a business) which can have many locations
So
A group can have many providers (person) as well. The thing is, the Provider is connected to a particular group through the group location. That is to say a provider can have that location. In reality, i believe a provider can have many locations (belonging to multiple groups). The way I have this in my django so far which I don't think correct is this way:
class GroupLocations(models.Model):
address_id = models.ForeignKey(Address, on_delete= models.SET_NULL)
group_id = models.ForeignKey(Group, on_delete=models.SET_NULL)
doing_business_as = models.CharField(max_length = 255)
created_at=models.DateField(auto_now=false, auto_now_add=true)
updated_at=models.DateField(auto_now=true, auto_now_add=true)
class ProviderLocations(models.Model):
provider_id = models.ForeignKey(Provider, on_delete=models.CASCADE)
group_location_id = models.ForeignKey(GroupLocations, on_delete=models.CASCADE)
created_at=models.DateField(auto_now=false, auto_now_add=true)
updated_at=models.DateField(auto_now=true, auto_now_add=true)
My question is, does my Group (and/or Provider) model need to have some sort of relationship specified in their model definitions?
class Group(models.Model):
group_name = models.CharField(max_length=50)
group_contact= models.CharField(max_length=50)
#do I need something like the following:
providers = models.ManyToMany(Provider, through='ProviderLocations')
provider_locations = models.ManyToMany(Group, through='GroupLocations'
class Provider(models.Model):
created_at=models.DateField(auto_now=false, auto_now_add=true)
updated_at=models.DateField(auto_now=true, auto_now_add=true)
groups = models.ManyToManyField(Group, through='GroupLocations')
group_locations = models.ManyToMany(GroupLocations, through='ProviderLocations')
This is so i can get a list of groups from a provider, and the groups locations
and I can get a list of providers from a group and the providers locations.Actually more like the locations join which to which. I am still learning Django'ss relationship systems so any constructive criticism of how to make these relationships work well together would be helpful.
My question is, does my Group (and/or Provider) model need to have
some sort of relationship specified in their model definitions?
Yes a many to many relationship. And you only need to define it for one model or the other because many to many can be traversed in both direction.
Both ends of a many-to-many relationship get automatic API access to
the other end. The API works just as a “backward” one-to-many
relationship, above.
The only difference is in the attribute naming: The model that defines
the ManyToManyField uses the attribute name of that field itself,
whereas the “reverse” model uses the lowercased model name of the
original model, plus '_set' (just like reverse one-to-many
relationships).
Source: https://docs.djangoproject.com/en/dev/topics/db/queries/#many-to-many-relationships
Thus your models can be simplified.
class Group(models.Model):
group_name = models.CharField(max_length=50)
group_contact= models.CharField(max_length=50)
providers = models.ManyToMany(Provider, through='ProviderLocations')
class Provider(models.Model):
created_at=models.DateField(auto_now=false, auto_now_add=true)
updated_at=models.DateField(auto_now=true, auto_now_add=true)
I am not quite sure why you are trying to create both a GroupLocation and ProviderLocation model. I do believe they can be merged.
I've a Django model
class Person(models.Model):
name = models.CharField(max_length=50)
team = models.ForeignKey(Team)
And a team model
class Team(models.Model):
name = models.CharField(max_length=50)
Then, I would like to add a 'coach' property which is a one to one relationship to person. If I am not wrong, I have two ways of doing it.
The first approach would be adding the field to Team:
class Team(models.Model):
name = models.CharField(max_length=50)
coach = models.OneToOneField(Person, related_name='master')
The second one would be creating a new model:
class TeamCoach(models.Model):
team = models.OneToOneField(Team)
coach = models.OneToOneField(Person)
Is this right ? is there a big difference for practical purposes ? which are the pro and cons of each approach ?
I will say NEITHER, as every Person has a Team and if every Team has a Coach, it's rather redundant circulation and somewhat unnecessary.
Better to add a field in Person called type directly is more clean and direct, something like:
class Person(models.Model):
# use _ if you care about i18n
TYPES = ('member', 'member',
'coach', 'coach',)
name = models.CharField(max_length=50)
team = models.ForeignKey(Team)
type = models.CharField(max_length=20, choices=TYPES)
Although I would seriously consider refactoring Person to be more generic and get Team to have a ManyToMany to Person... in that case, you can re-use Person in other areas, like Cheerleaders.
class Person(models.Model):
# use _ if you care about i18n
TYPES = ('member', 'member',
'coach', 'coach',)
name = models.CharField(max_length=50)
type = models.CharField(max_length=20, choices=TYPES)
class Team(models.Model):
name = models.CharField(max_length=50)
member = models.ManyToManyField(Person, related_name='master')
Make your models more generic and DRY, they should be easily manageable and not tightly coupled to certain fields (unless absolutely necessary), then the models are more future proof and will not fall under migration nightmare that easily.
Hope this helps.
I can't agree so easy with #Anzel, and since the name of the question is
What are the benefits of having two models instead of one?
I'll try to give my two cents. But before i start i want to place some quotes from the docs.
It doesn’t matter which model has the ManyToManyField, but you should
only put it in one of the models – not both.
Generally, ManyToManyField instances should go in the object that’s
going to be edited on a form. In the above example, toppings is in
Pizza (rather than Topping having a pizzas ManyToManyField ) because
it’s more natural to think about a pizza having toppings than a
topping being on multiple pizzas. The way it’s set up above, the Pizza
form would let users select the toppings.
Basically that's the first thing you should have in mind when creating a M2M relation (your TeamCoach model is that, but more on that in a second) which one is the object holding the relation. What would be more suitable for your problem - choosing a coach for a team when you create it, or choosing a team for a person when you create it? IF you ask me i would prefer the second variant and keep the teams inside of the Person class.
Now lets go to the next section of the docs
Extra fields on many-to-many relationships
When you’re only dealing with simple many-to-many relationships such
as mixing and matching pizzas and toppings, a standard ManyToManyField
is all you need. However, sometimes you may need to associate data
with the relationship between two models.
For example, consider the case of an application tracking the musical
groups which musicians belong to. There is a many-to-many relationship
between a person and the groups of which they are a member, so you
could use a ManyToManyField to represent this relationship. However,
there is a lot of detail about the membership that you might want to
collect, such as the date at which the person joined the group.
For these situations, Django allows you to specify the model that will
be used to govern the many-to-many relationship. You can then put
extra fields on the intermediate model. The intermediate model is
associated with the ManyToManyField using the through argument to
point to the model that will act as an intermediary.
That's actually the answer of your question, having an intermediate model give you the ability to store additional data about the collection. Consider the situation where a coach moves to another team next season, if you just update the M2M relation, you will loose the track of his past teams where he was coaching. Or you will never be able to answer the question who was the coach of that team at year XXX. So if you need more data, go with intermediate model. This is also were #Anzel going wrong, the type field is an additional data of that intermediate model, it's place must be inside it.
Now here is how i would probably create the relations:
class Person(models.Model):
name = models.CharField(max_length=50)
teams = models.ManyToManyField('Team', through='TeamRole')
class Team(models.Model):
name = models.CharField(max_length=50)
class TeamRole(models.Model):
COACH = 1
PLAYER = 2
CHEERLEADER = 3
ROLES = (
(COACH, 'Coach'),
(PLAYER, 'Player'),
(CHEERLEADER, 'Cheerleader'),
)
team = models.ForeignKey(Team)
person = models.ForeignKey(Person)
role = models.IntegerField(choices=ROLES)
date_joined = models.DateField()
date_left = models.DateField(blank=True, null=True, default=None)
How will I query this? Well, I can use the role to get what type of persons I'm looking for, and I can also use the date_left field to get the current persons participating in that team right now. Here are a few example methods:
class Person(models.Model):
#...
def get_current_team(self):
return self.teams.filter(teamrole__date_left__isnull=True).get()
class Team(models.Model):
#...
def _get_persons_by_role(self, role, only_active):
persons = self.person_set.filter(teamrole__role=role)
if only_active:
return persons.filter(teamrole__date_left__isnull=True)
return persons
def get_coaches(self, only_active=True):
return self._get_persons_by_role(TeamRole.COACH, only_active)
def get_players(self, only_active=True):
return self._get_persons_by_role(TeamRole.PLAYER, only_active)
I'm trying to work out the most django-reffic way to do the following:
Models
class Warehouse(models.Model):
name = models.CharField()
class Product(models.Model):
name = models.CharField()
class ProductStock(models.Model):
product = models.ForeignKey(Product)
warehouse = models.ForeignKey(Warehouse)
qty = models.IntegerField()
What would be the best way to build the forms on the product page knowing that I need to enter the stock for each warehouse?
I know I could just grab the warehouses and iterate over them and build a qty field input then iterate over that on submission, but is there a better way?
Cheers,
Ben
Modelformsets should do the trick. In particular, look into inline modelformsets and inlineformset_factory. They are one of my favourite things in Django, but also a big gnarly if you're a newcomer to the framework.