Lặp lại các tên và giá trị của trường mẫu trong mẫu


183

Tôi đang cố gắng tạo một mẫu cơ bản để hiển thị các giá trị trường của trường hợp đã chọn, cùng với tên của chúng. Hãy coi nó chỉ là một đầu ra tiêu chuẩn của các giá trị của thể hiện đó ở định dạng bảng, với tên trường (verbose_name cụ thể nếu được chỉ định trên trường) trong cột đầu tiên và giá trị của trường đó trong cột thứ hai.

Ví dụ: giả sử chúng ta có định nghĩa mô hình sau:

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

Tôi muốn nó là đầu ra trong mẫu như vậy (giả sử một thể hiện với các giá trị đã cho):

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

Những gì tôi đang cố gắng đạt được là có thể chuyển một thể hiện của mô hình sang một mẫu và có thể lặp lại một cách linh hoạt trong mẫu đó, đại loại như thế này:

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

Có cách nào gọn gàng, "được Django chấp thuận" để làm việc này không? Nó có vẻ như là một nhiệm vụ rất phổ biến, và tôi sẽ cần phải thực hiện nó thường xuyên cho dự án cụ thể này.

Câu trả lời:


171

model._meta.get_all_field_names()sẽ cung cấp cho bạn tất cả các tên trường của mô hình, sau đó bạn có thể sử dụng model._meta.get_field()để làm việc theo cách của bạn đến tên dài dòng và getattr(model_instance, 'field_name')để lấy giá trị từ mô hình.

LƯU Ý: model._meta.get_all_field_names()không được dùng trong django 1.9. Thay vào đó, sử dụng model._meta.get_fields()để lấy các trường của mô hình và field.nameđể lấy từng tên trường.


2
Điều này vẫn còn rất thủ công và tôi sẽ phải xây dựng một số loại đối tượng meta trong chế độ xem mà sau đó tôi chuyển vào mẫu, đây là một bản hack nhiều hơn tôi muốn. Chắc chắn phải có một cách gọn gàng hơn?
Wayne Koorts

2
Bạn có thể gói gọn tất cả những thứ này trong một lớp, giống như ModelForm.
Ignacio Vazquez-Abrams

18
Tôi không tin rằng bạn có thể gọi bất kỳ phương thức _ nào trong các mẫu.
Issac Kelly

2
Điều này hoạt động nhưng bạn không nên phụ thuộc vào API riêng (vì nó có tiền tố là "_") để đạt được nó. Vấn đề với việc dựa vào API riêng là các phương thức riêng tư không được đảm bảo để hoạt động từ phiên bản này sang phiên bản khác.
Devy

1
Tôi nghĩ rằng phương pháp này không nên được ưu tiên vì chúng ta không nên truy cập các thuộc tính bắt đầu bằng dấu gạch dưới từ các mẫu
GP92

72

Bạn có thể sử dụng serializer bộ truy vấn to-python của Django .

Chỉ cần đặt mã sau đây trong quan điểm của bạn:

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

Và sau đó trong mẫu:

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

Ưu điểm lớn của nó là thực tế là nó xử lý các trường quan hệ.

Đối với tập hợp con của các trường, hãy thử:

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

Điều đó thật tuyệt - nhưng với phương pháp này, làm thế nào người ta sẽ giới hạn kết quả chỉ trong một số trường nhất định?
Herman Schaaf

2
Đây phải là câu trả lời dứt khoát, xử lý các khóa ngoại và không có cuộc gọi api riêng tư. Câu trả lời tuyệt vời, cảm ơn.
Yunti

3
Không cần thiết phải sử dụng nối tiếp. Bạn có thể sử dụng phương thức value () của bộ truy vấn , trả về một từ điển. Hơn nữa, phương pháp này chấp nhận một danh sách các trường để tập hợp con. Xem liên kết . Xem câu trả lời đầy đủ của tôi.
3062149

Chúng ta có thể cập nhật điều này để chỉ gửi trong .fields thay vì phải xử lý nó trong một vòng lặp không? Tôi không muốn để lộ tên mô hình / bảng
thua

