source

템플릿의 모델 인스턴스 필드 이름 및 값에 대해 반복

goodcode 2023. 1. 19. 21:24
반응형

템플릿의 모델 인스턴스 필드 이름 및 값에 대해 반복

선택한 인스턴스의 필드 값과 이름을 표시하는 기본 템플릿을 만들려고 합니다.첫 번째 열에 필드 이름(특히 필드에 지정된 경우 verbose_name)과 두 번째 열에 필드 값이 있는 테이블 형식의 해당 인스턴스 값의 표준 출력이라고 생각하면 됩니다.

예를 들어 다음과 같은 모델 정의가 있다고 가정합니다.

class Client(Model):
    name = CharField(max_length=150)
    email = EmailField(max_length=100, verbose_name="E-mail")

다음과 같이 템플릿에 출력하고 싶습니다(지정된 값을 가진 인스턴스를 가정합니다).

Field Name      Field Value
----------      -----------
Name            Wayne Koorts
E-mail          waynes@email.com

제가 목표로 하는 것은 모델의 인스턴스를 템플릿으로 전달하여 템플릿에서 동적으로 반복할 수 있도록 하는 것입니다. 다음과 같습니다.

<table>
    {% for field in fields %}
        <tr>
            <td>{{ field.name }}</td>
            <td>{{ field.value }}</td>
        </tr>
    {% endfor %}
</table>

'장고 승인' 방법이 있을까요?매우 일반적인 작업인 것 같고, 이번 프로젝트에서는 자주 해야 할 것 같습니다.

model._meta.get_all_field_names()모델의 모든 필드 이름을 알려준 다음model._meta.get_field()getattr(model_instance, 'field_name')을 사용법

의:model._meta.get_all_field_names().9django 1.9에서는 되지 않습니다.에서는 권장되지 않습니다. " "를 사용합니다.model._meta.get_fields()field.name각 필드 이름을 가져옵니다.

Django의 To-Python 쿼리셋 시리얼라이저를 사용할 수 있습니다.

다음 코드를 뷰에 입력하기만 하면 됩니다.

from django.core import serializers
data = serializers.serialize( "python", SomeModel.objects.all() )

그리고 템플릿에서 다음을 수행합니다.

{% for instance in data %}
    {% for field, value in instance.fields.items %}
        {{ field }}: {{ value }}
    {% endfor %}
{% endfor %}

이 제품의 큰 장점은 관계 필드를 처리할 수 있다는 것입니다.

필드의 하위 집합에 대해 다음을 수행합니다.

data = serializers.serialize('python', SomeModel.objects.all(), fields=('name','size'))

개발 메일링 리스트에서 이 문제에 대한 좋은 해결책을 찾았습니다.

보기에서 다음을 추가합니다.

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

를 추가합니다.

{% for field in object %}
    <li><b>{{ field.label }}:</b> {{ field.data }}</li>
{% endfor %}

모델 방법을 사용한 또 다른 접근방식이 있습니다.이 버전에서는 선택 목록/선택 필드를 해결하고 빈 필드를 건너뛰며 특정 필드를 제외할 수 있습니다.

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

그런 다음 템플릿에서 다음을 수행합니다.

{% for f in app.get_all_fields %}
  <dt>{{f.label|capfirst}}</dt>
    <dd>
      {{f.value|escape|urlize|linebreaks}}
    </dd>
{% endfor %}

Django 1.8의 출시(및 모델 _meta API의 공식화)에 비추어 볼 때, 저는 이것을 좀 더 최근의 답변으로 업데이트해야겠다고 생각했습니다.

같은 모델을 전제로 하는 경우:

class Client(Model):
    name = CharField(max_length=150)
    email = EmailField(max_length=100, verbose_name="E-mail")

장고 <= 1.7

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')]

Django 1.8+ (공식화된 모델 _meta API)

Django 1.8에서 변경:

모델 API는 항상 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')]

