I have code that looks like this in my Django app's models.py:
from main.models import SmartPrefetchQuerySet
class EventPrivacyManager(SoftDeletablePrivacyManager):
def get_query_set_for_producer(self, producer):
return self.get_query_set().filter(users_about=producer)
def get_query_set(self):
return SmartPrefetchQuerySet(self.model, using=self._db)
...
The import works fine -- I can print SmartPrefetchQuerySet
in the module itself and the output is <class 'main.models.SmartPrefetchQuerySet'>
. But when I actually call the get_query_set method I get this:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File ".../feeds/models.py", line 29, in smart_prefetch_for
return self.get_query_set().smart_prefetch_for(*args, **kwargs)
File ".../feeds/models.py", line 26, in get_query_set
return SmartPrefetchQuerySet(self.model, using=self._db)
TypeError: 'NoneType' object is not callable
If, on the other hand, I move the import inside the get_query_set method itself, it works fine. And if I open up a Django shell and instantiate SmartPrefetchQuerySet by passing the Event model to it directly, that works fine too. It's only inside the method that SmartPrefetchQuerySet appears to be None (a print statement injected into that method verifies that the name indeed refers to None).
The "SmartPrefetchQuerySet" name is only used in the class definition for that class, and in this place calling it, and nowhere else in the codebase.
I don't understand how this behavior is possible given how Python namespaces normally work. How can an imported name be defined to be one thing at the module level, and a totally different thing inside a method in that same module, with no other assignments to that name anywhere in the module? My only thought so far is that it might be a circular import problem, but I can't find any such circular import, and usually circular imports seem to result in less subtle problems.
Edit: the entire models.py file, somewhat sanitized and abbreviated:
from django.db import models
from django.conf import settings
from auth.models import HasPrivacy, SoftDeletablePrivacyManager
from lck.django.common.models import TimeTrackable, SoftDeletable
from groups.models import Group
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.utils import timezone
from main.models import SmartPrefetchQuerySet # not literally from a module named "main", but the name has to be sanitized for this post
print SmartPrefetchQuerySet # prints "<class 'main.models.SmartPrefetchQuerySet'>"
# Note: there is an additional import at the bottom of this file for event signal registration
class EventPrivacyManager(SoftDeletablePrivacyManager):
def get_query_set_for_producer(self, producer):
"class that can be overridden by children of this manager for models that don't have a 'user' attrib"
return self.get_query_set().filter(users_about=producer)
def get_query_set(self):
print SmartPrefetchQuerySet # prints "None"
return SmartPrefetchQuerySet(self.model, using=self._db)
def smart_prefetch_for(self, *args, **kwargs):
return self.get_query_set().smart_prefetch_for(*args, **kwargs)
class Event(HasPrivacy, SoftDeletable, TimeTrackable):
...
objects = EventPrivacyManager()
...
class Notification(SoftDeletable, TimeTrackable):
...
print SmartPrefetchQuerySet # prints "<class 'main.models.SmartPrefetchQuerySet'>"
# this import registers the event signal handlers.
# don't remove it even if it doesn't look like it's being used in this
# file, and don't move it from the bottom of this file in order to avoid
# circular imports!
import events
print SmartPrefetchQuerySet # prints "<class 'main.models.SmartPrefetchQuerySet'>"