Liệu phương pháp này cho phép verbose_namecác lĩnh vực được thông qua?
bí danh51

70

Cuối cùng cũng tìm thấy một giải pháp tốt cho việc này trong danh sách gửi thư của nhà phát triển :

Trong chế độ xem thêm:

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

trong mẫu thêm:

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

1
Giải pháp tốt, nhưng không chung chung vì nó trả về không phải là model_to_dict cho các trường ForeignKey, nhưng kết quả unicode , vì vậy bạn không thể dễ dàng tuần tự hóa đối tượng phức tạp thành dict
Vestel

22
Nguy hiểm khi ghi đè đối tượng, bạn nên sử dụng một số tên khác.
Emil Stenström

Cảm ơn bạn! Tôi đã thay thế model_to_dict () của Django để có thể xử lý ForeignKey. Vui lòng xem câu trả lời riêng của tôi (Tôi đã xóa nhận xét trước đó vì các nhận xét không hỗ trợ định dạng mã. Xin lỗi, tôi không biết điều đó.)
Magnus Gustavsson

2
Giả sử ở đây FooFormlà một ModelForm, sẽ không dễ dàng hơn để làm : FooForm(instance=Foo.objects.get(pk=object_id)))?
beruic

Bất kỳ ý tưởng làm thế nào bạn sẽ chỉ hiển thị các trường có thể chỉnh sửa với phương pháp này?
bí danh51

22