사실, 위 내용이 필요 이상으로 되어 있다는 것을 알게 되었습니다(동의합니다!).단순한 것이 복잡한 것보다 낫다.상기 사항을 참고용으로 남깁니다.그러나 템플릿에 표시하려면 ModelForm을 사용하여 인스턴스를 통과하는 것이 가장 좋습니다.폼에 대해 반복하고(폼의 각 필드에 대해 반복하는 것과 동일) 레이블 속성을 사용하여 모델 필드의 verbose_name을 검색하고 값 메서드를 사용하여 값을 검색할 수 있습니다.

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

이제 템플릿의 필드를 렌더링합니다.

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

좋아요, 좀 늦은 건 알지만, 제가 정답을 찾기 전에 우연히 발견했으니까 다른 사람도 찾을 수 있을 거예요.

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.'}]

.values()의 of의 queryset사전이 반환됩니다.또한 이 메서드는 서브셋할 필드 목록을 받아들입니다.values() 메서드는 이방 method method 、 method 、 method 、 method 、 method 、 method method method method method method method method method 。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})

»detail.html

<ul>
   {% for key, value in object.items %}
        <li><b>{{ key }}:</b> {{ value }}</li>
   {% endfor %}
</ul>

필터에 의해 반환된 인스턴스 컬렉션의 경우:

   object = Foo.objects.filter(id=object_id).values() # no [0]

상세.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 %}

폼으로 대신할 수 있습니다.

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

그런 다음 템플릿에서 다음을 수행합니다.

<table>
    {% for field in form %}
        <tr>
            <td>{{ field.name }}</td>
            <td>{{ field.value }}</td>
        </tr>
    {% endfor %}
</table>

아래는 섀커즈에서 영감을 받은 내 것이다. get_all_fields. 하나의 재귀적으로 받아쓰다관계 필드를 만나면 필드 값에 dict를 재귀적으로 지정합니다.

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

이 함수는 주로 모델 인스턴스를 json 데이터로 덤프하는 데 사용됩니다.

def to_json(self):
    tree = to_dict(self, exclude=('id', 'User.password'))
    return json.dumps(tree, ensure_ascii=False)

https://stackoverflow.com/a/3431104/2022534을 사용했지만 ForeignKey를 처리하기 위해 Django의 model_to_model()을 다음과 같이 교체했습니다.

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

제가 필요없는 부분을 제거해서 많이 간소화 했으니 참고하시기 바랍니다.그것들을 원래대로 돌려놓는 게 좋을 거야.

이 작업을 할 수 있는 기본 제공 방법이 있어야 합니다.는 제가 쓴 입니다.build_pretty_data_view 및 를한다.SortedDict.

이 솔루션의 이점은 다음과 같습니다.

  • 를 유지하고 .SortedDict.
  • 는 라벨/verbose_name을 취득하려고 하지만 필드명이 정의되지 않은 경우 필드명으로 폴백합니다.
  • , 옵션으로 「」, 「」, 「」, 「」, 「」, 「」, 「」도 필요합니다.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

, 그럼 이제 그 your your your your your yourviews.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,}))

의 이 your your your my-template.html템플릿은 이렇게 데이터를 반복할 수 있습니다.

{% for field,value in data.items %}

    <p>{{ field }} : {{value.label}}: {{value.fieldvalue}}</p>

{% endfor %}

행운을 빌어요.이게 누군가에게 도움이 되길 바라!

모든 모델을 편집하는 대신 주어진 모델의 모든 필드를 반환하는 템플릿 태그를 하나 작성하는 것이 좋습니다.
에는 필드 .._meta.fields.
.name과 방법을 것입니다.value_to_string()에 되어 있는 것object값이 반환됩니다.
나머지는 장고 문서에 나와 있는 것처럼 간단하다.

이 템플릿 태그의 예를 다음에 나타냅니다.

    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>] %}")

네, 예쁘지 않아요. 직접 포장지를 만들어야 할 거예요.실제로 필요한 모든 기능을 갖춘 내장 데이터 로우즈 앱을 살펴보십시오.

