Using '_id' in Django - python

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?

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 the Car model will have a manufacturer_id column. (You can change this explicitly by specifying db_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.

Related

how to get only one column from a entire table using foreign key in Django

I'm working on a Django project. where I need to map the fields using foreign key.
how to add only one field instead of whole table using foreign key ?
You can implement the __str__ method to specify how it should show the Developer object:
class Developers(models.Model):
# …
def __str__(self):
return self.Developer_Name
Note: normally a Django model is given a singular name, so Developer instead of Developers.
Note: normally the name of the fields in a Django model are written in snake_case, not PascalCase, so it should be: developer_name instead of Developer_Name.

How to make a username as a foreign key of another model in django

I am very new to Django. I want to link a model which has 2 field 'username' and 'password'. I want to make 'username' field as as Foreign in another model. But as per Django we can only pass the whole Model Object, who is referring to as it's foreign key.
am I wrong somewhere? please give me any solution regarding this basic problem.
No you can link to any unique field of a Django model. So if your models look like:
class Target(models.Model):
name = models.CharField(max_length=128, unique=True)
class SourceModel(models.Model):
target = models.ForeignKey(Target, to_field='name', on_delete=models.CASCADE)
You can assign the value of the target column to the target_id then. So for example:
Target.objects.create(name='target1')
SourceModel.objects.create(target_id='target1')
So you do not need to pass a Target object itself. You can use the …_id "twin" field to use the target column value. The database will normally enforce referential integrity, and thus will prevent passing a non-existing value to the foreign key column.

Django - bulk_create objects with order_with_respect_to attribute

Hi I have list of model objects: my_objects, which should be saved in a databse.
This model has order_with_respect_to property in its Meta class.
When I try to bulk_create this list I got:
null value in column "_order" violates not-null constraint" during bulk_create
When I just iterate over elements and invoke save() on every each of them. Everything is fine, but such sequential database access doesn't satisfy me...
I've tried to invoke signals.pre_save.send function, but this didn't change the situation.
This worked when I've invoked _save_table, on every signle element from my_objects, but _save_table is the heaviest part of save() method, so I gained nothing...
Is there a possibility to save batch of django objects with only one database connection?
I'm using postgresql.
It's just a field and you can set "_order" manually or calculate that before bulk_create.
# Model
class Product(models.Model):
name = models.CharField(max_length=255)
# Bulk create example
# Data
product_data_list = [{"name": "Apple"}, {"name": "Potato"}]
# Add "_order" field for each product
for index, product_data in enumerate(product_data_list):
product_data["_order"] = index
# Create
Product.objects.bulk_create(Product(**product_data) for product_data in product_data_list)
From the docs:
https://docs.djangoproject.com/en/1.8/ref/models/querysets/#bulk-create
If the model’s primary key is an AutoField it does not retrieve and set the primary key attribute, as save() does.
I am guessing that your id was on autoincrement and now it isn't being saved, which is being referenced by _order.

Saving FK model field by fieldname_id allows non-existing FK relations

I have a model consisting of two ForeignKey fields as below. (This is a ManytoMany through field)
class EntityConceptLink(models.Model):
entity = models.ForeignKey(Entity)
standard_concept = models.ForeignKey(StandardConcept)
other fields...
I am trying to create objects like so:
EntityConceptLink.objects.get_or_create(
entity_id=entity_id, # passing in an integer, should be PK of Entity
standard_concept=concept) # passing in a model instance
The problem is, when I pass in an entity_id corresponding to an nonexistent Entity, the above code somehow nonetheless saves the model instance. It's only later when I try to do entityconceptlinkinstance.entity that a DoesNotExist: Entity matching query does not exist is raised.
Shouldn't the model fail validation during the attempt to save? Am I doing something wrong here?
Yeah I think below code should work fine.
EntityConceptLink.objects.get_or_create(
entity__id=entity_id, # Believe `id` would be the primary key
standard_concept=concept)
In the above case it will raise error if entity model do not find the required id. See the use double __ instead of single _ in the entity id.

Django ForeignKey which does not require referential integrity?

I'd like to set up a ForeignKey field in a django model which points to another table some of the time. But I want it to be okay to insert an id into this field which refers to an entry in the other table which might not be there. So if the row exists in the other table, I'd like to get all the benefits of the ForeignKey relationship. But if not, I'd like this treated as just a number.
Is this possible? Is this what Generic relations are for?
This question was asked a long time ago, but for newcomers there is now a built in way to handle this by setting db_constraint=False on your ForeignKey:
https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.db_constraint
customer = models.ForeignKey('Customer', db_constraint=False)
or if you want to to be nullable as well as not enforcing referential integrity:
customer = models.ForeignKey('Customer', null=True, blank=True, db_constraint=False)
We use this in cases where we cannot guarantee that the relations will get created in the right order.
EDIT: update link
I'm new to Django, so I don't now if it provides what you want out-of-the-box. I thought of something like this:
from django.db import models
class YourModel(models.Model):
my_fk = models.PositiveIntegerField()
def set_fk_obj(self, obj):
my_fk = obj.id
def get_fk_obj(self):
if my_fk == None:
return None
try:
obj = YourFkModel.objects.get(pk = self.my_fk)
return obj
except YourFkModel.DoesNotExist:
return None
I don't know if you use the contrib admin app. Using PositiveIntegerField instead of ForeignKey the field would be rendered with a text field on the admin site.
This is probably as simple as declaring a ForeignKey and creating the column without actually declaring it as a FOREIGN KEY. That way, you'll get o.obj_id, o.obj will work if the object exists, and--I think--raise an exception if you try to load an object that doesn't actually exist (probably DoesNotExist).
However, I don't think there's any way to make syncdb do this for you. I found syncdb to be limiting to the point of being useless, so I bypass it entirely and create the schema with my own code. You can use syncdb to create the database, then alter the table directly, eg. ALTER TABLE tablename DROP CONSTRAINT fk_constraint_name.
You also inherently lose ON DELETE CASCADE and all referential integrity checking, of course.
To do the solution by #Glenn Maynard via South, generate an empty South migration:
python manage.py schemamigration myapp name_of_migration --empty
Edit the migration file then run it:
def forwards(self, orm):
db.delete_foreign_key('table_name', 'field_name')
def backwards(self, orm):
sql = db.foreign_key_sql('table_name', 'field_name', 'foreign_table_name', 'foreign_field_name')
db.execute(sql)
Source article
(Note: It might help if you explain why you want this. There might be a better way to approach the underlying problem.)
Is this possible?
Not with ForeignKey alone, because you're overloading the column values with two different meanings, without a reliable way of distinguishing them. (For example, what would happen if a new entry in the target table is created with a primary key matching old entries in the referencing table? What would happen to these old referencing entries when the new target entry is deleted?)
The usual ad hoc solution to this problem is to define a "type" or "tag" column alongside the foreign key, to distinguish the different meanings (but see below).
Is this what Generic relations are for?
Yes, partly.
GenericForeignKey is just a Django convenience helper for the pattern above; it pairs a foreign key with a type tag that identifies which table/model it refers to (using the model's associated ContentType; see contenttypes)
Example:
class Foo(models.Model):
other_type = models.ForeignKey('contenttypes.ContentType', null=True)
other_id = models.PositiveIntegerField()
# Optional accessor, not a stored column
other = generic.GenericForeignKey('other_type', 'other_id')
This will allow you use other like a ForeignKey, to refer to instances of your other model. (In the background, GenericForeignKey gets and sets other_type and other_id for you.)
To represent a number that isn't a reference, you would set other_type to None, and just use other_id directly. In this case, trying to access other will always return None, instead of raising DoesNotExist (or returning an unintended object, due to id collision).
tablename= columnname.ForeignKey('table', null=True, blank=True, db_constraint=False)
use this in your program

Categories