Difference between ForeignKey(User, unique=True) and OneToOneField [duplicate] - django

This question already has answers here:
What's the difference between django OneToOneField and ForeignKey?
(11 answers)
Closed 8 years ago.
What is different between models.ForeignKey(Modelname, unique=True) and models.OneToOneField in Django?
Where should I use models.OneToOneField and models.ForeignKey(Modelname, unique=True)?

A OneToOneField is very similar to a ForeignKey with unique=True. Unless you are doing multiple table inheritance, in which case you have to use OneToOneField, the only real difference is the api for accessing related objects.
In the Django docs it says:
Conceptually, this is similar to a ForeignKey with unique=True, but the "reverse" side of the relation will directly return a single object.
Let's show what that means with an example. Consider two models, Person and Address. We'll assume each person has a unique address.
class Person(models.Model):
name = models.CharField(max_length=50)
address = models.ForeignKey('Address', unique=True)
class Address(models.Model):
street = models.CharField(max_length=50)
If you start with a person, you can access the address easily:
address = person.address
However if you start with an address, you have to go via the person_set manager to get the person.
person = address.person_set.get() # may raise Person.DoesNotExist
Now let's replace the ForeignKey with a OneToOneField.
class Person(models.Model):
name = models.CharField(max_length=50)
address = models.OneToOneField('Address')
class Address(models.Model):
street = models.CharField(max_length=50)
If you start with a person, you can access the address in the same way:
address = person.address
And now, we can access the person from the address more easily.
person = address.person # may raise Person.DoesNotExist

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.
I hope this helps illustrate the differences between the relationships created.

Related

How to add id (instead of object) in ManyToManyField of Django model?

models.py :
class Employee(models.Model):
name = models.CharField(max_length=100)
class Department(models.Model):
name = models.CharField(max_length=100)
employee = models.ManyToManyField(Employee, null=True, blank=True)
I need to save employee ids (instead of employee object) in 'employee' ManyToManyField of 'Department' model. How to do that?
views.py:
dept = Department(name=name)
dept.save()
employee_ids = [1,2]
We can use method add (Django Docs):
Adds the specified model objects to the related object set.
dept = Department.objects.create(name=name)
dept.employee.add(*[1, 2])
Or method set(Django Docs):
Replace the set of related objects
dept.employee.set([1, 2])
Note that add(), create(), remove(), clear(), and set() all
apply database changes immediately for all types of related fields. In
other words, there is no need to call save() on either end of the
relationship.
I think this question is unclear what exactly are you trying to do ?
If you want to create a relation between department and employee on the database level django does that for you
on your current structure the relation and is like
id|department_id|user_id
--|-------------|-------
1| 3 | 2

django model query back reference filter confusion

Given the following models
class Category(models.Model):
name = models.CharField(max_length=50)
class Business(models.Model):
name = models.CharField(max_length=50)
category = models.ForeignKey(Category, related_name="businesses")
class Package(models.Model):
business_id = models.ForeignKey(Business)
status = models.CharField(max_length=50)
I have 2 following queries get list of business and categories which the packages are live:
filter_businesses = Business.objects.filter(package__status = 'live')
filter_categories = Category.objects.filter(businesses__package__status = 'live')
Now the questions is, given the related name "businesses" should be equals to category.business_set, why shouldn't the filter in first query be package_set?
Suppose you have two related models: SomeModel and SomeOtherModel, and SomeOtherModel.somemodel is a ForeignKey to SomeModel.
Given any SomeModel instance, the someothermodel_set property is a manager for the related model already filtered. For example:
>>> your_some_model_instance = SomeModel.objects.all()[0]
In this case your_some_model_instance.shomeothermodel_set is equivalent to:
>>> SomeOtherModel.objects.filter(somemodel=your_some_model_instance)
[ update ]
sorry perhaps I didn't explain my questions more clearer, it's complicated to explain... I understand that XX_set and related_name refer to the manager, what I want to ask is in the first query why not use (package_set_status = 'live') given the second working query (businesses_package__status = 'live'), it's confusing because the second query references to the manager(by related_name), but the first query is not...
The filter interface uses the convention relatedmodelname__relatedmodelfield; In your example, related_name was used to give a fancier name to the backreference, but this is not its main purpose; the purpose of the related_name parameter in ForeignKey fields is solving the ambiguity in cases where relatedmodelname clashes with an already existing field at the ForeignKey.

