OneToOneField() vs ForeignKey() in Django
Asked Answered
R

12

562

What's the difference between Django OneToOneField and ForeignKey?

Rempe answered 3/5, 2011 at 13:54 Comment(0)
G
663

Differences between OneToOneField(SomeModel) and ForeignKey(SomeModel, unique=True) as stated in The Definitive Guide to Django:

OneToOneField

A one-to-one relationship. Conceptually, this is similar to a ForeignKey with unique=True, but the "reverse" side of the relation will directly return a single object.

In contrast to the OneToOneField "reverse" relation, a ForeignKey "reverse" relation returns a QuerySet.

Example

For example, if we have the following two models (full model code below):

  1. Car model uses OneToOneField(Engine)
  2. Car2 model uses ForeignKey(Engine2, unique=True)

From within python manage.py shell execute the following:

OneToOneField Example

>>> from testapp.models import Car, Engine
>>> c = Car.objects.get(name='Audi')
>>> e = Engine.objects.get(name='Diesel')
>>> e.car
<Car: Audi>

ForeignKey with unique=True Example

>>> from testapp.models import Car2, Engine2
>>> c2 = Car2.objects.get(name='Mazda')
>>> e2 = Engine2.objects.get(name='Wankel')
>>> e2.car2_set.all()
[<Car2: Mazda>]

Model Code

from django.db import models

class Engine(models.Model):
    name = models.CharField(max_length=25)

    def __unicode__(self):
        return self.name

class Car(models.Model):
    name = models.CharField(max_length=25)
    engine = models.OneToOneField(Engine)

    def __unicode__(self):
        return self.name

class Engine2(models.Model):
    name = models.CharField(max_length=25)

    def __unicode__(self):
        return self.name

class Car2(models.Model):
    name = models.CharField(max_length=25)
    engine = models.ForeignKey(Engine2, unique=True, on_delete=models.CASCADE)

    def __unicode__(self):
        return self.name
