Admin : Select category -> show subcategory

2,341 views
Skip to first unread message

martyn

unread,
May 2, 2008, 5:05:47 AM5/2/08
to Django users
Hi,

I've created a simple product model :

class Produit(models.Model):
nom = models.CharField(maxlength=200)
slug = models.SlugField(prepopulate_from=('nom',))
description = models.TextField(blank=True)
published = models.BooleanField(default=True)
prix_ht = models.DecimalField(max_digits=30, decimal_places=2)
famille = models.ForeignKey('Famille')
sous_categorie = models.ForeignKey('SousCategorie')
clic

class Admin:
pass

I've got also Category and SubCategory :


class Categorie(models.Model):
nom = models.CharField(maxlength=200)
slug = models.SlugField(prepopulate_from=('nom',))
class Admin:
pass

def __str__(self):
return self.nom

class SousCategorie(models.Model):
nom = models.CharField(maxlength=200)
slug = models.SlugField(prepopulate_from=('nom',))
categorie = models.ForeignKey('Categorie')
class Admin:
pass

def __str__(self):
return self.nom



Is there a way in django admin, in the Product form, to select the
category, then the subcategories of this category only are shown in
the select list.

Thanks a lot

Diego Ucha

unread,
May 3, 2008, 8:26:10 PM5/3/08
to Django users
Hello Martyn,

The main interaction, that i see you need is:
(On Product form) User select Category -> Subcategory field is auto-
filled -> User select a subcategory based on the category selected.

Then you will have to use some JS Library (I prefer JQuery, besides
there are some discussion about those libs on the list).

For filling this subcategory field, in terms of data transmission, i
use JSon, because JQuery has a fine JSon parser, in few lines it's all
done.

[]s,
Diego Ucha

martyn

unread,
May 5, 2008, 2:49:09 AM5/5/08
to Django users
Thank you, it's just what I wanted, but do I have to write a new
template (admin/model_name/etc...) ?
Or can I define this directly in my model (onchange actions...) ?

I have the django Book (definitive guide to django) but I can't find
this.



On 4 mai, 02:26, Diego Ucha <diegou...@gmail.com> wrote:
> HelloMartyn,
>
> The main interaction, that i see you need is:
> (On Product form) User select Category -> Subcategory field is auto-
> filled -> User select a subcategory based on the category selected.
>
> Then you will have to use some JS Library (I prefer JQuery, besides
> there are some discussion about those libs on the list).
>
> For filling this subcategory field, in terms of data transmission, i
> use JSon, because JQuery has a fine JSon parser, in few lines it's all
> done.
>
> []s,
> Diego Ucha
>

Diego Ucha

