Cannot call a custom model method in my view

1,896 views
Skip to first unread message

codecowboy

unread,
Apr 11, 2009, 4:25:45 PM4/11/09
to Django users
I've read some other posts regarding this issue as well as the
following article: http://www.b-list.org/weblog/2007/nov/03/working-models/.
I cannot seem to get this thing to work. Thank you in advance for any
help. Here is my code.

---------- view ----------
from django.db.models import get_model

def blah():
c = get_model('conferences', 'conference')
uc = c.upcoming()

---------- model ----------
class Conference(models.Model):
.
.
.

def upcoming(self):
today = datetime.today()
return self.objects.filter(date__gte=(today))

I've also tried the following in my view code:


def blah():
c = Conference()
uc = c.upcoming()

I cannot stop the following error from displaying:

TypeError at /scientists/portal

unbound method upcoming() must be called with Conference instance as
first argument (got nothing instead)

Request Method: GET
Request URL: http://127.0.0.1:8000/scientists/portal
Exception Type: TypeError
Exception Value:

unbound method upcoming() must be called with Conference instance as
first argument (got nothing instead)

Exception Location: /home/guy/DjangoApps/scinet/scientists/views.py
in portal, line 20

Daniel Roseman

unread,
Apr 11, 2009, 4:49:21 PM4/11/09
to Django users
You are confused between class and instance methods. upcoming as you
have defined it is an instance method - ie you call it on an instance
of Conference. However, the content of the method looks like it should
be a class method - that is, you call it on the Conference class
itself - and, indeed, that is what you are trying to do in your blah
view.

There are two solutions to this: the first is to tell Python that this
is a class method by simply using the @classmethod decorator - and, by
convention, using cls as the parameter to the method rather than
self.

However, looking at what you're actually trying to do - return a
custom queryset of Conference objects - the idiomatic way of achieving
this in Django is actually to define a custom manager. Again, two ways
of doing this: you can define an additional manager and put your
method in it as get_query_set - so you would call it as
Conference.upcoming.all(); or override the default manager and put
your method as upcoming - so you would call it as
Conference.objects.upcoming(). Your choice.

See here for information on custom managers:
http://docs.djangoproject.com/en/dev/topics/db/managers/
--
DR.

codecowboy

unread,
Apr 11, 2009, 6:10:16 PM4/11/09
to Django users
Thank you Daniel. I got it working. That link that you gave me
helped me to figure it out. I'm curious though, is there ever a
reason in Django to define a method in a model class or would I always
use a custom manager method?

I'm going to post my code here for anyone who has the same question
down the road. Thanks a lot and I hope that this helps someone else.

----- conferences/models.py -----

In this file I create a custom manager (ConferenceManager) class with
a custom function (def upcoming(self)). Notice in the Conference
model that I create a class variable named objects and set it equal to
the custom manager that I created. This is all that you have to do in
order to access the custom function in your manager.

from django.db import models
from datetime import datetime
from scinet.scientists.models import Scientist

class ConferenceManager(models.Manager):
def upcoming(self):
today = datetime.today()
return super(ConferenceManager, self).get_query_set().filter
(date__gte=(today))

class Conference(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
date = models.DateTimeField()
scientists = models.ManyToManyField(Scientist,
through='ConferenceAttendee')
created = models.DateTimeField()
modified = models.DateTimeField()

objects = ConferenceManager()

----- conferences/views.py -----

As you can see, once you create the model the way that I did above,
you will be able to call the upcoming() function like I did. "uc =
Conference.objects.upcoming()".

def detail(request, conference_id):
c = get_object_or_404(Conference, pk=conference_id)

# Get all upcoming conferences
uc = Conference.objects.upcoming()

return render_to_response('conferences/detail.html',
{'conference': c, 'upcoming_conferences' : uc})

----- templates/conferences/details.html -----

The template is not relevant here but I will include it just for the
sake of providing a complete.

<h2>Upcoming Conferences</h2>

<ul>
{% for conference in upcoming_conferences %}
<li>{{ conference.date|date:"F d"}}: <a href="/conferences/
{{ conference.id }}">{{ conference.title }}</a></li>
{% endfor %}



</ul>

On Apr 11, 4:49 pm, Daniel Roseman <roseman.dan...@googlemail.com>
wrote:

Daniel Roseman

unread,
Apr 13, 2009, 2:30:47 PM4/13/09
to Django users
On Apr 11, 11:10 pm, codecowboy <guy.ja...@gmail.com> wrote:
> Thank you Daniel.  I got it working.  That link that you gave me
> helped me to figure it out.  I'm curious though, is there ever a
> reason in Django to define a method in a model class or would I always
> use a custom manager method?

It's frequently useful to define normal (instance) methods within
models, which operate on a single instance - eg to provide a formatted
or calculated version of one or more of the model fields for use in a
template, or to override the save method with some custom validation,
etc.

Whether or not you use class methods within a model is up to you - I
have used them as a useful place to define signals on a particular
model class, but you certainly don't need them for that.
--
DR.
Reply all
Reply to author
Forward
0 new messages