I'm defining my Django models right now and I realized that there wasn't a OneToManyField
in the model field types. I'm sure there's a way to do this, so I'm not sure what I'm missing. I essentially have something like this:
class Dude(models.Model):
numbers = models.OneToManyField('PhoneNumber')
class PhoneNumber(models.Model):
number = models.CharField()
In this case, each Dude
can have multiple PhoneNumber
s, but the relationship should be unidirectional, in that I don't need to know from the PhoneNumber
which Dude
owns it, per se, as I might have many different objects that own PhoneNumber
instances, such as a Business
for example:
class Business(models.Model):
numbers = models.OneToManyField('PhoneNumber')
What would I replace OneToManyField
(which doesn't exist) with in the model to represent this kind of relationship? I'm coming from Hibernate/JPA where declaring a one-to-many relationship was as easy as:
@OneToMany
private List<PhoneNumber> phoneNumbers;
How can I express this in Django?
This question is related to
django
django-models
If the "many" model does not justify the creation of a model per-se (not the case here, but it might benefits other people), another alternative would be to rely on specific PostgreSQL data types, via the Django Contrib package
Postgres can deal with Array or JSON data types, and this may be a nice workaround to handle One-To-Many when the many-ies can only be tied to a single entity of the one.
Postgres allows you to access single elements of the array, which means that queries can be really fast, and avoid application-level overheads. And of course, Django implements a cool API to leverage this feature.
It obviously has the disadvantage of not being portable to others database backend, but I thougt it still worth mentionning.
Hope it may help some people looking for ideas.
In Django, a one-to-many relationship is called ForeignKey. It only works in one direction, however, so rather than having a number
attribute of class Dude
you will need
class Dude(models.Model):
...
class PhoneNumber(models.Model):
dude = models.ForeignKey(Dude)
Many models can have a ForeignKey
to one other model, so it would be valid to have a second attribute of PhoneNumber
such that
class Business(models.Model):
...
class Dude(models.Model):
...
class PhoneNumber(models.Model):
dude = models.ForeignKey(Dude)
business = models.ForeignKey(Business)
You can access the PhoneNumber
s for a Dude
object d
with d.phonenumber_set.objects.all()
, and then do similarly for a Business
object.
You can use either foreign key on many side of OneToMany
relation (i.e. ManyToOne
relation) or use ManyToMany
(on any side) with unique constraint.
django
is smart enough. Actually we don't need to define oneToMany
field. It will be automatically generated by django
for you :-). We only need to define foreignKey
in related table. In other words, we only need to define ManyToOne
relation by using foreignKey
.
class Car(models.Model):
// wheels = models.oneToMany() to get wheels of this car [**it is not required to define**].
class Wheel(models.Model):
car = models.ForeignKey(Car, on_delete=models.CASCADE)
if we want to get the list of wheels of particular car. we will use python's
auto generated object wheel_set
. For car c
you will use c.wheel_set.all()
01) one-to-many relationship:
ASSUME:
class Business(models.Model):
name = models.CharField(max_length=200)
.........
.........
phone_number = models.OneToMany(PhoneNumber) (NB: Django do not support OneToMany relationship)
class Dude(models.Model):
name = models.CharField(max_length=200)
.........
.........
phone_number = models.OneToMany(PhoneNumber) (NB: Django do not support OneToMany relationship)
class PhoneNumber(models.Model):
number = models.CharField(max_length=20)
........
........
NB: Django doesn't provides any OneToMany relationship. So we can't use upper method in Django. But we need to convert in relational model. So what can we do? In this situation we need to convert relational model into reverse relational model.
Here:
relational model = OneToMany
So, reverse relational model = ManyToOne
NB: Django support ManyToOne relationship & in Django ManyToOne is represented by ForeignKey.
02) many-to-one relationship:
SOLVE:
class Business(models.Model):
.........
.........
class Dude(models.Model):
.........
.........
class PhoneNumber(models.Model):
........
........
business = models.ForeignKey(Business)
dude = models.ForeignKey(Dude)
NB: THINK SIMPLY!!
While rolling stone's answer is good, straightforward and functional, I think there are two things it does not solve.
Introduce the content types framework, which exposes some objects that allow us to create a "generic foreign key" on the PhoneNumber model. Then, we can define the reverse relationship on Dude and Business
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.db import models
class PhoneNumber(models.Model):
number = models.CharField()
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
owner = GenericForeignKey()
class Dude(models.Model):
numbers = GenericRelation(PhoneNumber)
class Business(models.Model):
numbers = GenericRelation(PhoneNumber)
See the docs for details, and perhaps check out this article for a quick tutorial.
Also, here is an article that argues against the use of Generic FKs.
To be more clear - there's no OneToMany in Django, only ManyToOne - which is Foreignkey described above. You can describe OneToMany relation using Foreignkey but that is very inexpressively.
A good article about it: https://amir.rachum.com/blog/2013/06/15/a-case-for-a-onetomany-relationship-in-django/
Source: Stackoverflow.com