Impact of a CustomManager on the RelatedManager

421 views
Skip to first unread message

gaz

unread,
Sep 21, 2008, 7:49:36 PM9/21/08
to Django users
Hi everyone,

I apologise for the verbosity of this message - for my first post it's
quite long.

I am currently working on my first project employing the Sites
framework, and have been moving along quite well with the
documentation until I hit a snag last night.

I have overloaded the default manager in my model to use a slight
variant of the CurrentSiteManager, shown below.

class MyCurrentSiteManager(models.Manager):
def __init__(self, field_name='site'):
super(MyCurrentSiteManager, self).__init__()
self.__field_name = field_name
def get_query_set(self):
return super(MyCurrentSiteManager,
self).get_query_set().filter(**{self.__field_name + '__id__exact':
settings.SITE_ID})

The reason I've trimmed it down, is because I want field_name to be a
site reference on a related model. such as:

class Venue(models.Model):
name = models.CharField(max_length=50)
site = models.ForeignKey(Site)
objects = MyCurrentSiteManager()
systemwide = models.Manager()

class Conference(models.Model):
title = models.CharField(max_length=50)
venue = models.ForeignKey(Venue, related_name='conferences')
objects = MyCurrentSiteManager('venue__site')
systemwide = models.Manager()

What I am seeing is that the following queries work and present only
the objects which are on the site (Venue) or objects which are related
to a Venue on the site (Conference):

Venue.objects.all()
Conference.objects.all()

However, if I try to get the related objects of a Venue object, I get
an error as below:

>>> v = Venue.objects.get(pk=1)
>>> v.conferences.all()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/lib/python2.5/site-packages/django/db/models/manager.py",
line 78, in all
return self.get_query_set()
File "/usr/lib/python2.5/site-packages/django/db/models/fields/
related.py", line 300, in get_query_set
return
superclass.get_query_set(self).filter(**(self.core_filters))
File "/path/munged/managers.py", line 14, in get_query_set
return super(MyCurrentSiteManager,
self).get_query_set().filter(**{self.__field_name + '__id__exact':
settings.SITE_ID})
File "/usr/lib/python2.5/site-packages/django/db/models/query.py",
line 483, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File "/usr/lib/python2.5/site-packages/django/db/models/query.py",
line 501, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File "/usr/lib/python2.5/site-packages/django/db/models/sql/
query.py", line 1224, in add_q
can_reuse=used_aliases)
File "/usr/lib/python2.5/site-packages/django/db/models/sql/
query.py", line 1099, in add_filter
negate=negate, process_extras=process_extras)
File "/usr/lib/python2.5/site-packages/django/db/models/sql/
query.py", line 1287, in setup_joins
"Choices are: %s" % (name, ", ".join(names)))
FieldError: Cannot resolve keyword 'site' into field. Choices are:
venue, id, title

I added a print line to my manager's get_query_set method, so it now
reads:

def get_query_set(self):
print self.model._meta.object_name, self.__field_name
return super(MyCurrentSiteManager,
self).get_query_set().filter(**{self.__field_name + '__id__exact':
settings.SITE_ID})

When I redo the query above, I now get:

>>> v.conferences.all()
Venue site
Conference site
Traceback (most recent call last):
... as before ...

I was expecting it to be:

>>> v.conferences.all()
Venue site
Conference venue__site
<QuerySet>

So my analysis is that the RelatedManager (v.conferences) is not
completely partnering up with my MyCurrentSiteManager because,
although the print statements are firing off, they are not actually
using the field_name parameter I supplied when instantiating the
manager on the model.

And here we are, finally at my question! Is it possible to have the
related manager use the field_name that was passed in to my custom
manager?

Again, sorry for the long post but I thought it best to lay it all out
there first!

Regards,
Gary

bruno desthuilliers

unread,
Sep 22, 2008, 8:01:40 AM9/22/08
to Django users
On 22 sep, 01:49, gaz <garyjohnreyno...@gmail.com> wrote:
(snip)
> I have overloaded the default manager in my model to use a slight
> variant of the CurrentSiteManager, shown below.
>
(snip)
> What I am seeing is that the following queries work and present only
> the objects which are on the site (Venue) or objects which are related
> to a Venue on the site (Conference):
>
> Venue.objects.all()
> Conference.objects.all()
>
> However, if I try to get the related objects of a Venue object, I get
> an error as below:
>
(snip)

I might be wrong (only had a very cursory glance at your code), but
I'd say you want to have a look at this:
http://docs.djangoproject.com/en/dev/topics/db/managers/#using-managers-for-related-object-access

HTH

gaz

unread,
Sep 22, 2008, 7:26:30 PM9/22/08
to Django users
Thanks Bruno,

I'd already tried that - I noticed that with or without the
use_for_related_field being set on the Custom Manager the effect was
the same - ie. the RelatedManager fires off it's own code without
actually using the MyCurrentSiteManager instance that is already
associated with the Model Class.

At the moment my solution has been to do:

def _get_conferences(self):
return Conference.objects.filter(venue=self)
conferences = property(_get_conferences)

I'm not sure this is the best way, but I am basing that on my reading
at http://docs.djangoproject.com/en/dev/topics/db/managers/#adding-extra-manager-methods
and http://docs.djangoproject.com/en/dev/topics/db/models/#model-methods

Any advice on as to whether or not this is the best way to get the
solution I am after appreciated!

Gary

On Sep 22, 10:01 pm, bruno desthuilliers
>  http://docs.djangoproject.com/en/dev/topics/db/managers/#using-manage...
>
> HTH

bruno desthuilliers

unread,
Sep 23, 2008, 4:15:13 PM9/23/08
to Django users
On 23 sep, 01:26, gaz <garyjohnreyno...@gmail.com> wrote:
> Thanks Bruno,
>
> I'd already tried that - I noticed that with or without the
> use_for_related_field

FWIW, it's a plural, ie "use_for_related_field*s*" - but I assume the
typo wasn't in your code.

Out of curiousity, which Django version are you using ?

> being set on the Custom Manager the effect was
> the same - ie. the RelatedManager fires off it's own code without
> actually using the MyCurrentSiteManager instance that is already
> associated with the Model Class.
>
> At the moment my solution has been to do:
>
> def _get_conferences(self):
> return Conference.objects.filter(venue=self)
> conferences = property(_get_conferences)

<ot>
You could refactor it to

conferences = property(lambda self:
Conference.objects.filter(venue=self))

</ot>

But this doesn't really answer your question...

> I'm not sure this is the best way, but I am basing that on my reading
> athttp://docs.djangoproject.com/en/dev/topics/db/managers/#adding-extra...
> andhttp://docs.djangoproject.com/en/dev/topics/db/models/#model-methods
>
> Any advice on as to whether or not this is the best way to get the
> solution I am after appreciated!

Well... A working solution is by all means better than a broken one,
ins't it !-)

This being said, I'm afraid I can't help much more without installing
your code and tracing it.

Any Django guru around ???
Reply all
Reply to author
Forward
0 new messages