Opened 8 years ago
Last modified 8 years ago
#29331 closed Bug
Model fields where the python attribute name does not match the db column are not saved — at Version 3
| Reported by: | Ben Mathes | Owned by: | nobody |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 2.0 |
| Severity: | Normal | Keywords: | models, deferred_field, save |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Reproduced in this github django repo: https://github.com/benmathes/deferred_fields_bug
When defining a model, if you rename a model's db column, django will thing that model is deferred and will not save() it.
e.g.
class SomeModel(models.Model):
"""
a contrived model field where we want a "field" that is stored
in a "field" column, but we use @property getter/setters so
we name the SomeModel class's attribute as "_field".
"""
name = models.TextField(null=True)
_field = models.TextField(name="field")
@property
def field(self):
return self._field.upper()
@field.setter
def field(self, new_value):
self._field = new_value.lower()
With a renamed db column, "_field" is in self.__dict__, but "field" is not,
def get_deferred_fields(self):
"""
Return a set containing names of deferred fields for this instance.
"""
return {
f.attname for f in self._meta.concrete_fields
if f.attname not in self.__dict__
}
So field is not saved in .save(), because django _mistakenly_ thinks "field" is deferred, so it is ignored during .save()
# https://github.com/django/django/blob/93331877c81c1c6641b163b97813268f483ede4b/django/db/models/base.py#L712 # ... # elif not force_insert and deferred_fields and using == self._state.db: # field_names = set() # for field in self._meta.concrete_fields: # if not field.primary_key and not hasattr(field, 'through'): # field_names.add(field.attname) # -> loaded_fields = field_names.difference(deferred_fields) # if loaded_fields: # update_fields = frozenset(loaded_fields) # # self.save_base(using=using, force_insert=force_insert, # force_update=force_update, update_fields=update_fields) # ...
Reproduced in this github django repo: https://github.com/benmathes/deferred_fields_bug
Change History (3)
comment:1 by , 8 years ago
| Needs tests: | set |
|---|
comment:2 by , 8 years ago
| Description: | modified (diff) |
|---|
comment:3 by , 8 years ago
| Description: | modified (diff) |
|---|