Limiting the queryset for a foreign key field in the admin change_list view

27 views
Skip to first unread message

Margie

unread,
May 14, 2009, 8:26:44 PM5/14/09
to Django users
Sorry for the length of this - I hope someone knowledgable about ajax
has a minute to take a look, I've been working on it for awhile.
George - if you are reading this - this is my attempt to do the jquery/
ajax that you recommended a few days back when I posted a more general
question.

Ok - here's the high level: I have a Task model that contains an owner
field. In the admin change_list view for the task, I am am trying to
create a jquery ajax request that will override the queryset for the
task's owner field so that it contains the users returned by a GET
request to http://mysite.com/admin/taskmanager/task/get_owner_queryse
/<taskId>.

In other words, I don't want the queryset for owner to contain all
Users in the system, I want it to just contain the users that are
specified in the task's 'resources' field, which is a ManyToMany
field.

Note: all code is also at http://dpaste.com/44241 - more readable
there.

I'm trying hard to leverage the admin interface, which I think will
work for me if I can just figure out how to configure it with some
spiffy jquery/ajax.

I'm doing this by overriding formfield_for_foreignkey () so that it
uses a special OwnerSelectWidget for the 'owner' field, like this:



def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "owner":
kwargs["widget"] = OwnerSelectWidget()
return db_field.formfield(**kwargs)
return super(TaskAdmin, self).formfield_for_foreignkey
(db_field, request, **kwargs)

My OwnerSelectWidget looks like this:

class OwnerSelectWidget(widgets.Select):

class Media:
css = {}
js = (
'js/jquery.js',
)

def render(self, name, value, attrs=None):
rendered = super(OwnerSelectWidget, self).render(name, value,
attrs)
return rendered + mark_safe(u'''
<script type="text/javascript">
$('#id_%(name)s').mousedown(function() {
$.getJSON("get_owner_queryset/
NEED_TASK_ID_HERE",
function(data) {
var options = '';
for (var i = 0; i <
data.length; i++) {
/* set options based on
data - not quite sure how */
$('#id_%(name)s').html
(options);
})
})
</script>
''' % {'name': name, })

My code that services the GET is in my admin.py file and looks like
this:

class TaskAdmin(admin.ModelAdmin):

def __call__(self, request, url):
if url is None:
pass
else:
match = re.search('get_owner_queryset/(\d+)', url)
if match:
return self.getOwnerQuerySet(match.group(0))
else:
return super(TaskAdmin, self).__call__(request, url)

def getOwnerQuerySet(self, taskId):
task = Task.objects.get(taskId)
resourcesToReturn = task.resources.all() # resources are users
return HttpResponse(simplejson.dumps(resourcesToReturn),
mimetype='application/json')


I have a couple problems (so far that I know of).

1. In line 8 of the render() method, where I have NEED_TASK_ID_HERE,
I'm trying to figure out how I get the task id. It seems like at
this point in the code I don't have access to that. The id is
output as part of the change_list form, but it doesn't have an id
associated with it. What is the best approach to take?

2. In getOwnerQuerySet(), I don't think what I'm returning is
correct. When I play around in pdb and create a User queryset and
then try to call simplejson.dumps() on it:
resources = User.objects.all()
return HttpResponse(simplejson.dumps(resourcesToReturn),
mimtype='application/json')
I get the error:

*** TypeError: [<User: buck>, <User: bob>] is not JSON serializable

So I think I am not really returning the data correctly. And when I
run the app
this way, I get a 500 INTERNAL SERVER ERROR.

3. Once I do manage to return whatever it is that I'm supposed to
return (ie, question 2), I'm not quite sure what it is going to look
like when it gets back to the jquery callback function. I have a
little for loop in there, but I think I need to come up name/value
pairs. If the GET is returning a list of user names, where does the
value come from?


Ok - sorry for the length of this but I've been working for awhile now
on it and could really use some pointers from someone knowledgable out
there. I know there is doc on this simplejson stuff, but the first
time around, it's just hard to make sense of it all.

Margie

Colin Bean

unread,
May 14, 2009, 11:23:04 PM5/14/09
to django...@googlegroups.com
Re: your second question, you'll want to use django's built in serialization:
http://docs.djangoproject.com/en/dev/topics/serialization/

This nicely handles django models, and you can select a subset of
fields to include, etc. Instead of your simplejson call, you can use:
serializers.serialize("json", resourcesToReturn)

To take a stab at your third question, JSON is literally a bit of
javascript syntax that gets evaluated (JavaScript Object Notation :).
So from a serialized queryset you'll get (on the javascript side) a
list of objects with field names / data. So {'foo':'bar'} would give
you a javascript object (call it 'test'), and test.foo == 'bar'. In
your code you should be able to access an object in your loop with:
item = data[i]
Then try
item.fields.name (if your model field is "name", etc).
It might be helpful to look at a serialized queryset in the shell to
see how the JSON is structured.

Colin

Margie

unread,
May 15, 2009, 2:22:54 AM5/15/09
to Django users
Thanks Colin. I will try that. I also found a tutorial at
http://lethain.com/entry/2008/sep/21/intro-to-unintrusive-javascript-with-django/
that does some basic ajax stuff and that's useful to just get familiar
with the paradigm. Been studying this stuff all day, am too bleary
eyed to go any further tonight.

Margie

On May 14, 8:23 pm, Colin Bean <ccb...@gmail.com> wrote:
> On Thu, May 14, 2009 at 5:26 PM, Margie <margierogin...@yahoo.com> wrote:
>
> > Sorry for the length of this - I hope someone knowledgable about ajax
> > has a minute to take a look, I've been working on it for awhile.
> > George - if you are reading this - this is my attempt to do the jquery/
> > ajax that you recommended a few days back when I posted a more general
> > question.
>
> > Ok - here's the high level: I have a Task model that contains an owner
> > field.  In the admin change_list view for the task, I am am trying to
> > create a jquery ajax request that will override the queryset for the
> > task's owner  field so that it contains the users returned by a GET
> > request to  http://mysite.com/admin/taskmanager/task/get_owner_queryse
> > /<taskId>.
>
> > In other words, I don't want the queryset for owner to contain all
> > Users in the system, I want it to just contain the users that are
> > specified in the task's 'resources' field, which is a ManyToMany
> > field.
>
> > Note: all code is also athttp://dpaste.com/44241- more readable
Reply all
Reply to author
Forward
0 new messages