Trong phiên bản phát hành của Django 1.8 (và việc chính thức hóa Model _meta API , tôi đoán rằng tôi sẽ cập nhật điều này với một câu trả lời gần đây hơn.

Giả sử cùng một mô hình:

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

Django <= 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+ (API _meta Model chính thức)

Thay đổi trong Django 1.8:

_metaAPI mẫu luôn tồn tại dưới dạng nội bộ Django, nhưng không được tài liệu và hỗ trợ chính thức. Là một phần trong nỗ lực để công khai API này, một số điểm nhập API hiện có đã thay đổi một chút. Hướng dẫn di chuyển đã được cung cấp để hỗ trợ chuyển đổi mã của bạn để sử dụng API chính thức mới.

Trong ví dụ dưới đây, chúng tôi sẽ sử dụng phương thức chính thức để truy xuất tất cả các trường hợp trường của một mô hình thông qua 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')]

Trên thực tế, tôi đã nhận thấy rằng phần trên hơi quá mức cho những gì cần thiết (tôi đồng ý!). Đơn giản là tốt hơn phức tạp. Tôi để lại ở trên để tham khảo. Tuy nhiên, để hiển thị trong mẫu, phương pháp tốt nhất sẽ là sử dụng ModelForm và truyền vào một thể hiện. Bạn có thể lặp lại biểu mẫu (tương đương với việc lặp qua từng trường của biểu mẫu) và sử dụng thuộc tính nhãn để truy xuất verbose_name của trường mô hình và sử dụng phương thức giá trị để truy xuất giá trị:

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

Bây giờ, chúng tôi kết xuất các trường trong mẫu:

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

2
Sẽ thật tuyệt nếu bạn điều chỉnh câu trả lời của mình để hiển thị cách "> 1.8" để đặt các trường mô hình vào một mẫu. Tại thời điểm câu trả lời của bạn không trả lời trực tiếp câu hỏi; nó chỉ ra cách lấy các trường của mô hình trong trình bao.
Escher

@Escher - Cập nhật câu trả lời! Cám ơn vì sự gợi ý. Hãy cho tôi biết nếu tôi bỏ lỡ bất cứ điều gì / làm hỏng bất cứ điều gì!
Michael B

Nâng cao. Tôi đã chỉnh sửa để bao gồm in các giá trị cũng như tên trường. Xem những gì bạn nghĩ.
Escher

Nơi nào bạn in các giá trị? Tôi chỉ thấy nó in tên và verbose_name?
Bác sĩ Ernie

@MichaelB Hmm. Tôi đã không thể làm cho "field.value" hoạt động; các trường dường như là các trường cơ sở dữ liệu, không phải dữ liệu cột thực tế. Tôi đã phải sử dụng một bộ lọc gọi là getattr (object, name). Phiên bản nào của Django phù hợp với bạn?
Bác sĩ Ernie

19

Đây là một cách tiếp cận khác bằng cách sử dụng một phương pháp mô hình. Phiên bản này giải quyết các trường danh sách / lựa chọn, bỏ qua các trường trống và cho phép bạn loại trừ các trường cụ thể.

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

Sau đó, trong mẫu của bạn:

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

3
tại sao bạn cần except User.DoesNotExist:?
Thứ bảy

Tôi sẽ có xu hướng sử dụng AttributionError thay vì User.DoesNotExist - Tôi không thể hiểu tại sao nó lại ném User.DoesNotExist.
hỏi

Ngoài ra, có thể tốt hơn để sử dụng self._meta.get_fields () vì điều này được hiển thị chính thức trong django 1.8+. Tuy nhiên, sau đó bạn kết thúc với các mối quan hệ trong mã, mà bạn phải lọc ra bằng cách kiểm tra f.is_relation
hỏi

Tôi đã chỉnh sửa câu trả lời để sử dụng AttributionError thay vì User.DoesNotExist (vốn là phần còn lại từ triển khai ban đầu của tôi). Cảm ơn. Tôi đang giữ _meta.get_fields()cho đến khi tôi có thể kiểm tra nó.
Shacker

13

Ok, tôi biết điều này hơi muộn, nhưng vì tôi đã vấp phải điều này trước khi tìm được câu trả lời chính xác nên có thể có người khác.

Từ các tài liệu 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.'}]

Tôi thích câu trả lời này. Nếu truy vấn của bạn trả về nhiều hơn một bản ghi và bạn chỉ muốn bản ghi mới nhất, hãy làm như sau. 1. Hãy chắc chắn rằng bạn có ordering = ['-id']trong class Meta:đối tượng của bạn trong models.py. 2. sau đó sử dụngBlog.objects.filter(name__startswith='Beatles').values()[0]
Sevenearths

Ý tưởng thông minh. Nhưng nếu bạn đã có một modelđối tượng, thì bạn sẽ truy cập lại cơ sở dữ liệu chỉ để lấy các trường. Có cách nào khác không?
frnhr

@ user1763732 chỉ cần kiểm tra các tài liệu cho Truy vấn
olofom

9

Bạn có thể sử dụng values()phương thức a queryset, trả về một từ điển. Hơn nữa, phương pháp này chấp nhận một danh sách các trường để tập hợp con. Các values()phương pháp sẽ không làm việc với get(), vì vậy bạn phải sử dụng filter()(tham khảo các API QuerySet ).

Trong view...

def show(request, object_id):
   object = Foo.objects.filter(id=object_id).values()[0]
   return render_to_response('detail.html', {'object': object})

Trong detail.html...

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

Đối với một tập hợp các trường hợp được trả về bởi bộ lọc:

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

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

Điều này thật tuyệt vời, cảm ơn bạn! Tôi có một câu hỏi, nếu bạn có thể giúp tôi với; Tôi đang đặt tất cả dữ liệu đối tượng vào a table, vì vậy tôi cần mỗi keys trong a th. Làm thế nào để tôi làm điều đó mà không có vòng lặp? Chỉ cần lấy bất kỳ đối tượng và lặp qua nó cho keys? Hiện tại tôi đang chuyển riêng model_to_dict(Model())cho th, nhưng tôi nghĩ đó là một sự khởi tạo đối tượng không cần thiết.
Oxwivi

Câu trả lời tuyệt vời. Cá nhân, tôi đã sử dụng điều này trong cả chế độ xem danh sách và chế độ xem chi tiết. Chế độ xem danh sách phần lớn là rõ ràng để thực hiện, nhưng với chế độ xem chi tiết, tôi ghi đè lên get_objectchế độ xem chi tiết (bị sai lệch do giới hạn mã nội tuyến trên các nhận xét và không cảm thấy như thế này là đủ cho câu trả lời của chính nó khi xem xét mức độ bão hòa của chủ đề này): def get_object(self, **kwargs): obj = super().get_object(**kwargs) obj = obj.__class__.objects.filter(pk=obj.pk).values()[0] return obj
sdconrox

Làm thế nào bạn có thể thêm obj.get_absolute_urlvào danh sách này mà không cần sao chép các hàng?
bí danh51

8

Tôi đã sử dụng https://stackoverflow.com/a 43231104/2022534 nhưng đã thay thế model_to_dict () của Django bằng cái này để có thể xử lý 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

Xin lưu ý rằng tôi đã đơn giản hóa nó một chút bằng cách loại bỏ các phần của bản gốc mà tôi không cần. Bạn có thể muốn đặt lại.


8

Bạn có thể có một hình thức làm việc cho bạn.

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

Sau đó trong mẫu:

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

3
Phương pháp này (được sử dụng trong a DetailView) hoạt động tốt đối với tôi. Tuy nhiên, bạn có thể muốn sử dụng field.labelthay vì field.name.
David Cain

7

Thực sự nên có một cách tích hợp để làm điều này. Tôi đã viết tiện ích build_pretty_data_viewnày lấy một đối tượng mô hình và thể hiện mẫu (một biểu mẫu dựa trên mô hình của bạn) và trả về a SortedDict.

Lợi ích của giải pháp này bao gồm:

  • Nó bảo vệ trật tự bằng cách sử dụng tích hợp của Django SortedDict.
  • Khi cố lấy nhãn / verbose_name, nhưng lại rơi vào tên trường nếu không xác định tên.
  • Nó cũng sẽ tùy chọn lấy một exclude()danh sách các tên trường để loại trừ các trường nhất định.
  • Nếu lớp biểu mẫu của bạn bao gồm a Meta: exclude(), nhưng bạn vẫn muốn trả về các giá trị, sau đó thêm các trường đó vào append()danh sách tùy chọn .

Để sử dụng giải pháp này, trước tiên hãy thêm tệp / chức năng này vào một nơi nào đó, sau đó nhập nó vào 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

Vì vậy, bây giờ trong views.pybạn có thể làm một cái gì đó như thế này

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

Bây giờ trong my-template.htmlmẫu của bạn, bạn có thể lặp lại dữ liệu như vậy ...

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

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

{% endfor %}

Chúc may mắn. Hy vọng điều này sẽ giúp được ai đó!


7

Dưới đây là của tôi, lấy cảm hứng từ shacker get_all_fields . Nó nhận được một dict của một thể hiện mô hình, nếu gặp trường quan hệ, sau đó gán giá trị trường một dict theo cách đệ quy.

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

Hàm này chủ yếu được sử dụng để kết xuất một thể hiện mô hình vào dữ liệu json:

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

Công việc tuyệt vời Đề xuất thêm các lựa chọn hỗ trợ ... elif hasattr (trường, 'tests'): cây [field.name] = dict (field.choices) .get (value, value)
oden

5

Thay vì chỉnh sửa mọi mô hình, tôi khuyên bạn nên viết một thẻ mẫu sẽ trả về tất cả các trường của bất kỳ mô hình nào được cung cấp.
Mỗi đối tượng có danh sách các lĩnh vực ._meta.fields.
Mỗi đối tượng trường có thuộc tính namesẽ trả về tên và phương thức value_to_string()được cung cấp với mô hình của bạn objectsẽ trả về giá trị của nó.
Phần còn lại đơn giản như đã nói trong tài liệu Django .

Dưới đây là ví dụ của tôi làm thế nào templatetag này có thể trông như thế nào:

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

4

Vâng, nó không đẹp, bạn sẽ phải làm cho trình bao bọc của riêng bạn. Hãy xem ứng dụng databrowse dựng sẵn , có tất cả các chức năng bạn cần thực sự.


Tôi sẽ nói .... databrowse làm điều đó, mặc dù tôi thấy nó là một ứng dụng hoàn toàn vô dụng.
mở

4

Đây có thể được coi là một hack nhưng tôi đã thực hiện điều này trước khi sử dụng modelform_factory để biến một thể hiện mô hình thành một biểu mẫu.

Lớp Form có rất nhiều thông tin bên trong rất dễ lặp lại và nó sẽ phục vụ cùng một mục đích với chi phí cao hơn một chút. Nếu kích thước cài đặt của bạn tương đối nhỏ, tôi nghĩ rằng tác động hiệu suất sẽ không đáng kể.

Một lợi thế bên cạnh sự tiện lợi tất nhiên là bạn có thể dễ dàng biến bảng thành một bảng dữ liệu có thể chỉnh sửa vào một ngày sau đó.


4

Tôi đã đưa ra phương pháp sau, phương pháp này hiệu quả với tôi vì trong mọi trường hợp, mô hình sẽ có ModelForm được liên kết với nó.

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)

