#24804 closed Bug (invalid)
META API: get_field method cache issue
Reported by: | Aamir Rind | Owned by: | nobody |
---|---|---|---|
Component: | Core (Cache system) | Version: | 1.8 |
Severity: | Normal | Keywords: | meta, meta api, get_field, FieldDoesNotExist, cache, internal cache |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
When Model._meta.get_field raises a django.core.exceptions.FieldDoesNotExist exception for field name, later on if we add the field with that name it stills throws exception because of internal cache issue even the field has been added. Consider below code to reproduce the issue:
from django.db.models import CharField from django.core.exceptions import FieldDoesNotExist class AutoCleanField(CharField): def __init__(self, depends_on=None, *args, **kwargs): self.depends_on = depends_on super(AutoCleanField, self).__init__(*args, **kwargs) def deconstruct(self): name, path, args, kwargs = super(AutoCleanField, self).deconstruct() if self.depends_on: kwargs['depends_on'] = self.depends_on return name, path, args, kwargs def contribute_to_class(self, cls, name, **kwargs): super(AutoCleanField, self).contribute_to_class(cls, name, **kwargs) try: field = cls._meta.get_field(self.depends_on) except FieldDoesNotExist: field = None if not field: raise TypeError('{0} `depends_on` field "{1}" does not exists in model "{2}".' .format(self.__class__.__name__, self.depends_on, self.model.__name__)) class Test(models.Model): auto = AutoCleanField(depends_on='name') # <--- intentionally setting a field for param `depends_on` which does not exists
After the above code has been run, now add the name field in Test model and re-run, The FieldDoesNotExist exception does not go away:
class Test(models.Model): # everything should works fine now, but didn't name = models.CharField(max_length=255) auto = AutoCleanField(depends_on='name')
Note:
See TracTickets
for help on using tickets.
Hi intellisense,
This behavior might be a bit counter intuitive but it has nothing to do with
get_field()
caching. It is instead related to how Python builds classes internally.When a model class is built its defined attributes such as fields are not necessarily ordered the way they are defined; they are collected in an non-ordered mapping (
dict
) and thus the declared ordering is lost.In your example you're assuming the
auto
field will be added after thename
one because the latter is declared before. What's happening here is thatauto
is ordered beforename
inattrs
and thus itscontribute_to_class
is called before.You shouldn't assume that
dict
will be ordered in any way. For example, if you change the seed used to define a an order over unordered collection (python -R
) you should be able to make the following example print either an empty tuple or a singleton containing thename
field:I suggest you take a look at how the
GenericForeignKey
deals with a similar pattern.