Way*_*rts 175 python django django-templates
我正在尝试创建一个基本模板来显示所选实例的字段值及其名称.可以将其视为表格格式中该实例值的标准输出,其中第一列中的字段名称(特别是如果在字段上指定了verbose_name)和第二列中该字段的值.
例如,假设我们有以下模型定义:
class Client(Model):
name = CharField(max_length=150)
email = EmailField(max_length=100, verbose_name="E-mail")
Run Code Online (Sandbox Code Playgroud)
我希望它在模板中输出如此(假设具有给定值的实例):
Field Name Field Value
---------- -----------
Name Wayne Koorts
E-mail waynes@email.com
Run Code Online (Sandbox Code Playgroud)
我想要实现的是能够将模型的实例传递给模板,并能够在模板中动态迭代它,如下所示:
<table>
{% for field in fields %}
<tr>
<td>{{ field.name }}</td>
<td>{{ field.value }}</td>
</tr>
{% endfor %}
</table>
Run Code Online (Sandbox Code Playgroud)
是否有一个整洁,"Django批准"的方式来做到这一点?这似乎是一项非常常见的任务,我需要经常为这个特定的项目做这件事.
Ign*_*ams 166
model._meta.get_all_field_names()将为您提供所有模型的字段名称,然后您可以使用model._meta.get_field()您的方式查找详细名称,并getattr(model_instance, 'field_name')从模型中获取值.
注意:model._meta.get_all_field_names()在django 1.9中不推荐使用.而是使用model._meta.get_fields()获取模型的字段并field.name获取每个字段名称.
Paw*_*iak 69
您可以使用Django的to-python queryset序列化程序.
只需在您的视图中输入以下代码:
from django.core import serializers
data = serializers.serialize( "python", SomeModel.objects.all() )
Run Code Online (Sandbox Code Playgroud)
然后在模板中:
{% for instance in data %}
{% for field, value in instance.fields.items %}
{{ field }}: {{ value }}
{% endfor %}
{% endfor %}
Run Code Online (Sandbox Code Playgroud)
它的巨大优势在于它处理关系字段.
对于字段子集,请尝试:
data = serializers.serialize('python', SomeModel.objects.all(), fields=('name','size'))
Run Code Online (Sandbox Code Playgroud)
Rog*_*ger 66
最后在dev邮件列表上找到了一个很好的解决方案:
在视图中添加:
from django.forms.models import model_to_dict
def show(request, object_id):
object = FooForm(data=model_to_dict(Foo.objects.get(pk=object_id)))
return render_to_response('foo/foo_detail.html', {'object': object})
Run Code Online (Sandbox Code Playgroud)
在模板中添加:
{% for field in object %}
<li><b>{{ field.label }}:</b> {{ field.data }}</li>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)
Mic*_*l B 22
根据Django 1.8的发布(以及Model _meta API的形式化,我想我会用更新的答案来更新它.
假设相同的型号:
class Client(Model):
name = CharField(max_length=150)
email = EmailField(max_length=100, verbose_name="E-mail")
Run Code Online (Sandbox Code Playgroud)
fields = [(f.verbose_name, f.name) for f in Client._meta.fields]
>>> fields
[(u'ID', u'id'), (u'name', u'name'), (u'E-mail', u'email')]
Run Code Online (Sandbox Code Playgroud)
更改了Django 1.8:
Model
_metaAPI一直作为Django内部存在,但没有正式记录和支持.作为公开此API的努力的一部分,一些现有的API入口点略有改变.我们提供了一个迁移指南,以帮助您转换代码以使用新的官方API.
在下面的例子中,我们将利用形式化方法检索模型的所有字段的实例通过Client._meta.get_fields():
fields = [(f.verbose_name, f.name) for f in Client._meta.get_fields()]
>>> fields
[(u'ID', u'id'), (u'name', u'name'), (u'E-mail', u'email')]
Run Code Online (Sandbox Code Playgroud)
实际上,我已经注意到上面的内容略微超出需要的范围(我同意!).简单比复杂更好.我将离开以上内容以供参考.但是,要在模板中显示,最好的方法是使用ModelForm并传入实例.您可以遍历表单(相当于迭代每个表单的字段)并使用label属性检索模型字段的verbose_name,并使用value方法检索值:
from django.forms import ModelForm
from django.shortcuts import get_object_or_404, render
from .models import Client
def my_view(request, pk):
instance = get_object_or_404(Client, pk=pk)
class ClientForm(ModelForm):
class Meta:
model = Client
fields = ('name', 'email')
form = ClientForm(instance=instance)
return render(
request,
template_name='template.html',
{'form': form}
)
Run Code Online (Sandbox Code Playgroud)
现在,我们渲染模板中的字段:
<table>
<thead>
{% for field in form %}
<th>{{ field.label }}</th>
{% endfor %}
</thead>
<tbody>
<tr>
{% for field in form %}
<td>{{ field.value|default_if_none:'' }}</td>
{% endfor %}
</tr>
</tbody>
</table>
Run Code Online (Sandbox Code Playgroud)
sha*_*ker 17
这是使用模型方法的另一种方法.此版本可解析选项列表/选项字段,跳过空白字段,并允许您排除特定字段.
def get_all_fields(self):
"""Returns a list of all field names on the instance."""
fields = []
for f in self._meta.fields:
fname = f.name
# resolve picklists/choices, with get_xyz_display() function
get_choice = 'get_'+fname+'_display'
if hasattr(self, get_choice):
value = getattr(self, get_choice)()
else:
try:
value = getattr(self, fname)
except AttributeError:
value = None
# only display fields with values and skip some fields entirely
if f.editable and value and f.name not in ('id', 'status', 'workshop', 'user', 'complete') :
fields.append(
{
'label':f.verbose_name,
'name':f.name,
'value':value,
}
)
return fields
Run Code Online (Sandbox Code Playgroud)
然后在你的模板中:
{% for f in app.get_all_fields %}
<dt>{{f.label|capfirst}}</dt>
<dd>
{{f.value|escape|urlize|linebreaks}}
</dd>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)
olo*_*fom 13
好吧,我知道这有点晚了,但是因为我在找到正确的答案之前偶然发现了这个,所以可能是其他人.
来自django文档:
# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
[<Blog: Beatles Blog>]
# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]
Run Code Online (Sandbox Code Playgroud)
您可以让表单为您完成工作.
def my_model_view(request, mymodel_id):
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
model = get_object_or_404(MyModel, pk=mymodel_id)
form = MyModelForm(instance=model)
return render(request, 'model.html', { 'form': form})
Run Code Online (Sandbox Code Playgroud)
然后在模板中:
<table>
{% for field in form %}
<tr>
<td>{{ field.name }}</td>
<td>{{ field.value }}</td>
</tr>
{% endfor %}
</table>
Run Code Online (Sandbox Code Playgroud)
您可以使用a的values()方法queryset,它返回一个字典.此外,此方法接受要子集的字段列表.该values()方法无法使用get(),因此必须使用filter()(请参阅QuerySet API).
在view......
def show(request, object_id):
object = Foo.objects.filter(id=object_id).values()[0]
return render_to_response('detail.html', {'object': object})
Run Code Online (Sandbox Code Playgroud)
在detail.html......
<ul>
{% for key, value in object.items %}
<li><b>{{ key }}:</b> {{ value }}</li>
{% endfor %}
</ul>
Run Code Online (Sandbox Code Playgroud)
对于filter返回的实例集合:
object = Foo.objects.filter(id=object_id).values() # no [0]
Run Code Online (Sandbox Code Playgroud)
在detail.html ...
{% for instance in object %}
<h1>{{ instance.id }}</h1>
<ul>
{% for key, value in instance.items %}
<li><b>{{ key }}:</b> {{ value }}</li>
{% endfor %}
</ul>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)
应该有一种内置的方法来做到这一点.我写了这个实用程序build_pretty_data_view,它接受一个模型对象和表单实例(一个基于你的模型的表单)并返回一个SortedDict.
此解决方案的好处包括:
SortedDict.exclude()字段名称列表来排除某些字段.Meta: exclude(),但仍希望返回值,则将这些字段添加到可选append()列表中. 要使用此解决方案,首先在某处添加此文件/函数,然后将其导入到您的views.py.
utils.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: ai ts=4 sts=4 et sw=4
from django.utils.datastructures import SortedDict
def build_pretty_data_view(form_instance, model_object, exclude=(), append=()):
i=0
sd=SortedDict()
for j in append:
try:
sdvalue={'label':j.capitalize(),
'fieldvalue':model_object.__getattribute__(j)}
sd.insert(i, j, sdvalue)
i+=1
except(AttributeError):
pass
for k,v in form_instance.fields.items():
sdvalue={'label':"", 'fieldvalue':""}
if not exclude.__contains__(k):
if v.label is not None:
sdvalue = {'label':v.label,
'fieldvalue': model_object.__getattribute__(k)}
else:
sdvalue = {'label':k,
'fieldvalue': model_object.__getattribute__(k)}
sd.insert(i, k, sdvalue)
i+=1
return sd
Run Code Online (Sandbox Code Playgroud)
所以现在views.py你可能会做这样的事情
from django.shortcuts import render_to_response
from django.template import RequestContext
from utils import build_pretty_data_view
from models import Blog
from forms import BlogForm
.
.
def my_view(request):
b=Blog.objects.get(pk=1)
bf=BlogForm(instance=b)
data=build_pretty_data_view(form_instance=bf, model_object=b,
exclude=('number_of_comments', 'number_of_likes'),
append=('user',))
return render_to_response('my-template.html',
RequestContext(request,
{'data':data,}))
Run Code Online (Sandbox Code Playgroud)
现在在您的my-template.html模板中,您可以迭代数据,如此...
{% for field,value in data.items %}
<p>{{ field }} : {{value.label}}: {{value.fieldvalue}}</p>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)
祝好运.希望这有助于某人!
以下是我的,灵感来自shacker's get_all_fields.它获取一个模型实例的字典,如果遇到关系字段,则递归地将字段值设为字典.
def to_dict(obj, exclude=[]):
"""???? dict, ?????? model instance ??.
"""
tree = {}
for field in obj._meta.fields + obj._meta.many_to_many:
if field.name in exclude or \
'%s.%s' % (type(obj).__name__, field.name) in exclude:
continue
try :
value = getattr(obj, field.name)
except obj.DoesNotExist:
value = None
if type(field) in [ForeignKey, OneToOneField]:
tree[field.name] = to_dict(value, exclude=exclude)
elif isinstance(field, ManyToManyField):
vs = []
for v in value.all():
vs.append(to_dict(v, exclude=exclude))
tree[field.name] = vs
elif isinstance(field, DateTimeField):
tree[field.name] = str(value)
elif isinstance(field, FileField):
tree[field.name] = {'url': value.url}
else:
tree[field.name] = value
return tree
Run Code Online (Sandbox Code Playgroud)
该函数主要用于将模型实例转储为json数据:
def to_json(self):
tree = to_dict(self, exclude=('id', 'User.password'))
return json.dumps(tree, ensure_ascii=False)
Run Code Online (Sandbox Code Playgroud)
我使用/sf/answers/240177311/但用这个替换了Django的model_to_dict()以便能够处理ForeignKey:
def model_to_dict(instance):
data = {}
for field in instance._meta.fields:
data[field.name] = field.value_from_object(instance)
if isinstance(field, ForeignKey):
data[field.name] = field.rel.to.objects.get(pk=data[field.name])
return data
Run Code Online (Sandbox Code Playgroud)
请注意,我已经通过删除我不需要的原件的部分简化了它.你可能想把它们放回去.
我建议不要编辑每个模型,而是编写一个模板标签,它将返回给定的任何模型的所有字段.
每个对象都有字段列表._meta.fields.
每个字段对象都具有name将返回其名称的属性,并且value_to_string()随模型提供的方法object将返回其值.
其余的就像在Django文档中说的那样简单.
以下是此模板标签的示例:
from django.conf import settings
from django import template
if not getattr(settings, 'DEBUG', False):
raise template.TemplateSyntaxError('get_fields is available only when DEBUG = True')
register = template.Library()
class GetFieldsNode(template.Node):
def __init__(self, object, context_name=None):
self.object = template.Variable(object)
self.context_name = context_name
def render(self, context):
object = self.object.resolve(context)
fields = [(field.name, field.value_to_string(object)) for field in object._meta.fields]
if self.context_name:
context[self.context_name] = fields
return ''
else:
return fields
@register.tag
def get_fields(parser, token):
bits = token.split_contents()
if len(bits) == 4 and bits[2] == 'as':
return GetFieldsNode(bits[1], context_name=bits[3])
elif len(bits) == 2:
return GetFieldsNode(bits[1])
else:
raise template.TemplateSyntaxError("get_fields expects a syntax of "
"{% get_fields <object> [as <context_name>] %}")
Run Code Online (Sandbox Code Playgroud)