660👍
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
withunique=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):
Car
model usesOneToOneField(Engine)
Car2
model usesForeignKey(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
183👍
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.
- [Django]-Suddenly when running tests I get "TypeError: 'NoneType' object is not iterable
- [Django]-How to change User representation in Django Admin when used as Foreign Key?
- [Django]-What is a "django backend"?
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
.
- [Django]-Django REST Framework – 405 METHOD NOT ALLOWED using SimpleRouter
- [Django]-What is the difference between cached_property in Django vs. Python's functools?
- [Django]-Django Template Language: Using a for loop with else
16👍
OneToOneField (one-to-one) realizes, in object orientation, the notion of composition, while ForeignKey (one-to-many) relates to agregation.
- [Django]-Sending an SMS to a Cellphone using Django
- [Django]-Django: how save bytes object to models.FileField?
- [Django]-Name '_' is not defined
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')
- [Django]-Import data from excel spreadsheet to django model
- [Django]-Django url tag multiple parameters
- [Django]-Django count RawQuerySet
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.
- [Django]-How to use pdb.set_trace() in a Django unittest?
- [Django]-How do I run tests for all my Django apps only?
- [Django]-How can I handle Exceptions raised by dango-social-auth?
6👍
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.
- [Django]-How can I access environment variables directly in a Django template?
- [Django]-Are Django SECRET_KEY's per instance or per app?
- [Django]-Django-way for building a "News Feed" / "Status update" / "Activity Stream"
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.
- [Django]-How do you use the django-filter package with a list of parameters?
- [Django]-How to show processing animation / spinner during ajax request?
- [Django]-Create a field whose value is a calculation of other fields' values
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
- [Django]-Django switching, for a block of code, switch the language so translations are done in one language
- [Django]-Django count RawQuerySet
- [Django]-How does one make logging color in Django/Google App Engine?
2👍
OneToOneField (Example: one car has one owner)
ForeignKey(OneToMany) (Example: one restaurant has many items)
- [Django]-Running Django with FastCGI or with mod_python
- [Django]-Best way to integrate SqlAlchemy into a Django project
- [Django]-How to test Django's UpdateView?
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
- [Django]-Set up a scheduled job?
- [Django]-How can i test for an empty queryset in Django?
- [Django]-What does error mean? : "Forbidden (Referer checking failed – no Referer.):"
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 ↑ ↑ ↑
- [Django]-How to check if ManyToMany field is not empty?
- [Django]-How do you use the django-filter package with a list of parameters?
- [Django]-New url format in Django 1.9