#This requires Mootools. #Get it at http://mootools.net/downloads/mootools-1.2-core-yc.js #I put mine in media/js. #**Here are the models:** from django.db import models class Category(models.Model): name = models.CharField(max_length=255) def __unicode__(self): return self.name class Meta: app_label = 'product' verbose_name_plural = 'Categories' class SubCategory(models.Model): category = models.ForeignKey('Category') name = models.CharField(max_length=255) def __unicode__(self): return self.name class Meta: app_label = 'product' verbose_name = 'Sub-Category' verbose_name_plural = 'Sub-Categories' STATUS = ( ( 'A', 'Active' ), ( 'I', 'Inactive' ), ( 'O', 'Out of Production'), ) class Product(models.Model): name = models.SlugField(max_length=255) status = models.CharField(max_length=2, choices=STATUS, default='I') subcategory = models.ForeignKey(SubCategory) brand = models.CharField(max_length=255, blank=True) manufacturer = models.CharField(max_length=255, blank=True) description = models.TextField() short_description = models.CharField(max_length=255, blank=True) part_number = models.CharField(max_length=50, blank=True) model_number = models.CharField(max_length=50, blank=True) quantity = models.IntegerField(null=True, blank=True) image = models.ImageField(upload_to='product_images', blank=True) image_thumbnail = models.ImageField(upload_to='product_images', blank=True) created = models.DateField(auto_now_add=True) def __unicode__(self): return self.name.title() class Meta: app_label = 'product' #**Then in admin.py:** from django.contrib import admin from django import forms from vacancy.product.models import Category, SubCategory, Product #first create a custom form to use in admin class ProductAdminForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(ProductAdminForm, self).__init__(*args, **kwargs) print dir(self.instance) try: #Try and set the selected_cat field from instance if it exists self.fields['selected_cat'].initial = self.instance.subcategory.category.id except: pass #The product model is defined with out the category, so add one in for display category = forms.ModelChoiceField(queryset=Category.objects.all().order_by('name'), widget=forms.Select(attrs={'id':'category'}), required=False) #This field is used exclusively for the javascript so that I can select the #correct category when editing an existing product selected_cat = forms.CharField(widget=forms.HiddenInput, required=False) class Meta: model = Product class Media: #Alter these paths depending on where you put your media js = ( 'js/mootools-1.2-core-yc.js', 'js/product.js', ) class ProductAdmin(admin.ModelAdmin): form = ProductAdminForm #I don't like using a fieldset here, because it makes the form more brittle, #if you change the model for form be sure to update the fieldset. #I'm using it in this instance because I need for category to show up #right above the subcategory fieldsets = ( (None, { 'fields' : ('name','status','category','subcategory','description') }), ('Optional', { 'classes' : ('collapse',), 'fields' : ('brand','manufacturer','short_description','part_number','model_number','image','image_thumbnail','selected_cat') }) ) admin.site.register(Product, ProductAdmin) #**put this file in your media dir (ex: project_foo/media/js/product.js):** window.addEvent('domready',function() { //You may will need to change category, id_subcategory, and id_selected_cat //to match the names of the fields that you are working with. var category = $('category'); var subcategory = $('id_subcategory'); var update_subcat = function() { var cat_id = $('id_selected_cat').value; if (cat_id) { $('id_selected_cat').value=''; category.value=cat_id; } else { cat_id = category.getSelected()[0].value; } //cat_id = category.getSelected()[0].value; var subcat_id = subcategory.getSelected()[0].value; var request = new Request.JSON({ url: "/product/subcategory/"+cat_id+"/", onComplete: function(subcats){ subcategory.empty(); if (subcats) { subcats.each(function(subcat) { var o = new Element('option', { 'value':subcat.pk, 'html':subcat.fields.name }); if (subcat.pk == subcat_id) { o.set('selected','selected'); } o.inject(subcategory); }); } else { var o = new Element('option', { 'value':'', 'html':'Please Choose A Category First' }); o.inject(subcategory); } } }).get(); }; update_subcat(); category.addEvent('change', function(e){ e.stop(); update_subcat(); }); }); #**Then create the view to handle the ajax subcategory request:** urls.py: urlpatterns = patterns('', url(r'^subcategory/(?P\d*)/$', 'foo.app.views.subcategory', name='subcategory'), ) views.py: from django.http import HttpResponse from django.core import serializers def subcategory(request, category_id): return HttpResponse(serializers.serialize('json', SubCategory.objects.filter(category=category_id), fields=('pk','name')))