2009-12-16 90 views
3

如何在管理中显示(模型)表单时设置字段的值(与表单相关,但不直接基于同一模型)?Django在模型中显示额外字段的值

这里是什么,我有一个简化版本(我的实际应用程序/模型/等比较复杂):

  • 一个building有许多room小号
  • 一个room有很多的equipment

型号:

#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 

当添加或编辑一件设备时,能够限制room的选择(通过建筑)会很好。我可以这样做:我将一个building字段添加到ModelForm中,然后在用户更改后,模板文件中的一些JQuery动态更新room的列表。该admin.py部分看起来像:

#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) 

当添加新的一块equipment,这一切工作正常 - 我的jQuery代码显示-----,直到建筑物被选中,此时下拉的room场启用并为该建筑填充适当的room

的问题是:显示一个现有的一件设备(demo.com/admin/spaces/equipment/12/)时,或者如果加载的形式不验证,则Room字段正确显示room - 但在building字段被消灭了。 外键值存在于表单实例中,并且管理员自动地将room字段设置为该值,但building字段的值需要由我设置。

我能得到的值不会有问题,因为它很容易在形式的初始化,以检查它作为一个实例,然后穿越回了来获取值:

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

但我该如何处理这个值才能使该字段显示出来?我还没有尝试过的唯一的事情是在我的模板中添加更多的代码来使用Jquery获取值并将其设置在最后,但我宁愿不必让页面中的JavaScript命中数据库来显示数字价值,因为它似乎是当表单呈现时应该做的事情...

有什么想法?谢谢你的帮助!

回答

1

here的形式检查Fieldinitial参数。也许将初始设置为Building对象的建筑物会有所帮助。


另外,你是否真的需要限制选择到建筑物?我刚刚找到足够改变Room__unicode__方法,所以它同时显示BuildingRoom号:

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

然后你会得到所有的房间列表,但不难看出,其建筑他们属于...

+0

我宁愿能够限制对建筑物的选择,因为A)将会有几百个房间,和B)我想使用相同的程序来限制其他地方的其他外键。 – mightyhal 2009-12-16 16:45:34

+0

field.initial不会帮助,因为我想为该建筑物设置的值是动态的(取决于实例)。 Form.initial看上去很有希望,在__init__中设置self.initial ['building'],并且一个print self.initial将所有字段及其值的字典回传出来......但是当它呈现时,它不会设置值(虽然看起来应该是这样) – mightyhal 2009-12-16 16:51:23

0

这是怎么回事?

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

修改__init__中的self.data ['building']没有任何效果。 (在__init__中删除print self.data会给我一个{},所以我可能需要重写__init__以影响self.data,或者self.data不是正确的修改) – mightyhal 2009-12-16 16:44:13

0

这个工作对我来说:

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) 

我故意不使用*指定参数时,** kwargs因为我没有检查如何构造函数中的代码(例如和初始elswere叫可能在* args或** kwargs)。

1

这一个应该工作:

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) 

在views.py:

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