In Django 1.5 I have 3 apps: common, app1, app2 in which I have the following (simplified) models:
# common/models.py
class ApiUser(models.Model):
username = models.CharField(max_length=255)
channel = models.CharField(max_length=20)
# app1/models.py
class Place(models.Model):
title = models.CharField(max_length=255)
created_by = models.ForeignKey('common.ApiUser', null=True, related_name="%(app_label)s_places")
# app2/models.py
class Tag(models.Model):
name = models.CharField(max_length=255)
user = models.ForeignKey('common.ApiUser', null=True, related_name="%(app_label)s_tags")
app1
is listed before app2
in INSTALLED_APPS
.
When I try to create the following queryset:
qs = ApiUser.objects.filter(channel='app1').annotate(Count('app1_places'))
I get back:
Cannot resolve keyword 'app1_places' into field. Choices are: app2_tags, channel, username
Where the list of choices provided does not include 'app1_places'
but does contain 'app2_tags'
. However if I try to reference app1_places
on a model instance I don't get an error; it works fine:
>>> u = ApiUser.objects.get(pk=23)
>>> u.app1_places.all()
[]
Annotate with app2_tags
works too:
qs = ApiUser.objects.filter(channel='app2').annotate(Count('app2_tags'))
Is this a bug in django or is there something I am doing wrong configuring these fields.
edit: here is the stack trace:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/vagrant/.virtualenvs/thorium/lib/python2.6/site-packages/django/db/models/query.py", line 795, in annotate
is_summary=False)
File "/home/vagrant/.virtualenvs/thorium/lib/python2.6/site-packages/django/db/models/sql/query.py", line 1019, in add_aggregate
field_list, opts, self.get_initial_alias(), False)
File "/home/vagrant/.virtualenvs/thorium/lib/python2.6/site-packages/django/db/models/sql/query.py", line 1337, in setup_joins
"Choices are: %s" % (name, ", ".join(names)))
FieldError: Cannot resolve keyword 'app1_places' into field. Choices are: app2_tags, channel, username
Note: some app1 models are using the GeoDjango GeoManager (including places) but there are also models in app1 which don't use the geomanager and have foreign keys that also do not work with annotate.
It turns out the issue was with a proxy model that was on app1 and not app2. The proxy model had a custom manager:
# app1/models.py
class App1User(common_models.ApiUser):
objects = common_models.ApiUser.objects.filter(channel='app1')
class Meta:
proxy = True
App2 is not using a corresponding proxy model for ApiUser. When django first loads all the models to determine the model domain and calculate backwards references the overridden manager in the proxy model short-circuited the loading of app1.models, leaving all the backwards references for that module uninitialised.
Removing the custom manager definition resolved the issue.