views:

106

answers:

3

I have models like this:

class User(models.Model): 
    Switch = models.ForeignKey(Switch, related_name='SwitchUsers') 
    Port = models.ForeignKey(Port) 
class Switch(models.Model): 
    Name = models.CharField(max_length=50) 
class Port(models.Model): 
    PortNum = models.PositiveIntegerField() 
    Switch = models.ForeignKey(Switch, related_name = "Ports") 

When I'm in Admin interface and choose Switch from Switches available, I would like to have Port prepopulated accordingly with Ports from the related Switch. As far as I understand I need to create some JS script to prepopulate it. Unfortunately I don't have this experience, and I would like to keep things simple as it possible and don't rewrite all Django admin interface. Just add this functionality for one Field.

Could you please help me with my problem? Thank you.

A: 

You are correct that you will need some js to create this. You don't need to re-write the django admin interface. You only need to customize it. This type of a thing requires a few things.

Start here: http://docs.djangoproject.com/en/1.2/ref/contrib/admin/#modeladmin-objects

To include your javascript use the Media class.

The django forms give all form inputs consistent ids so it is easy to manipulate them. You will need, however, to "pass" your relationship to the client. I mean, on the client you'll need to know which Ports go with which Switch. Depending on how much data you have, there are a couple of approaches for this:

  • Encode the relationship in json and output it in a tag by customizing the admin template for your model.

  • Use ajax. You'll need at least one extra view that takes a Switch and returns a json list (or something similar) for the Ports that go with it.

The javascript maniuplation should be straight forward: you want to bind the onChange() event of the dropbox to a function that strips all but the relevant Ports in the Port dropbox.

I'd suggest doing your DOM manipulation using jquery.

rz
A: 

You can end up with a simpler solution than provided above. Instead of customizing template and putting json in a tag, put this json in the beginning of you js file, also put there $().ready call that will assign the listener to the select-box change event, and reference this js file into the ModelAdmin's Media.

class MyAdmin(admin.ModelAdmin):
    class Media:
        js = ("my_code.js",)

Tip: use Firebug or Chrome inspector to investigate the real names of HTML fields on the form.

Guard
Thank you for the comment. Looks like the easiest way to achieve what I need. Just one question about JQuery in Django admin. I've tried something like:$("#id_Switch").click( function() { alert("hello");});But it doesn't work. FireBug tells me that $ is undefined.HTML code looks like:<form id="user_form" method="post" action="" enctype="multipart/form-data"><select id="id_Switch" name="Switch"><option selected="selected" value="">---------</option><option value="1">ds-27-1</option></select></form>From my understanding of JQuery it should work but it doesn't.
onorua
you should include jquery.js in your page too - through Media for specific admin class, or globally through inheriting the entry editing template and overriding the extrahead (or something like this) block
Guard
A: 

I understand that this is a shortcut, and may not be optimal, but have you considered combining the two select widgets into a single one using optgroups? It would save you from writing custom javascript.

Since it's a ForeignKey, if they select a port, you know what the switch is. You could have the switches be optgroups, with a value of "", so they can't save after selecting just a switch. Here are the steps I can see:

  1. Customize the form fields to omit switch.
  2. Change the title of the port form field to Switch/Port.
  3. Change the choices of the port form field to a tuple, generated from the switches/ports.
  4. Add a custom view for saving that gets the switch from the port and sets the switch of the user to it.

If the users/stakeholders would find this acceptable, it's a way to get around JavaScript programming that involves a fair bit of Django programming.

Ben Atkin