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

后端 未结 2 1058
生来不讨喜
生来不讨喜 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 %}
        
          {{ label|capfirst }}
          
            {% if value.get_absolute_url and request.is_ajax %}
              {{ value }}
            {% elif value.get_absolute_url %}
              {{ value }}
            {% else %}
              {% if is_link and request.is_ajax %}
                {{ value }}
              {% elif is_link %}
                {{ value }}
              {% else %}
                {{ value }}
              {% endif %}
            {% endif %}
          
        
      {% 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.

提交回复
热议问题