What’s the difference between django OneToOneField and ForeignKey?
What's the difference between django OneToOneField and ForeignKey?
Be careful to realize that there are some differences between
ForeignKey(SomeModel, unique=True). As stated in The Definitive Guide to Django:
A one-to-one relationship. Conceptually, this is similar to a
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
For example, if we have the following two models (full model code below):
python manage.py shell execute the following:
>>> from testapp.models import Car, Engine >>> c = Car.objects.get(name='Audi') >>> e = Engine.objects.get(name='Diesel') >>> e.car <Car: Audi>
>>> from testapp.models import Car2, Engine2 >>> c2 = Car2.objects.get(name='Mazda') >>> e2 = Engine2.objects.get(name='Wankel') >>> e2.car2_set.all() [<Car2: Mazda>]
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
A ForeignKey is for one-to-many, so a Car object might have many Wheels, each Wheel having a ForeignKey to the Car it belongs to. A OneToOneField would be like an Engine, where a Car object can have one and only one.
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
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
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 : from thepub.models import Reporter, Article In : R1 = Reporter(first_name='Rick') In : R1.save()
Create the Article object A1.
In : A1 = Article.objects.create(title='TDD In Django', reporter=R1) In : A1.save()
Then use the following piece of code to get the name of the reporter.
In : A1.reporter.first_name Out: 'Rick'
Now create the Reporter object R2 by running the following python code.
In : R2 = Reporter.objects.create(first_name='Harry') In : R2.save()
Now try to add R2 to the Article object A1.
In : 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 : A2 = Article.objects.create(title='Python News', reporter=R1) In : R1.article_set.all() Out: [<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
OneToOneField (one-to-one) realizes, in object orientation, the notion of composition, while ForeignKey (one-to-many) relates to agregation.
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.
OneToOneField is useful to be used as primary key to avoid key duplication. One may do not have implicit / explicit autofield
OneToOneField as primary key instead (imagine
UserProfile model for example):
user = models.OneToOneField( User, null=False, primary_key=True, verbose_name='Member profile')
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.
ForeignKey allows you receive subclasses is it definition of another class but OneToOneFields cannot do this and it is not attachable to multiple variables
- Database Administration Tutorials
- Programming Tutorials & IT News
- Linux & DevOps World
- Entertainment & General News
- Games & eSport