Django - 模型字段的自定义属性

时间:2011-12-06 22:31:21

标签: django tabs

Django中是否有一种方法可以将自定义属性添加到模型的字段中(无需借助子类化字段)?

我只想在模板的某些部分显示某些字段。这是因为最终每种类型的字段都将显示在单独的选项卡中。我想为每个字段添加一个自定义属性,以确定它应该进入哪个部分/标签。但到目前为止,我没有运气。

我有几种字段类型:

class Enum(set):
    def __getattr__(self, name):
        if name in self:
            return name
        raise AttributeError

FieldTypes = Enum(["one","two","three",])

以及一些模特:

class Model1(models.Model):
  a = models.CharField()
  b = models.ForeignKey('Model2')
  c = models.IntegerField()
  a.type = FieldTypes.one  # this obviously doesn't work
  b.type = FieldTypes.two  # this obviously doesn't work
  c.type = FieldTypes.three  # this obviously doesn't work

class Model2(models.Model):
  d = models.CharField()

表格:

class Form1(forms.ModelForm):
  class Meta:
    model = Mode1

一个模板:

{% for fieldType in FieldTypes %}
  <div class="{{fieldType}}">
      {% for field in form %}
        {% if field.type = fieldType %}
          {{ field }}
         {% endif %}
      {% endfor %} 
  </div>
{% endfor %}

但这不起作用。

想法?或者只在页面的某些部分放置某些字段的其他建议?

感谢。

3 个答案:

答案 0 :(得分:2)

通常,我会将此逻辑保留在模型类之外。如果您可以提供帮助,模型不应该与表示元素纠缠在一起,并且选择在表单中显示哪些字段似乎是表示关注点。幸运的是,Form类在数据层(模型)和表示层(视图和模板)之间提供了一个很好的,以UI为中心的层。

以下是我过去解决这个问题的方法。在我的Form类中,我创建了一个字段组列表,每个字段组都有一个标题和它们包含的字段名称列表:

class MyModelForm(forms.ModelForm):
    field_groups = (
        {'name':'Group One', 'fields':('a', 'b', 'c')},
        {'name':'Group Two', 'fields':('d', 'e')},
    )
    class Meta:
        model = MyModel

然后在模板中,我循环遍历组,并在该循环内有条件地包括那些字段:

{% for group in form.field_groups %}
<h3 class="groupheader">{{group.name}}</h3>
    {% for field in form %}
        {% if field.name in group.fields %}
        <div class="fieldWrapper">
            {{ field.errors }}
            {{ field.label_tag }}: {{ field }}
        </div>
        {% endif %}
    {% endfor %}
{% endfor %}

这允许您控制MyModelForm类中表单字段的分组和显示,这是表示逻辑生存的合理位置。

答案 1 :(得分:0)

这是可能的!

class Model1(models.Model):
   a = models.CharField()
   b = models.ForeignKey('Model2')
   c = models.IntegerField()

表格:

class Form1(forms.ModelForm):

  def __init__(self, *args, **kwargs):
    super(Form1, self).__init__(*args, **kwargs)
    self.fields['a'].type = FieldTypes.one  # this obviously doesn't work
    self.fields['b'].type = FieldTypes.two  # this obviously doesn't work
    self.fields['c'].type = FieldTypes.three  # this obviously doesn't work


  class Meta:
    model = Mode1

答案 2 :(得分:0)

原来,我确实想在我的模型类中使用这个逻辑;字段类型不仅用于解决显示它们的位置/方式(尽管它们也用于此)。我提出了以下解决方案。

我定义了一些类来存储一组字段类型:

class FieldType(object):
    def __init__(self, type=None, name=None):
        self._type = type
        self._name = name

    def getType(self):
        return self._type

    def getName(self):
        return self._name

class FieldTypeList(deque):
    def __getattr__(self,type):
        for ft in self:
            if ft.getType() == type:
                return ft
        raise AttributeError

FieldTypes = FieldTypeList([FieldType("ONE","The Name Of Field One"),FieldType("TWO","The Name Of Field Two")])

一些模型,每个模型都有一组从字段类型到特定字段名称的映射(在此示例中,字段'a','b'和'c'的类型为'ONE'和字段'd '属于'TWO'类型):

class ParentModel(models.Model):
  _fieldsByType = {}

  a = models.CharField()
  b = models.CharField()

  def __init__(self, *args, **kwargs):
      super(ParentModel, self).__init__(*args, **kwargs)
      for ft in FieldTypes:
        self.setFieldsOfType(ft, [])
      self.setFieldsOfType(FieldTypes.ONE, ['a','b'])

  def setFieldsOfType(self,type,fields):
    typeKey = type.getType()
    if typeKey in self._fieldsByType:
      self._fieldsByType[typeKey] += fields
    else:
      self._fieldsByType[typeKey] = fields

class ChildModel(ParentModel):
  _fieldsByType = {}   # not really sure why I have to repeat this attribute in the derived class

  c = models.CharField()
  d = models.CharField()

  def __init__(self, *args, **kwargs):
    super(ChildModel, self).__init__(*args, **kwargs)
    self.setFieldsOfType(FieldTypes. ['c'])
    self.setFieldsOfType(FieldTypes. ['d'])

我有一个基本形式:

class MyForm(forms.ModelForm):
  class Meta:
    model = ChildModel

一个自定义过滤器,用于从特定表单返回给定类型的所有字段(注意,通过其Meta类从表单访问模型):

@register.filter
def getFieldsOfType(form,type):
    return form.Meta.model._fieldsByType[type.getType()]

最后,一个模板将它们全部拉到一起(模板采用MyForm和FieldTypes):

  {% for type in types %}
    <div id="{{type.getType}}">
      {% with fieldsOfType=form|getFieldsOfType:type %}
        {% for field in form %}
          {% if field.name in fieldsOfType %}
            <p>
              {{ field.errors }}
              {{ field.label_tag }}: {{ field }}
            </p>
          {% endif %}
        {% endfor %}
      {% endwith %}
    </div>
  {% endfor %}