在Django中显示对象表格

8 投票
2 回答
9534 浏览
提问于 2025-04-17 14:15

我需要用Django从我的数据库中显示一个表格。最简单的方法就是手动输入表头,然后通过model.objects.all()来循环查询结果。不过,我比较懒,想要自动化,也就是说通过反射来加载模型中的所有字段作为列标题,并加载所有字段值作为行数据。这样做还能省下我后续的时间,因为当我的模型发生变化时,我就不需要更新模板代码了。我已经让它工作了,但遇到了两个问题:

  1. 我找不到方法来加载AutoField字段(即id)的值,所以我不得不把ID列去掉。
  2. 代码看起来有点乱,尤其是使用了一些随机的模板标签。

这是我的代码。请注意,代码运行得很好,所以我就不提导入部分了,因为它们都是正确的:

views.py 我使用序列化器来序列化数据,这是我在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:注意我必须通过去掉字段列表的第一个元素来去掉ID列。

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

2 个回答

6

serializers.serialize("jsonxml", Model.objects.all()) 这个格式会返回每个对象的id字段;这可能不是你想要的结果,不过一些jQuery的网格插件可以进一步简化这个过程。

2

太好了!我找到了一种解决办法,感谢Видул Петров的建议,使用将数据转换成json格式的方法,这样我也能加载pk字段了。虽然感觉这个方法还是有点手动、笨拙(而且代码也比较冗长),但我觉得我快成功了。请帮我进一步优化这段代码。

views.py 将数据序列化成一系列的JSON对象,然后解析成字典列表,以便传递给模板。

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 现在模板看起来好多了。

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

撰写回答