manager select_related()

62 views
Skip to first unread message

saeb

unread,
Aug 18, 2008, 11:50:41 PM8/18/08
to Django users

Sorry to ask a stupid question, but following is my basic model
structure. I want to create a custom manager for a class which has a
foreignKey to another class. And to call that manager function in list
display to display all the related properties. Am I doing it right? I
don't see any associated fields when I execute the following in shell.
Please help me with this issue, Thanks.



class privateAcctManager(models.Manager):
def show_acct(self):
return super(privateAcctManager,
self).get_query_set().select_related()

class privateAcct(models.Model):
id = models.ForeignKey(Acct)
obj = privateAcctManager()

def all_acct(self):
return self.obj.show_acct()

class Meta:
db_table= 'private_acct'

class PublicAcct(models.Model):
id = models.ForeignKey(Acct)
class Meta:
db_table= 'public_acct'

class Account(models.Model):
name = models.TextField()
balance = models.decimalfield()

class PrivateAcctAdmin(admin.modelAdmin):
list_display =( id, all_acct.name , all_acct.balance)


ocgstyles

unread,
Aug 19, 2008, 8:57:36 AM8/19/08
to Django users
Hi saeb,

I believe you misunderstand the purpose of select_related(). When
used, it does the extra database work to retrieve related objects at
the beginning, rather than when you try to access them. Here's an
example:

# in this example, notice how __dict__ isn't populated with the
_site_cache until AFTER we manually refer to the site (f.site.domain)

>>> from feedback.models import Feedback
>>> f = Feedback.objects.get(pk=1)
>>> f.__dict__
{'display_name': u'Keith', 'site_id': 1L, 'comments': u'YAY', 'id':
1L, 'pub_date': datetime.datetime(2008, 8, 1, 23, 35, 7)}
>>> f.site.domain
u'shopfha.com'
>>> f.__dict__
{'display_name': u'Keith', 'site_id': 1L, 'comments': u'hello', 'id':
1L, '_site_cache': <Site: example.com>, 'pub_date':
datetime.datetime(2008, 8, 1, 23, 35, 7)}


# in this example, notice how __dict__ is now populated with the
_site_cache without first referring to the site

>>> from feedback.models import Feedback
>>> f = Feedback.objects.select_related().get(pk=2)
>>> d.__dict__
{'display_name': u'Paul', 'site_id': 1L, 'comments': u"hello", 'id':
2L, '_site_cache': <Site: example.com>, 'pub_date':
datetime.datetime(2008, 8, 1, 23, 37, 41)}

HTH

Keith

ocgstyles

unread,
Aug 19, 2008, 9:00:13 AM8/19/08
to Django users
apparently i pasted that in there twice. woops...

Malcolm Tredinnick

unread,
Aug 19, 2008, 9:04:07 AM8/19/08
to django...@googlegroups.com

Firstly, if this is real code, don't put the admin class in the same
file as the model class. This will lead to double-registration errors.
Put the admin class in another file (admin.py is typical and means you
can use admin.autodiscover()).

Secondly, when referring to model methods in the list_display, you
should be using strings, not function references. Thirdly, you can only
refer to functions/methods there, not attributes on the returned
objects. So you need to have a method which returns exactly what you
want to display, since you can't extract anything from it using
attribute access (the dot-notation) as you're trying to do here.

Regards,
Malcolm


saeb

unread,
Aug 19, 2008, 9:33:47 AM8/19/08
to Django users
No, that is not the real code. The real code as you mentioned is split
into models.py and admin.py. And I am referring to the functions as
strings ( a typo on my part). After posting the message last night I
messed with the code more and function is displaying as 'none' .
Referring to Malcolm's last suggestion, I changed the function to
return an attribute and I still see the same issue, where the column
is 'none' in display.

This is what I have. I really appreciate your help

---models.py----

class privateAcctManager(models.Manager):
def show_acct_name(self):
t = Acct.objects.all().filter(id= self.id).name
return t

class privateAcct(models.Model):
id = models.ForeignKey(Acct)
obj = privateAcctManager()

def acct_name(self):
return self.obj.show_acct_name()

