#25343 closed Bug (wontfix)
IntegerField(primary_key=True) behaves like AutoField in SQLite but Django doesn't treat it as such
| Reported by: | eng. Ilian Iliev | Owned by: | nobody |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 1.8 |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Example:
# models.py
class Language(models.Model):
language = models.IntegerField(primary_key=True)
code = models.CharField(verbose_name='Language code (2 chars)', blank=False, max_length=2)
# views.py
l = Language.objects.create(code='x')
print l.pk # return None
The above mention problem happens only if we have "primary_key=True" otherwise it works as expected.
Change History (11)
comment:1 by , 10 years ago
| Description: | modified (diff) |
|---|
comment:2 by , 10 years ago
| Severity: | Release blocker → Normal |
|---|
comment:3 by , 10 years ago
The expected behaviour is that the pk property to be set to the value of the primary key.
Because if you do like this
lang = Language.objects.create(code='x') lang.pk is None # returns True lang = Language.objects.get(code='x') lang.pk is not None # for example 1
Then you have quite inconsistent behaviour
follow-up: 5 comment:4 by , 10 years ago
Is this really your exact code? Unless you have null=True on the language field, that code should raise a database error like "null value not allowed in column 'language'".
But it looks like your database is automatically setting a value for that field instead of raising an error. So maybe your database schema doesn't match your model definition? What database are you using, and what is the actual schema for that table? Did Django create it, or did you create it manually?
If you set a value for the language field, that will be the value of the pk attribute.
If you don't want to have to explicitly set a value for the primary key, you should be using AutoField, not IntegerField (or just let Django automatically add an AutoField named id, as it does if you don't set primary_key=True on any of your fields).
comment:5 by , 10 years ago
Replying to carljm:
Is this really your exact code? Unless you have
null=Trueon thelanguagefield, that code should raise a database error like "null value not allowed in column 'language'".
But it looks like your database is automatically setting a value for that field instead of raising an error. So maybe your database schema doesn't match your model definition? What database are you using, and what is the actual schema for that table? Did Django create it, or did you create it manually?
If you set a value for the
languagefield, that will be the value of thepkattribute.
If you don't want to have to explicitly set a value for the primary key, you should be using
AutoField, notIntegerField(or just let Django automatically add anAutoFieldnamedid, as it does if you don't setprimary_key=Trueon any of your fields).
No actually the exact code is:
class Language(models.Model):
language = models.IntegerField(verbose_name='Language', primary_key=True) #, choices=LANGUAGES, max_length=2)
code = models.CharField(verbose_name='Language code (2 chars)', blank=False, max_length=2)
priority = models.PositiveIntegerField(verbose_name="Priority", default=0, null=False, blank=True)
it is a legacy code, and I am not sure how the DB has been created but I can reproduce it if I recreate the table with syncdb in a new DB (sqlite). The value is automatically autoincremented.
I also found the the language property is also not set in the object after create. However after getting the object from the DB everything is fine.
follow-up: 7 comment:6 by , 10 years ago
It looks like AutoField() and IntegerField(primary_key=True) create the same "integer PRIMARY KEY" type on SQLite, but Django doesn't know to treat the latter definition as an AutoField (and I don't think it should try to). Other databases (tested with PostgreSQL) with throw the expected IntegrityError for a null value in the language column.
We could document the issue or add a database-specific check when SQLite is in use. Is it worthwhile?
comment:7 by , 10 years ago
Replying to timgraham:
It looks like
AutoField()andIntegerField(primary_key=True)create the same "integer PRIMARY KEY" type on SQLite, but Django doesn't know to treat the latter definition as anAutoField(and I don't think it should try to). Other databases (tested with PostgreSQL) with throw the expectedIntegrityErrorfor a null value in thelanguagecolumn.
We could document the issue or add a database-specific check when SQLite is in use. Is it worthwhile?
That makes sense. Regarding whether it should be documented or not - it is a strange corner case caused by ugly legacy code that I stumbled upon so probably this is quite a rare case and there is no need to add it to the docs. It will stay documented here if anyone hits the same issue.
comment:8 by , 10 years ago
| Resolution: | → wontfix |
|---|---|
| Status: | new → closed |
| Summary: | pk attribute not set when having own primary key → IntegerField(primary_key=True) behaves like AutoField in SQLite but Django doesn't treat it as such |
Okay, thanks for the feedback
comment:9 by , 10 years ago
For future reference, in case that decision ever changes (and frankly, I wouldn't turn down a solid patch for this if someone supplied one), the way to fix this would be with a db backend feature flag, I think; something like integer_pk_always_autoincrements.
comment:10 by , 10 years ago
For what it's worth, I don't know if 'autoincrements' in the feature name might be slightly misleading as the default behavior for SQLite is merely to select as unused id. Django does add AUTOINCREMENT for AutoField, so what it generates for the two definitions is actually not strictly equivalent in that respect.
comment:11 by , 10 years ago
Good point. Something like integer_pk_always_autofills might be better.
What is the expected behavior? I wouldn't expect an
IntegerFieldto automatically generate a primary key value.