Reputation: 197
I am a bit confused how Django handles '_id' property when we use ORM with some models that use foreign key. For example:
class CartItem(models.Model):
user = models.ForeignKey('accounts.CustomUser', related_name='carts', on_delete=models.CASCADE, verbose_name='User')
product = models.ForeignKey('pizza.Product', related_name='carts', on_delete=models.CASCADE, verbose_name=_('Product'))
quantity = models.SmallIntegerField(verbose_name=_('Quantity'))
And when I use ORM with 'filter' I can easily use something like:
CartItem.objects.filter(user=1, product=1, quantity=1)
And Django kind of 'see' that I refer to 'id', but when I use exacly the same line of code, but with 'create' instead of 'filter':
CartItem.objects.create(user=1, product=1, quantity=1)
Then it throws an error saying:
Cannot assign "1": "CartItem.user" must be a "CustomUser" instance.
And to create it I need to use:
CartItem.objects.create(user_id=1, product_id=1, quantity=1)
Why is that? Is there some rule here that I don't understand?
Upvotes: 6
Views: 5313
Reputation: 476574
This is the database representation of the ForeignKey
[Django-doc]. A reference to model object is represented as:
Behind the scenes, Django appends
"_id"
to the field name to create its database column name. In the above example, the database table for theCar
model will have amanufacturer_id
column. (You can change this explicitly by specifyingdb_column
) However, your code should never have to deal with the database column name, unless you write custom SQL. You’ll always deal with the field names of your model object.
So you could say that Django will construct a "twin" column, with an _id
suffix. This column has the same type as the type of the primary key of the model you target, and that column will thus contain the primary key of the model object you use. Note that you can use a different field to which you target by specifying the to_field=…
parameter [Django-doc].
The ForeignKey
itself thus does not exists at the database, that is the logic of Django that will use the primary of that object, and store that in a column with, by default, an _id
suffix.
Upvotes: 4