开发者

Django display value of extra field in modelform

How do I set the value of a field (which is relevant to form, but not based directly on the same model) on a (model) form when it is displayed in the admin?

Here is a simplified version of what I have (my actual app/model/etc is more complicated):

  • A building has many rooms
  • A room has many pieces of equipment

Models:

#spaces/models.py
from django.db import models    

class Building(models.Model):
    name=models.CharField(max_length=32)
    def __unicode__(self):
      return self.name

class Room(models.Model):
    number=models.CharField(max_length=8)
    building=models.ForeignKey(Building)
    def __unicode__(self):
        return self.number

class Equipment(models.Model):
    tech = models.CharField(max_length=64)
    room = models.ForeignKey(Room)
    def __unicode__(self):
     return self.tech

When adding or editing a piece of equipment, it would be nice to be able to limit the room choices down (by building). This I can do: I add a building field to the ModelForm, and then as it gets changed by the user, a bit of JQuery in the template file dynamically updates the list of rooms. The admin.py part looks like:

#spaces/admin.py
from demo.spaces.models import Building, Room, Equipment
from django.contrib import admin
from django import forms


class EquipmentForm(forms.ModelForm):
     class Meta:
      model = Equipment
     building = forms.ModelChoiceField(Building.objects)

class EquipmentAdmin(admin.ModelAdmin):
     form = EquipmentForm

admin.site.register(Equipment, EquipmentAdmin)
admin.site.register(Building)
admin.site.register(Room)

When adding a new piece of equipment, this all works fine--my JQuery code displays ----- until a building is selected, at which point the drop down for the room field is enabled and populated with the appropriate rooms for that building.

The problem is: when displaying an existing piece of equipment (demo.com/admin/spaces/equipment/12/) or if the add form doesn't validate,开发者_StackOverflow社区 the Room field properly displays the room --but the building field is wiped out. The equipment.room foreign key value exists in the form instance and the admin automagically takes care of setting the room field to that value, but the value of the building field needs to be set by me.

I can get the value without a problem, since it's easy in the init of the form to check for it being an instance, and then traversing back up to get the value:

def __init__(self, *args, **kwargs):  
     super(EquipmentForm, self).__init__(*args, **kwargs)  
     if 'instance' in kwargs:
        building_value = kwargs['instance'].room.building

But what do I do with that value to make the field display it? The only thing I haven't tried yet is adding more code in my template to use Jquery to get the value and set it at the end, but I'd rather not have to have the javascript in the page hit the database to figure display the value, since it seems like something that should be done when the form is rendered...

Any thoughts? Thank you for you help!


Check the initial parameter of the Field in forms here. Maybe setting building with initial set to a Building object would help.


Also, do you really need to limit choices down to a building? I'd just found sufficient to modify the Room's __unicode__ method, so it shows both Building and Room number:

def __unicode__(self):
    return "Room nr %s in %s" % (self.number, self.building)

Then you'll get a list of all rooms, but easy to find out to which building they belong to...


This one should work:

class EquipmentForm(ModelForm):
    def __init__(self, *args, **kwargs):
        kwargs['initial']=kwargs.get('initial',{})
        if kwargs['instance']:
            kwargs['initial']['building']=kwargs['instance'].building
        super(EquipmentForm, self).__init__(*args, **kwargs)  

In the views.py:

instance.building="some_building"
form = EquipmentForm(request.POST, instance=instance)


What about this?

def __init__(self, *args, **kwargs):  
 super(EquipmentForm, self).__init__(*args, **kwargs)  
 if 'instance' in kwargs:
    self.data['building']=kwargs['instance'].room.building


This works for me:

def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
                 initial=None, error_class=ErrorList, label_suffix=':',
                 empty_permitted=False, instance=None):
        if instance:
            initial = initial or {}
            initial['field_name'] = instance.some_value

        super(MyCustomForm, self).__init__(data, files, auto_id, prefix,initial,
                error_class, label_suffix,empty_permitted, instance)

I intentionally don't use *args, **kwargs cause I didn't check how this constructor is called elswere in the code (instance and initial could be in *args or **kwargs).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