在Django中显示对象表格
我需要用Django从我的数据库中显示一个表格。最简单的方法就是手动输入表头,然后通过model.objects.all()
来循环查询结果。不过,我比较懒,想要自动化,也就是说通过反射来加载模型中的所有字段作为列标题,并加载所有字段值作为行数据。这样做还能省下我后续的时间,因为当我的模型发生变化时,我就不需要更新模板代码了。我已经让它工作了,但遇到了两个问题:
- 我找不到方法来加载AutoField字段(即id)的值,所以我不得不把ID列去掉。
- 代码看起来有点乱,尤其是使用了一些随机的模板标签。
这是我的代码。请注意,代码运行得很好,所以我就不提导入部分了,因为它们都是正确的:
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("json
或 xml", 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>