class Meta:
db_table= 'private_acct'

class PublicAcct(models.Model):
id = models.ForeignKey(Acct)
class Meta:
db_table= 'public_acct'

class Account(models.Model):
name = models.TextField()
balance = models.decimalfield()

-------admin.py--------

class PrivateAcctAdmin(admin.modelAdmin):
list_display =( 'id', 'acct_name' )


On Aug 19, 8:04 am, Malcolm Tredinnick <malc...@pointy-stick.com>
wrote:

Daniel Roseman

unread,
Aug 19, 2008, 10:37:38 AM8/19/08
to Django users
There's quite a lot wrong with this code, quite apart from the
list_display issue. Comments interspersed below.

On Aug 19, 2:33 pm, saeb <sridevi.ma...@gmail.com> wrote:
> No, that is not the real code. The real code as you mentioned is split
> into models.py and admin.py. And I am referring to the functions as
> strings ( a typo on my part). After posting the message last night I
> messed with the code more and function is displaying as 'none' .
> Referring to Malcolm's last suggestion, I changed the function to
> return an attribute and I still see the same issue, where the column
> is 'none' in display.
>
> This is what I have. I really appreciate your help
>
> ---models.py----
>
> class privateAcctManager(models.Manager):
>         def show_acct_name(self):
>            t = Acct.objects.all().filter(id= self.id).name
>            return t

You can't do this. The result of filter() is always a queryset, even
if only one object is returned. Plus 'self' here refers to the
manager, which doesn't have an ID.

Anyway, this code doesn't really belong in a manager, but in a method
on the model itself.

> class privateAcct(models.Model):
>     id = models.ForeignKey(Acct)
>     obj = privateAcctManager()
>
>     def  acct_name(self):
>        return self.obj.show_acct_name()

No need for the reference to the manager here. Just return
self.id.name.

id is a really bad name for the foreign key to Acct (which doesn't
seem to exist in the code you've got here - or did you mean Account?)
This will clobber the autogenerated primary key. If you want an actual
foreign key as primary key, you should probably be using OneToOneField
instead.

>      class Meta:
>            db_table= 'private_acct'
>
> class PublicAcct(models.Model):
>     id = models.ForeignKey(Acct)
>      class Meta:
>            db_table= 'public_acct'

Same comments apply re use of id here.

> class Account(models.Model):
>    name = models.TextField()
>    balance = models.decimalfield()
>
> -------admin.py--------
>
> class PrivateAcctAdmin(admin.modelAdmin):
> list_display =( 'id', 'acct_name' )

With the changes above, this should now work (assuming it's indented
properly).
--
DR.

Steve Holden

unread,
Aug 19, 2008, 10:39:19 AM8/19/08
to django...@googlegroups.com
saeb wrote:
> No, that is not the real code. The real code as you mentioned is split
> into models.py and admin.py. And I am referring to the functions as
> strings ( a typo on my part). After posting the message last night I
> messed with the code more and function is displaying as 'none' .
> Referring to Malcolm's last suggestion, I changed the function to
> return an attribute and I still see the same issue, where the column
> is 'none' in display.
>
> This is what I have. I really appreciate your help
>
> ---models.py----
>
> class privateAcctManager(models.Manager):
> def show_acct_name(self):
> t = Acct.objects.all().filter(id= self.id).name
> return t
>
>
I suspect your issue is above. You are trying to retrieve the "name"
attribute of a queryset rather than a row. You could either change this
to

t = Acct.objects.all().filter(id= self.id)[0].name


or, more comprehensibly, to

t = Acct.objects.get(pk=self.id).name

I think. Though this would seem to make sense as a __unicode__() method too.

regards
Steve

saeb

unread,
Aug 19, 2008, 11:35:40 AM8/19/08
to Django users

Thanks, ideally OneToOneField is what I need, but due to weird legacy
database schema, I can't use it. id is a bad name, but I would have to
deal with the nomenclature for the moment. Thanks for help



On Aug 19, 9:37 am, Daniel Roseman <roseman.dan...@googlemail.com>
wrote:
Reply all
Reply to author
Forward
0 new messages