[python] 템플릿에서 모델 인스턴스 필드 이름과 값을 반복

선택한 인스턴스의 필드 값과 이름을 표시하는 기본 템플릿을 만들려고합니다. 첫 번째 열의 필드 이름 (필드에 구체적으로 지정된 경우 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>

이 작업을 수행 할 수있는 깔끔한 “Django 승인”방법이 있습니까? 매우 일반적인 작업 인 것 같으므로이 특정 프로젝트를 위해 자주 수행해야합니다.



답변

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를 얻고 각 필드 이름을 얻는 데 사용하십시오.


답변

Django의 to-python queryset serializer 사용할 수 있습니다 .

다음 코드를보기에 넣으십시오.

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


답변

마지막으로 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})

템플릿에서 다음을 추가하십시오.

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


답변

Django 1.8의 릴리스 (및 Model _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)

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

실제로, 위의 내용이 필요한 것보다 약간 선상에 있음이 주목되었습니다 (동의합니다!). 단순한 것보다 복잡한 것이 좋습니다. 위의 내용을 참고로 남겨두고 있습니다. 그러나 템플릿에 표시하려면 가장 좋은 방법은 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}
    )

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

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


답변

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

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


답변

좋아, 나는 이것이 조금 늦다는 것을 알고 있지만, 나는 정답을 찾기 전에 이것을 우연히 발견했기 때문에 다른 누군가도 그렇게 할 수 있습니다.

로부터 장고 문서 :

# 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()메소드를 사용할 수 있습니다 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})

에서 detail.html

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

A의 인스턴스의 컬렉션을 필터에 의해 반환

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

에서 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 %}