Đây là một trích xuất từ ​​mẫu tôi đang sử dụng cho chế độ xem cụ thể này:

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

Điều thú vị về phương pháp này là tôi có thể chọn trên cơ sở từng mẫu theo thứ tự mà tôi muốn hiển thị nhãn trường, sử dụng bộ dữ liệu được truyền vào GetModelData và chỉ định tên trường. Điều này cũng cho phép tôi loại trừ các trường nhất định (ví dụ: khóa ngoại của người dùng) vì chỉ các tên trường được truyền qua bộ dữ liệu mới được tích hợp vào từ điển cuối cùng.

Tôi sẽ không chấp nhận đây là câu trả lời vì tôi chắc chắn ai đó có thể nghĩ ra thứ gì đó "Djangonic" hơn :-)

Cập nhật: Tôi đang chọn đây là câu trả lời cuối cùng bởi vì đây là câu trả lời đơn giản nhất trong số những thứ được đưa ra làm những gì tôi cần. Cảm ơn mọi người đã đóng góp câu trả lời.


3

Giải pháp Django 1.7 cho tôi:

Có các biến chính xác cho câu hỏi, nhưng bạn chắc chắn có thể mổ xẻ ví dụ này

Chìa khóa ở đây là sử dụng khá nhiều .__dict__mô hình
view.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)