Gallice answered 5/5, 2011 at 1:57 Comment(9)
@MarkPNeyer: as far as I understand, a OneToOne field is just that: one-to-one. It does not have to be onto. See this example: a place does not have to be a restaurant.Scoggins
This answer says "there are some differences", and then names one difference. Are there others?Overbold
I'm wondering the same as Chris. Is it simply syntactic sugar, is there some underlying difference in how the data is accessed, leading to performance differences?Dust
Is there a fundamental reason why Django couldn't have a rule such that if the foreign key is unique and not null, then e.car also works?Orleans
So...when would one even want to use a ForeignKey with unique=True rather than a OneToOneField? I see in other questions that Django even warns that a OneToOneField usually best serve's one's interests. The reverse QuerySet will never have more than one element, right?Methodical
@Methodical Another difference, and one reason to use a ForeignKey is to avoid errors when accessing the reverse relation. In the example above engine_instance.car can raise a RelatedObjectDoesNotExist exception, whereas engine2_instance.car_set will at worst return an empty query set. To keep my model queries consistent, I prefer using engine = models.ForeignKey(Engine2, unique=True, related_name='car'. Then the only difference when making queries is between xxx.filter(...).all() for many-to-one/many-to-many, and xxx.filter().first() for one-to-one.Schoolhouse
By your description it seems like functionally OneToOne and ForeignKeyFields are exactly the same in that they can be used to accomplish the exact same tasks in any situation, which isn't true. The functionally important difference between the two is that many foreign keys from different objects may map to a single object, whereas with OneToOne it is illegal for multiple objects to map to a single object. This answer misses that point completely, and it's really the only important thing you need to understand to choose which one to use... If you set unique=true they are functionally identical.Thomasina
I have a model abc which has a field name MJ and this field is a OneToOneField to another Model xyz. Now the issue is I want to display only the data containing in abc and not from the xyz Model but it is fetching data from xyz and not abc. How should I filter in this scenario?Fellowship
Great answer. A small note: OneToOneField also requires an on_delete parameter.Grasmere
M
185

A ForeignKey is a many-to-one relationship. So, a Car object might have many instances of Wheel. Each Wheel would consequently have a ForeignKey to the Car it belongs to. A OneToOneField would be like an instance of Engine, where a Car object has at most one and only one.

Mayolamayon answered 3/5, 2011 at 13:58 Comment(7)
thank you, Dose OneToOneField(someModel) mean ForeignKey(SomeModel, unique=True)?Rempe
Yes: 'A OneToOneField is essentially the same as a ForeignKey, with the exception that always carries a "unique" constraint with it and the reverse relation always returns the object pointed to (since there will only ever be one), rather than returning a list.'Mayolamayon
What about several cars having the same engine?Prizefight
@OlegTikhonov They might have a copy of the same engine design, but I'd like the see an instance where several cars are sharing the same physical engine.Mayolamayon
There is a little confusion about the terms in this answer. ForeignKey is not a one-to-many but it is a many-to-one relationship according to official django documentation: docs.djangoproject.com/en/2.0/ref/models/fields/…Godesberg
OneToOneField(user, primary_key=True) why primary key = true in django document?????????????????Rigi
@DanBreen can you give a code example of this, please..? How will the Wheel, Engine, and Car model look like?Stinkwood
P
72

The best and the most effective way to learn new things is to see and study real world practical examples. Suppose for a moment that you want to build a blog in django where reporters can write and publish news articles. The owner of the online newspaper wants to allow each of his reporters to publish as many articles as they want, but does not want different reporters to work on the same article. This means that when readers go and read an article they will se only one author in the article.

For example: Article by John, Article by Harry, Article by Rick. You can not have Article by Harry & Rick because the boss does not want two or more authors to work on the same article.

How can we solve this 'problem' with the help of django? The key to the solution of this problem is the django ForeignKey.

The following is the full code which can be used to implement the idea of our boss.

from django.db import models

# Create your models here.

class Reporter(models.Model):
    first_name = models.CharField(max_length=30)

    def __unicode__(self):
        return self.first_name


class Article(models.Model):
    title = models.CharField(max_length=100)
    reporter = models.ForeignKey(Reporter)

    def __unicode__(self):
        return self.title

Run python manage.py syncdb to execute the sql code and build the tables for your app in your database. Then use python manage.py shell to open a python shell.

Create the Reporter object R1.

In [49]: from thepub.models import Reporter, Article

In [50]: R1 = Reporter(first_name='Rick')

In [51]: R1.save()

Create the Article object A1.

In [5]: A1 = Article.objects.create(title='TDD In Django', reporter=R1)

In [6]: A1.save()

Then use the following piece of code to get the name of the reporter.

In [8]: A1.reporter.first_name
Out[8]: 'Rick'

Now create the Reporter object R2 by running the following python code.

In [9]: R2 = Reporter.objects.create(first_name='Harry')

In [10]: R2.save()

Now try to add R2 to the Article object A1.

In [13]: A1.reporter.add(R2)

It does not work and you will get an AttributeError saying 'Reporter' object has no attribute 'add'.

As you can see an Article object can not be related to more than one Reporter object.

What about R1? Can we attach more than one Article objects to it?

In [14]: A2 = Article.objects.create(title='Python News', reporter=R1)

In [15]: R1.article_set.all()
Out[15]: [<Article: Python News>, <Article: TDD In Django>]

This practical example shows us that django ForeignKey is used to define many-to-one relationships.

OneToOneField is used to create one-to-one relationships.

We can use reporter = models.OneToOneField(Reporter) in the above models.py file but it is not going to be useful in our example as an author will not be able to post more than one article.

Each time you want to post a new article you will have to create a new Reporter object. This is time consuming, isn't it?

I highly recommend to try the example with the OneToOneField and realize the difference. I am pretty sure that after this example you will completly know the difference between django OneToOneField and django ForeignKey.

Porterporterage answered 14/11, 2014 at 19:29 Comment(1)
I like this. The fundamental difference between OneToOne and ForeignKey is one to one and one to many relationship. You could use ForeignKey and unique=True to do one-to-one, the subtle difference is stated in Matthew's reply.Merola
W
16

OneToOneField (one-to-one) realizes, in object orientation, the notion of composition, while ForeignKey (one-to-many) relates to agregation.

Woolcott answered 27/4, 2012 at 21:42 Comment(1)
Nice analogy, but it's not always like that. There are some edge cases which don't fit into this explanation. Let's say for example we have classes Patient and Organ. Patient can have many Organs, but an Organ can belong to only one Patient. When Patient is deleted, all Organs are deleted too. They can't exist without a Patient.Chronologist
P
8

Also OneToOneField is useful to be used as primary key to avoid key duplication. One may do not have implicit / explicit autofield

models.AutoField(primary_key=True)

but use OneToOneField as primary key instead (imagine UserProfile model for example):

user = models.OneToOneField(
    User, null=False, primary_key=True, verbose_name='Member profile')
Pelaga answered 17/11, 2015 at 12:54 Comment(0)
G
7

I have also been confused with the usage of both the fields. Let me give an example for understanding their usage, as I have faced the problem recently and realised the usage of both the fields.

I had a model, like this-

from django.contrib.auth.models import User
from django.db import models


class Attendance(models.Model):
     user = models.OneToOneField(User, on_delete=models.CASCADE, default="", null=True)
     date = models.CharField(max_length=11)

     def __int__(self):
         return self.id

Now the problem with this was that I can't make multiple objects with the same user, i.e. a same user will have attendance on multiple days. Hence, multiple objects with same user.

But the OneToOne field didn't let me do that. Image for reference

So, I changed my model to-

from django.contrib.auth.models import User
from django.db import models


class Attendance(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, default="", null=True)
    date = models.CharField(max_length=11)

    def __int__(self):
        return self.id

Now it works fine and I can mark attendance for a user on multiple days.

So that's where the difference is, OneToOne field will not allow you to make multiple objects with the same user(as an example) but with ForeignKey it is possible.

Graphology answered 26/6, 2021 at 8:15 Comment(0)
N
6

When you access a OneToOneField you get the value of the field you queried. In this example a book model's 'title' field is a OneToOneField:

>>> from mysite.books.models import Book
>>> b = Book.objects.get(id=50)
>>> b.title
u'The Django Book'

When you access a ForeignKey you get the related model object, which you can then preform further queries against. In this example the same book model's 'publisher' field is a ForeignKey (correlating to the Publisher class model definition):

>>> b = Book.objects.get(id=50)
>>> b.publisher
<Publisher: Apress Publishing>
>>> b.publisher.website
u'http://www.apress.com/'

With ForeignKey fields queries work the other way too, but they're slightly different due to the non-symmetrical nature of the relationship.

>>> p = Publisher.objects.get(name='Apress Publishing')
>>> p.book_set.all()
[<Book: The Django Book>, <Book: Dive Into Python>, ...]

Behind the scenes, book_set is just a QuerySet and can be filtered and sliced like any other QuerySet. The attribute name book_set is generated by appending the lower case model name to _set.

Nagana answered 12/2, 2014 at 18:59 Comment(0)
M
2

OneToOneField: if second table is related with

table2_col1 = models.OneToOneField(table1,on_delete=models.CASCADE, related_name='table1_id')

table2 will contains only one record corresponding to table1's pk value, i.e table2_col1 will have unique value equal to pk of table

table2_col1 == models.ForeignKey(table1, on_delete=models.CASCADE, related_name='table1_id')

table2 may contains more than one record corresponding to table1's pk value.

Magnetostriction answered 28/3, 2019 at 11:2 Comment(0)
S
2

The easiest way to draw a relationship between items is by understanding them in plain languages. Example

A user can have many cars but then a car can have just one owner. After establishing this, the foreign key should be used on the item with the many relationship. In this case the car. Meaning you'll include user as a foreign key in cars

And a one on one relationship is quite simple. Say a man and a heart. A man has only one heart and a heart can belong to just one man

Saturant answered 14/7, 2020 at 22:8 Comment(2)
So where do you set the OneToOne field for the human heart example ? Do you set a OneToOne field in the Hearth class pointing to the Human model or a OneToOne field in the Human model posting to the Heart model? TelI me if I'm wrong but I guess it's better to put the OneToOne field in the Heart model and set it as primary key right?Conform
@PaulBénéteau you set the key in the child model... a heart model can't stand on it's own... so it becomes the child of the user model. So yes you're rightSaturant
D
2

OneToOneField (Example: one car has one owner) ForeignKey(OneToMany) (Example: one restaurant has many items)

Dampier answered 27/1, 2021 at 11:32 Comment(1)
OneToOneField (Example: one restaurant has one item). ForeignKey (Example: one restaurant has many items). ManyToManyField (Example: Many McDonald's has many same items). McDonald's Has Happy Meal, Big Mac Etc. Big Mac is in many different McDonald's restaurants.Chrysoberyl
A
0

ForeignKey allows you receive subclasses is it definition of another class but OneToOneFields cannot do this and it is not attachable to multiple variables

Accipiter answered 29/9, 2019 at 6:57 Comment(0)
L
0

OneToOneField() cannot access the child model with _set while ForeignKey() and ManyToManyField() can. *You can see my question and the answer about it.

For example, you have Person model and PersonDetail model with OneToOneField() as shown below:

class Person(models.Model):
    name = models.CharField(max_length=20)

class PersonDetail(models.Model):
    person = models.OneToOneField(Person, on_delete=models.CASCADE)
    age = models.IntegerField()
    gender = models.CharField(max_length=20)

Then, you cannot access the child model PersonDetail with persondetail_set of a Person object as shown below because there is error. *Use persondetail instead of persondetail_set to access the child model PersonDetail in this case of OneToOneField():

obj = Person.objects.get(id=1)
print(obj.persondetail_set.get(id=1)) # Error
        # ↑ ↑ ↑ Here ↑ ↑ ↑

Now, you use ForeignKey() and ManyToManyField() as shown below:

class PersonDetail(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    # ...
class PersonDetail(models.Model):
    person = models.ManyToManyField(Person)
    # ...

Then, you can access the child model PersonDetail with persondetail_set of a Person object as shown below:

obj = Person.objects.get(id=1)
print(obj.persondetail_set.get(id=1)) # PersonDetail object (1)
        # ↑ ↑ ↑ Here ↑ ↑ ↑
Laval answered 21/7, 2023 at 17:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.