이것은 해킹으로 간주될 수 있지만, 모델 인스턴스를 폼으로 만들기 위해 modelform_factory를 사용한 적이 있습니다.

양식 클래스에는 반복하기 매우 쉬운 정보가 훨씬 더 많이 포함되어 있으며, 동일한 목적을 위해 약간의 오버헤드가 발생합니다.세트 사이즈가 비교적 작으면 퍼포먼스에 미치는 영향은 미미하다고 생각합니다.

물론 편리함 외에 한 가지 장점은 나중에 테이블을 편집 가능한 데이터 그래피드로 쉽게 전환할 수 있다는 것입니다.

저는 다음과 같은 방법을 생각해 냈습니다.모든 경우 모델에 ModelForm이 관련되어 있기 때문입니다.

def GetModelData(form, fields):
    """
    Extract data from the bound form model instance and return a
    dictionary that is easily usable in templates with the actual
    field verbose name as the label, e.g.

    model_data{"Address line 1": "32 Memory lane",
               "Address line 2": "Brainville",
               "Phone": "0212378492"}

    This way, the template has an ordered list that can be easily
    presented in tabular form.
    """
    model_data = {}
    for field in fields:
        model_data[form[field].label] = eval("form.data.%s" % form[field].name)
    return model_data

@login_required
def clients_view(request, client_id):
    client = Client.objects.get(id=client_id)
    form = AddClientForm(client)

    fields = ("address1", "address2", "address3", "address4",
              "phone", "fax", "mobile", "email")
    model_data = GetModelData(form, fields)

    template_vars = RequestContext(request,
        {
            "client": client,
            "model_data": model_data
        }
    )
    return render_to_response("clients-view.html", template_vars)

이 뷰에 사용하고 있는 템플릿의 발췌를 다음에 나타냅니다.

<table class="client-view">
    <tbody>
    {% for field, value in model_data.items %}
        <tr>
            <td class="field-name">{{ field }}</td><td>{{ value }}</td>
        </tr>
    {% endfor %}
    </tbody>
</table>

이 방법의 장점은 GetModelData에 전달된 태플을 사용하여 필드 라벨을 표시할 순서를 템플릿별로 선택할 수 있다는 것입니다.또한 이 기능을 통해 전달된 필드 이름만 최종 사전에 포함되므로 특정 필드(예: 사용자 외부 키)를 제외할 수 있습니다.

누군가 좀 더 "장고닉"한 것을 생각해 낼 수 있다고 확신하기 때문에 나는 이것을 대답으로 받아들이지 않을 것이다:-)

업데이트: 필요한 작업을 수행하는 가장 간단한 답변이기 때문에 이 답변을 최종 답변으로 선택합니다.답변해 주신 모든 분들께 감사드립니다.

Django 1.7 솔루션:

이 질문에는 정확한 변수가 있지만 이 예제를 분석할 수 있어야 합니다.

여기서 중요한 것은 거의 대부분의 데이터를.__dict__모델의
views.py:

def display_specific(request, key):
  context = {
    'question_id':question_id,
    'client':Client.objects.get(pk=key).__dict__,
  }
  return render(request, "general_household/view_specific.html", context)

템플릿:

{% for field in gen_house %}
    {% if field != '_state' %}
        {{ gen_house|getattribute:field }}
    {% endif %}
{% endfor %}

템플릿에서 나는 필터를 사용하여 dict의 필드에 액세스했다.
필터가 포함되어 있습니다.py:

@register.filter(name='getattribute')
def getattribute(value, arg):
  if value is None or arg is None:
    return ""
  try:
    return value[arg]
  except KeyError:
    return ""
  except TypeError:
    return ""

저는 https://github.com/miracle2k/django-tables을 사용하고 있습니다.

<table>
<tr>
    {% for column in table.columns %}
    <th><a href="?sort={{ column.name_toggled }}">{{ column }}</a></th>
    {% endfor %}
</tr>
{% for row in table.rows %}
    <tr>
    {% for value in row %}
        <td>{{ value }}</td>
    {% endfor %}
    </tr>
{% endfor %}
</table>

