Django - custom attributes for model fields

与世无争的帅哥 提交于 2020-01-24 22:02:11

问题


Is there a way in Django to add custom attributes to a model's fields (without resorting to subclassing fields)?

I would like to only display certain fields in certain sections of my template. This is because eventually each type of field will be displayed in a separate tab. I thought about adding a custom attribute to each field to identify which section/tab it should go in. But, so far, I've had no luck.

I have a few field types:

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

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

And a few models:

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

And a form:

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

And a template:

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

But this doesn't work.

Ideas? Or other suggestions for only placing certain fields in certain sections of the page?

Thanks.


回答1:


In general, I would keep this logic outside of the model class. Models shouldn't be tangled up with presentation elements if you can help it, and choosing which fields to display in a form seems like a presentation concern. Fortunately, the Form class provides a nice, UI-focused layer between the data layer (the model) and the presentation layer (the view and template).

Here's how I've addressed this in the past. In my Form class, I created a list of field groups, each with a title and a list of the names of the fields they contain:

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

Then in the template, I looped through the groups, and within that loop conditionally included those fields:

{% 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 %}

This allows you to control the grouping and display of form fields within the MyModelForm class, which is a reasonable place for presentation logic to live.




回答2:


It's posible!

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

And a form:

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



回答3:


Turns out, that I do want this logic in my model class; the field types are used for more than just working out where/how to display them (though they are used for that too). I have come up with the following solution.

I defined some classes to store a set of field types:

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")])

And a few models each of which has a set of mappings from field types to particular field names (In this example, fields 'a', 'b', and 'c' are of type 'ONE' and field 'd' is of type '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'])

I have a basic form:

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

And a custom filter to return all fields of a given type from a particular form (note, the accessing the model from the form via its Meta class):

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

And, finally, a template to pull it all together (the template takes MyForm and 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 %}


来源:https://stackoverflow.com/questions/8407837/django-custom-attributes-for-model-fields

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!