#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 , 9 years ago
Description: | modified (diff) |
---|
comment:2 by , 9 years ago
Severity: | Release blocker → Normal |
---|
comment:3 by , 9 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 , 9 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 , 9 years ago
Replying to carljm:
Is this really your exact code? Unless you have
null=True
on thelanguage
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 thepk
attribute.
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 anAutoField
namedid
, as it does if you don't setprimary_key=True
on 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 , 9 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 , 9 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 expectedIntegrityError
for a null value in thelanguage
column.
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 , 9 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 , 9 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 , 9 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.
What is the expected behavior? I wouldn't expect an
IntegerField
to automatically generate a primary key value.