【问题标题】:Django display value of extra field in modelformDjango在模型表单中显示额外字段的值
【发布时间】:2009-12-16 05:25:37
【问题描述】:

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

这是我所拥有的简化版本(我的实际应用程序/模型/等更复杂):

  • 一个building 有很多rooms
  • 一个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 会动态更新rooms 的列表。 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 字段的下拉列表被启用并填充适合该建筑物的rooms。

问题是:在显示现有设备 (demo.com/admin/spaces/equipment/12/) 或添加表单未通过验证时,Room 字段会正确显示 room -- 但是building 字段被清除。 equipment.room 外键值存在于表单实例中,管理员自动将room 字段设置为该值,但building 字段的值需要由我设置。

我可以毫无问题地获取值,因为很容易在表单的 init 中检查它是否是一个实例,然后向上遍历以获取值:

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

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

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

【问题讨论】:

    标签: django field django-forms


    【解决方案1】:

    在here 表单中检查Field 的initial 参数。也许将初始设置为 Building 对象的构建会有所帮助。


    另外,您真的需要将选择限制在建筑物内吗?我刚刚发现足以修改Room 的__unicode__ 方法,因此它同时显示Building 和Room 编号:

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

    然后您将获得所有房间的列表,但很容易找出它们属于哪个建筑物...

    【讨论】:

    • 我更希望能够限制建筑物的选择,因为 A)将有几百个房间,并且 B)我想使用相同的程序来限制其他外键在其他地方。
    • field.initial 无济于事,因为我想为建筑物设置的值是动态的(取决于实例)。 Form.initial 看起来很有希望,在 init 中设置 self.initial['building'],然后打印 self.initial 会返回一个包含所有字段及其值的字典......但是当它呈现时,它没有设置构建的价值(尽管看起来应该)
    【解决方案2】:

    这个应该可以的:

    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)
    

    【讨论】:

      【解决方案3】:

      这个怎么样?

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

      【讨论】:

      • 在 init 中修改 self.data['building'] 无效。 (在 init 中删除打印 self.data 会给我一个 {},所以也许我需要覆盖除 init 之外的其他内容以影响 self.data 或 self.data不是正确的修改)
      【解决方案4】:

      这对我有用:

      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)
      

      我故意不使用 *args, **kwargs,因为我没有检查代码中如何调用此构造函数(实例和初始值可能在 *args 或 **kwargs 中)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-07
        • 1970-01-01
        • 1970-01-01
        • 2012-08-19
        • 1970-01-01
        • 2013-07-16
        • 1970-01-01
        • 2011-01-15
        相关资源
        最近更新 更多