mẫu :

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

trong mẫu tôi đã sử dụng bộ lọc để truy cập vào trường trong
bộ lọc dict lọc :

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

2

Tôi đang sử dụng cái này, 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>

2

Cách tiếp cận này cho thấy cách sử dụng một lớp như ModelForm của django và thẻ mẫu như {{form.as_table}}, nhưng có tất cả các bảng trông giống như đầu ra dữ liệu, không phải là một biểu mẫu.

Bước đầu tiên là phân lớp tiện ích TextInput của django:

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

Sau đó, tôi đã phân lớp ModelForm của django để trao đổi các widget mặc định cho các phiên bản chỉ đọc:

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" 

Đó là những vật dụng duy nhất tôi cần. Nhưng không khó để mở rộng ý tưởng này sang các vật dụng khác.


1

Chỉ cần một bản chỉnh sửa của @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

Hãy để Django xử lý tất cả các lĩnh vực khác ngoài các lĩnh vực liên quan. Tôi cảm thấy ổn định hơn



0

Tôi vừa thử nghiệm một cái gì đó như thế này trong vỏ và dường như thực hiện công việc của nó:

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

Lưu ý rằng nếu bạn muốn biểu diễn str () cho các đối tượng nước ngoài, bạn nên định nghĩa nó trong phương thức str của chúng . Từ đó bạn có dict của các giá trị cho đối tượng. Sau đó, bạn có thể kết xuất một số loại mẫu hoặc bất cứ điều gì.


0

Django> = 2.0

Thêm get_fields()vào của bạn 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]

Sau đó gọi nó như object.get_fieldstrên template.html:

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

-1

<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


1
Xin chào và chào mừng đến với SO. Xin vui lòng không gửi mã chỉ câu trả lời. Ngoài ra câu hỏi này đã có câu trả lời được chấp nhận, định dạng mã của bạn không chính xác, bạn đang sử dụng các thuộc tính html không dùng nữa và quan trọng nhất: Bạn không giải thích cách mã của bạn cung cấp giải pháp tốt hơn so với mã được chấp nhận.
Frieder
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.