Display table of objects django

巧了我就是萌 提交于 2019-12-04 21:45:04

问题


I need to display a table from my database with Django. The obvious way is to manually type in the table headings and loop through query results of model.objects.all(). However, being quite lazy, I want to do this automatically, i.e. load all fields from model through introspection to display as column headings and load all field values to display as rows. This approach can also save me some time later because I don't have to update my template code when my model changes. I got it to work but there are two problems:

  1. I can't find away to load the AutoField field (id) value so I have to slice off the ID column.
  2. The code looks quite messy especially with the use of random template tags.

Here is my code. Please note that the code works fine so I'll skip all the imports as they are correct:

views.py I use serializers to serialize the data, a trick I read somewhere on stackoverflow

def index(request):
   fields    = MyModel._meta.fields
   data      = serializers.serialize("python", MyModel.objects.all())
   context_instance = RequestContext(request, {    
       'data'      : data,
       'fields'    : fields,
   })
   return TemplateResponse(request, 'index.html', context_instance)

template/index.html: note that I have to slice off the ID column by slicing off the first element of the fields list

{% with fields|slice:"1:" as cached_fields %}
<table>
    <thead>
        <tr>
            {% for field in cached_fields %}
                <th>{% get_verbose_name field %}</th>
            {% endfor %}
        </tr>
    </thead>
    <tbody>
        {% for instance in data %}
        <tr>
            {% for field in cached_fields %}
                <td>{% get_value_from_key instance.fields field %}</td>
            {% endfor %}
        </tr>
        {% endfor %}
    </tbody>
</table>
{% endwith %}

templatetags/extra_tags.py

# tag to get field's verbose name in template 
@register.simple_tag
def get_verbose_name(object):
    return object.verbose_name

# tag to get the value of a field by name in template
@register.simple_tag
def get_value_from_key(object, key):
    # is it necessary to check isinstance(object, dict) here? 
    return object[key.name]

回答1:


serializers.serialize("json or xml", Model.objects.all()) formats return the id field; probably not what you are looking for but some of the jQuery grid plugins can further automate the task.




回答2:


Have a look at this should automate a lot of the this for you from your models. http://django-tables2.readthedocs.org/en/latest/




回答3:


Yay! I found a work around thanks to Видул Петров's suggestion about serializing the data to json, which allows me to load the pk field as well. It still feels too manual and hackish (and verbose) but I think I'm getting close. Please help me refactor this code further.

views.py Serialize data into a list of JSON objects and parse it into a list of dictionaries to pass it to template

from django.utils import simplejson as json    

def index(request):
   fields    = MyModel._meta.fields
   data      = json.loads(serializers.serialize("json", MyModel.objects.all()))

   def parse_data(data):

        result = [] 

        # flatten the dictionary
        def flatten_dict(d):
            """ 
            Because the only nested dict here is the fields, let's just
            remove the 'fields' suffix so that the fields can be loaded in 
            template by name
            """
            def items():
                for key, value in d.items():
                    if isinstance(value, dict):
                        for subkey, subvalue in flatten_dict(value).items():
                            yield subkey, subvalue
                    else:
                        yield key, value

            return dict(items())

        for d in data:
            # change the 'pk' key name into its actual name in the database
            d[Employee._meta.pk.name] = d.pop('pk') 
            # append the flattend dict of each object's field-value to the result 
            result.append(flatten_dict(d))

        return result


   context_instance = RequestContext(request, {    
       'data'      : parse_data(data),
       'fields'    : fields,
   })
   return TemplateResponse(request, 'index.html', context_instance)

template/index.html The template is much nicer now

<table>
    <thead>
        <tr>
            {% for field in cached_fields %}
                <th>{% get_verbose_name field %}</th>
            {% endfor %}
        </tr>
    </thead>
    <tbody>            
            {% for d in data %}
                <tr>
                    {% for field in fields %}
                        <td>{% get_value_from_key d field %}</td>
                    {% endfor %}
                </tr>
            {% endfor %}            
    </tbody>
</table>


来源:https://stackoverflow.com/questions/14615847/display-table-of-objects-django

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