이 접근법에서는 django의 ModelForm과 같은 클래스와 {{form.as_table}}과 같은 템플릿 태그를 사용하는 방법을 보여 줍니다. 단, 모든 테이블은 형식이 아닌 데이터 출력처럼 보입니다.

첫 번째 단계는 django의 TextInput 위젯을 서브클래스하는 것이었습니다.

from django import forms
from django.utils.safestring import mark_safe
from django.forms.util import flatatt

class PlainText(forms.TextInput):
    def render(self, name, value, attrs=None):
        if value is None:
            value = ''
        final_attrs = self.build_attrs(attrs)
        return mark_safe(u'<p %s>%s</p>' % (flatatt(final_attrs),value))

그런 다음 django의 ModelForm을 하위 분류하여 기본 위젯을 읽기 전용 버전으로 바꿉니다.

from django.forms import ModelForm

class ReadOnlyModelForm(ModelForm):
    def __init__(self,*args,**kwrds):
        super(ReadOnlyModelForm,self).__init__(*args,**kwrds)
        for field in self.fields:
            if isinstance(self.fields[field].widget,forms.TextInput) or \
               isinstance(self.fields[field].widget,forms.Textarea):
                self.fields[field].widget=PlainText()
            elif isinstance(self.fields[field].widget,forms.CheckboxInput):
                self.fields[field].widget.attrs['disabled']="disabled" 

내가 필요한 위젯은 그것만 있으면 돼그러나 이 아이디어를 다른 위젯으로 확장하는 것은 어렵지 않습니다.

@wonder 편집만 하면 됩니다.

def to_dict(obj, exclude=[]):
    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 as e:
            value = None
        except ObjectDoesNotExist as e:
            value = None
            continue
        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
        else:
            tree[field.name] = obj.serializable_value(field.name)
    return tree

관련 필드 이외의 모든 필드는 Django에서 처리하도록 하겠습니다.나는 그것이 더 안정적이라고 느낀다.

django-etc 어플리케이션을 확인합니다.정말 그랬어요.model_field_verbose_name템플릿 태그:http://django-etc.rtfd.org/en/latest/models.html#model-field-template-tags 에서 필드 상세 이름을 가져옵니다.

방금 이런 테스트를 해봤는데, 제대로 된 것 같아요.

my_object_mapped = {attr.name: str(getattr(my_object, attr.name)) for attr in MyModel._meta.fields}

외부 객체에 str() 표현을 원할 경우 해당 str 메서드에서 정의해야 합니다.여기서 오브젝트 값을 받아쓰게 됩니다.그런 다음 템플릿 같은 것을 렌더링할 수 있습니다.

장고 > = 2.0

더하다get_fields()고객님께models.py:

class Client(Model):
    name = CharField(max_length=150)
    email = EmailField(max_length=100, verbose_name="E-mail")

    def get_fields(self):
        return [(field.verbose_name, field.value_from_object(self)) for field in self.__class__._meta.fields]

그럼 이렇게 불러주세요object.get_fieldstemplate.html:

<table>
    {% for label, value in object.get_fields %}
        <tr>
            <td>{{ label }}</td>
            <td>{{ value }}</td>
        </tr>
    {% endfor %}
</table>

모델명이 Client이고 ID로 클라이언트 개체를 가져오는 경우 다음과 같이 진행하십시오.

client = Client.objects.get(id=id)
fields = Client._meta.get_fields()
for field in fields:
    value = getattr(client, field.name)
    print(field.name)
    print(value)

<table border='1'>
	<tr>
		{% for mfild in fields%}
			<td>{{mfild}}</td>
		{% endfor%}
	</tr>
    {%for v in records%}
        <tr>
        	<td>{{v.id}}</td>
        	<td>{{v.title}}</td>
        	<td class="">{{v.desc}}</td>

        </tr>

    {% endfor%}
 </table>
 
 
enter code here

언급URL : https://stackoverflow.com/questions/2170228/iterate-over-model-instance-field-names-and-values-in-template

반응형