#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')
Change History (1)
comment:1 by , 10 years ago
| Resolution: | → invalid |
|---|---|
| Status: | new → closed |
Version 0, edited 10 years ago by (next)
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
autofield will be added after thenameoen because the former is declared before. What's happening here is thatautois ordered beforenameinattrsand thus itscontribute_to_classis called before.You shouldn't assume that
dictwill 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 thenamefield:I suggest you take a look at how the
GenericForeignKeydeals with a similar pattern.