Should I use a seperate table instead of many to many field in Django

I needed to assign one or more categories to a list of submissions, I initially used a table with two foreign keys to accomplish this until I realized Django has a many-to-many field, however following the documentation I haven't been able to duplicate what I did with original table.
My question is : Is there a benefit to using many-to-many field instead of manually creating a relationship table? If better, are there any example on submitting and retrieving many-to-many fields with Django?
From the Django docs 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.
In short: If you have a simple relationship a Many-To_Many field is better (creates and manages the extra table for you). If you need multiple extra details then create your own model with foreign keys. So it really depends on the situation.
Update :- Examples as requested:
From the docs:
class Person(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __unicode__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
You can see through this example that membership details (date_joined and invite_reason) are kept in addition to the many-to-many relationship.
However on a simplified example from the docs:
class Topping(models.Model):
ingredient = models.CharField(max_length=128)
class Pizza(models.Model):
name = models.CharField(max_length=128)
toppings = models.ManyToManyField(Topping)
There seems no need for any extra data and hence no extra model.
Update 2 :-
An example of how to remove the relationship.
In the first example i gave you have this extra model Membership you just delete the relationship and its details like a normal model.
for membership in Membership.objects.filter(person__pk=1)
membership.delete()
Viola! easy as pie.
For the second example you need to use .remove() (or .clear() to remove all):
apple = Toppings.objects.get(pk=4)
super_pizza = Pizza.objects.get(pk=12)
super_pizza.toppings.remove(apple)
super_pizza.save()
And that one is done too!

What's the difference between django OneToOneField and ForeignKey?

What's the difference between Django OneToOneField and ForeignKey?
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):
Car model uses OneToOneField(Engine)
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
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.
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.
OneToOneField (one-to-one) realizes, in object orientation, the notion of composition, while ForeignKey (one-to-many) relates to agregation.
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')
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.
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.
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.
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
OneToOneField (Example: one car has one owner)
ForeignKey(OneToMany) (Example: one restaurant has many items)
ForeignKey allows you receive subclasses is it definition of another class but OneToOneFields cannot do this and it is not attachable to multiple variables

Access fields in Django intermediate model

I'm creating a Person Group and Membership as described in Django docs for intermediate model.
class Person(models.Model):
name = models.CharField(max_length=128)
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __unicode__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
It is possible to access the Person from a Group object with:
>>>Group.members.name
Does Django creates another query to fetch the Person?
Can I access the date_joined field from a Group object?
The thing that confuses me is that I would expect to get the Person name field with:
>>>Group.members.person.name
What happens if a Person has a field 'name' and also the intermediate model have a field 'name'.
The members field in your example is a ManyToManyField, so it's a way to access many people rather than one person.
The object that is under the members field is actually a special type of Manager, not a Person:
>>> print my_group.members
<django.db.models.fields.related.ManyRelatedManager object at 0x181f7d0>
To understand better what a Manager is, see the documentation.
To access a person's name you would do for example:
>>> for person in my_group.members.all():
>>> print person.name
You cannot access the fields in your Membership model via the Manager in the members field. To access any of the fields in it you would do:
>>> for membership in my_group.membership_set.all():
>>> print membership.date_joined
And so if you had a field called name in your Membership model, you would access it like this:
>>> for membership in my_group.membership_set.all():
>>> print membership.name
A second way to access a Person's name would be:
>>> for membership in my_group.membership_set.all():
>>> print membership.person.name
Note that membership_set is a default name for the manager pointing towards the membership, but it can be changed by specifying related_name in the corresponding foreign key. For example if the foreign key from the Membership to the Group would be defined like such:
group = models.ForeignKey(Group, related_name="group_members")
Then you would access the manager using group_members:
>>> for membership in my_group.group_members.all():
>>> print membership.name
Hope that helps a little :)
Use the manager of the membership class:
MyGroup.membership_set.all()
instead of:
MyGroup.members.all()