Why is not there a reusable template for Django's DetailView?

后端 未结 2 1031
生来不讨喜
生来不讨喜 2021-01-18 02:48

Displaying forms in a template is rather easy in Django:

{% csrf_token %} {{ form }}
相关标签:
2条回答
  • 2021-01-18 03:23

    I have created and have been using gladly for about a year now my own generic templates. So, I wanted to share, here it is:

    Creating a view is as simple as this:

    class PersonDetail(DetailViewParent):
        model=Person
    

    DetailViewParent used above (override fields and exclude as needed; default is to include all):

    class DetailViewParent(DetailView):
        fields=[]
        exclude=[]
        template_name='common/modal_detail.html'
    
        def get_context_data(self, **kwargs):
            context=super(DetailViewParent, self).get_context_data(**kwargs)
            context['exclude']=self.exclude
            context['fields']=self.fields
            return context
    

    Relevant part of the template:

      {% fields %}
      {% for name, label, value, is_link in fields %}
        <tr>
          <td><strong>{{ label|capfirst }}</strong></td>
          <td>
            {% if value.get_absolute_url and request.is_ajax %}
              <a class="modal-loader" href="{{ value.get_absolute_url }}">{{ value }}</a>
            {% elif value.get_absolute_url %}
              <a href="{{ value.get_absolute_url }}">{{ value }}</a>
            {% else %}
              {% if is_link and request.is_ajax %}
                <a class="modal-loader" href="{{ value }}">{{ value }}</a>
              {% elif is_link %}
                <a href="{{ value }}">{{ value }}</a>
              {% else %}
                {{ value }}
              {% endif %}
            {% endif %}
          </td>
        </tr>
      {% endfor %}
    

    And the template tags:

    @register.tag(name="fields")
    def generate_fields(parser, token):
        """
        {% fields %} - loads field name, label, value, is_link to the context
        """
        args=token.contents.split()
        object_name='object'
        if len(args) == 2:
            object_name=args[1]
        return FieldsNode(object_name)
    
    
    class FieldsNode(template.Node):
        """
        called by generate_fields above
        """
    
        def __init__(self, object_name):
            self.object_name=object_name
    
        def render(self, context):
            # Get the data necessary for rendering the thing, and add it to the context.
    
            try:
                obj=template.Variable(self.object_name).resolve(context)
            except template.VariableDoesNotExist:
                return ''
    
            include_fields=context.get("fields", None)
            exclude_fields=context.get("exclude", None)
    
            fields=[]
            for field in obj._meta.fields:
                name=field.name
    
                if exclude_fields and name in exclude_fields:
                    continue
    
                if include_fields and name not in include_fields:
                    continue
    
                label=field.verbose_name
                value=getattr(obj, field.name)
                is_link=(type(field).__name__ in ('URLField',))
    
                if isinstance(value, bool):
                    value=get_bool_check_mark(value)
                elif value is None:
                    value=''
    
                fields.append((
                    name, label, value, is_link,
                    ))
    
            # If include_fields was defined, then sort by the order.
            if include_fields:
                fields=sorted(fields, key=lambda field_: include_fields.index(field_[0]))
    
            context['fields']=fields
    
            return ''
    

    The template might be customized to your needs and liking. But I would like to note two things:

    1) get_absolute_url: if this (standard django) model method is defined, the field value is shown as url.

    2) modal-loader class: this triggers js on the client side to show the detail view in a bootstrap 3 modal. Furthermore, if clicked on a link as mentioned in 1) that is loaded onto the same modal, thus making it easier to browse detail views. It has also a "back" button to go back to the previous model's view. I am not including that here because it is a lot of code, and beyond the scope of this question.

    0 讨论(0)
  • 2021-01-18 03:29

    I think it is not as reusable as you imagine.

    It might conceivably be possible to define "standard" ways to render simple model properties like CharField - this quickly becomes impossible when you get into more complex relational fields like ManyToManyField, ForeignKey, OneToOneField. You would end up overriding any default representation very quickly for anything but the simplest of models.

    Secondly Django is not - and should not be - opinionated about what your models are for, and therefore it makes sense that it doesn't try to assume how you want to render them.

    This is different from forms where the structure of individual form fields is defined in Django and in HTML, and there is a strong correlation between the two.

    0 讨论(0)
提交回复
热议问题