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 %}
但这不起作用。
想法?或者只在页面的某些部分放置某些字段的其他建议?
感谢。
答案 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 %}