unread,
May 5, 2008, 2:28:45 PM5/5/08
to Django users
First of all, I recommend that you read chapter 17 of Django Book (if
you haven't already) http://www.djangobook.com/en/1.0/chapter17/

Moving on, you have to create a view, as we are working on Django's
admin, then i recommend that you create one like project/app/
admin_views.py with something similar to this code:

from indica.geral.models import *
from django.http import HttpResponse
from django.template import RequestContext
from django.utils import simplejson
from django.contrib.admin.views.decorators import
staff_member_required

def country_getStates(request):
id = request.GET.get('id','')
result = [u.__dict__ for u in State.objects.filter(country=id)]
return HttpResponse(simplejson.dumps(result), mimetype='application/
javascript')
country_getStates = staff_member_required(country_getStates)

Then, you have to customize the change_form.html template with the JS
call, something like this (as you can see, i am using JQuery):

{% extends "admin/change_form.html" %}

{% block extrahead %}
<script src="http://SERVERNAME/js/jquery-1.2.3.min.js" type="text/
javascript"></script>
<script type="text/javascript" charset="utf-8">
$(function(){
$("select#id_country").change(function(){
$.getJSON("/admin/bd1/country/getStates/",{id: $(this).val()},
function(j){
var options = '<option value="">---------</option>';
for (var i = 0; i < j.length; i++) {
options += '<option value="' + j[i].id + '">' + j[i].state +
'</option>';
}
$("select#id_state").html(options);
})
})
})
</script>
{% endblock %}

Create a JS file and put this second script tag in it, that way will
be easier to maintain your template.

At urls.py you need to add a pattern to reach the view:

(r'^admin/bd1/country/getStates/$',
'project.app.admin_views.country_getStates'),

This is the classic example of a country -> state interaction, the
same for your category -> subcategory need.

[]s,
Diego Ucha

martyn

unread,
May 8, 2008, 9:22:50 AM5/8/08
to Django users
That's it !
I'm discovering JQuery, not very "sexy" for the first time, but seems
to be really powerfull.

Thank you Diego.
Django community really rocks.

martyn

unread,
May 8, 2008, 10:22:44 AM5/8/08
to Django users
The Javascript Function does not seem to be executed.
In admin_form.html :

{% extends "admin/change_form.html" %}

{% block extrahead %}
<script src="http://127.0.0.1/django-medias/chantier/js/
jquery-1.2.3.js" type="text/javascript"></script>
<script type="text/javascript" charset="utf-8">
$(function(){
$("select#id_categorie").change(function(){
$.getJSON("/admin/boutique/produit/getsubcategory/",{id: $
(this).val()},
function(d){
alert("here")
var options = '<option value="">---------</option>';
for (var i = 0; i < j.length; i++) {
options += '<option value="' + j[i].id + '">' + j[i].nom +
'</option>';
}
$("select#id_sous_categorie").html(options);
})
alert("there")
})
})

</script>
{% endblock %}


The only alert I've got is [[there]] and never [[here]].
All seems to be fine except this...

An idea ?

Diego Ucha

unread,
May 8, 2008, 9:05:05 PM5/8/08
to Django users
You're welcome, Martyn.

You changed the argument of this nested function and didn't change the
reference to it in the subsequent code:
function(d){

What about replacing it for:
function(j){

Your code would look like that:

<script src="http://127.0.0.1/django-medias/chantier/js/
jquery-1.2.3.js" type="text/javascript"></script>
<script type="text/javascript" charset="utf-8">
$(function(){
$("select#id_categorie").change(function(){
$.getJSON("/admin/boutique/produit/getsubcategory/",{id: $
(this).val()},
function(j){
alert("here")
var options = '<option value="">---------</option>';
for (var i = 0; i < j.length; i++) {
options += '<option value="' + j[i].id + '">' + j[i].nom +
'</option>';
}
$("select#id_sous_categorie").html(options);
})
alert("there")
})

})
</script>


[]s
Diego Ucha

martyn

unread,
May 13, 2008, 1:23:26 AM5/13/08
to Django users
It's true, I don't know for what reason I changed this before posting,
but I've seen the error to, correct it and, no way.
But I made a error on my urls,
this /admin/boutique/produit/getsubcategory/ was not the same as
urls.py, so I had no response.

Now I've got another question. I've never used jQuery and I'm also new
to django.
I can't find the way to don't repeat my self on loading my object and
show the subcategory with jQuery.

On load
1- Load the results for the current category
2- Select the current subcategory

<script type="text/javascript" charset="utf-8">
$(function(){
$("select#id_categorie").change(function(){
$.getJSON("/admin/boutique/produit/getsubcategory/",{id: $
(this).val()}, function(j){
var options = '<option value="">---------</option>';
for (var i = 0; i < j.length; i++) {
options += '<option value="' + j[i].id + '">' + j[i].nom + '</
option>';
}
$("select#id_sous_categorie").html(options);
})
})
})

$(document).ready(function(){
$.getJSON("/admin/boutique/produit/getsubcategory/",{id:
document.getElementById("id_categorie").value}, function(j){
var options = '<option value="">---------</option>';
for (var i = 0; i < j.length; i++) {
options += '<option value="' + j[i].id + '">' + j[i].nom + '</
option>';
}
$("select#id_sous_categorie").html(options);
})
});
// HOW TO GET {{ object.subcategory }} ?
</script>

Diego Ucha

unread,
May 17, 2008, 7:22:03 PM5/17/08
to Django users
You need to set a Subcategory as default when this field is loaded by
the field Category?
Sorry Martyn, i didn't get your doubt, could you elaborate more?

martyn

unread,
May 20, 2008, 4:53:02 AM5/20/08
to Django users
In fact, at the creation, you select a category, the the subcategories
are shown. It's OK
But, a

martyn

unread,
May 20, 2008, 4:59:18 AM5/20/08
to Django users
In fact, at the creation, you select a category, the the
subcategories
are shown. It's OK

/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-
===Create_Object===

Category
[--select_category--]

SubCategory
[--select_subcategory--]

/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-

But, at the modification / edition of an object, I have to set the
right category and the right subcategory.

/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-
===Edit_Object===

Category
[--shoes--]

SubCategory
[--pretty_shoes--]

/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-/*-

All I want is not to right the same javascript code twice
(on_selectlist_change == on_document_ready)
I don't know the better way to do this in django FW.
The only thing I did is to right the same code twice... It's not the
DRY philosophy of Django.

Diego Ucha

unread,
May 20, 2008, 9:38:34 PM5/20/08
to Django users
Ok Martyn, understood.
Mainly that piece of code represents many functions, one inside the
other, since you need to reuse one, than you could declare this inner
function that you are aiming at, outside the event and call it on the
event(s) (in your case onchange and document ready).
That way you will have to write this function only once.
What do you think?

[]s
Diego Ucha

Declare it somewhere else, and call him from the event

martyn

unread,
May 21, 2008, 6:43:10 AM5/21/08
to Django users
Stupid me, yes you're absolutly right.
It could be something like this

$(document).ready(function(){
changeMySelect();
# ... and select my subcategorie too.
}

$("select#id_categorie").change(function(){
changeMySelect();
}

function changeMySelect(){
...do something to change my select list...
}

I'm not sure about the exact syntax, but the jquery IRC or
documentation could help me.

Thank you Diego
Reply all
Reply to author
Forward
0 new messages