Şablondaki model örneği alan adları ve değerleri üzerinde yineleme


183

İsimleri ile birlikte seçilen örneğin alan değerlerini görüntülemek için temel bir şablon oluşturmaya çalışıyorum. Bunu, ilk sütunda alan adı (özellikle alanda belirtilmişse ayrıntılı_adı) ve ikinci sütundaki o alanın değeri ile tablo örneğindeki değerlerin standart çıktısı olarak düşünün.

Örneğin, aşağıdaki model tanımına sahip olduğumuzu varsayalım:

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

Ben böyle çıktı şablon istiyorum istiyorum (verilen değerleri ile bir örnek varsayalım):

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

Ne elde etmeye çalışıyorum modelin bir örneğini bir şablona geçirebiliyor ve şablonda dinamik olarak yineleyebiliyoruz, şöyle bir şey:

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

Bunu yapmanın düzgün, "Django onaylı" bir yolu var mı? Çok yaygın bir görev gibi görünüyor ve bunu bu proje için sık sık yapmam gerekecek.

Yanıtlar:


171

model._meta.get_all_field_names()size tüm modelin alan adlarını verir, daha sonra model._meta.get_field()ayrıntılı isme giden yolu çalışmak getattr(model_instance, 'field_name')ve değeri modelden almak için kullanabilirsiniz.

NOT: model._meta.get_all_field_names()django 1.9'da kullanımdan kaldırılmıştır. Bunun yerine model._meta.get_fields(), modelin alanlarını ve field.nameher alan adını almak için kullanın .


2
Bu hala çok manuel ve görünümde daha sonra bir şablon meta nesne oluşturmak zorunda kalacaktı, ki bu benim istediğimden daha fazla bir hack. Elbette daha temiz bir yol olmalı mı?
Wayne Koorts

2
Tüm bunları ModelForm'un yaptığı gibi bir sınıfta kapsülleyebilirsiniz.
Ignacio Vazquez-Abrams

18
Şablonlarda _ yöntemini çağırabileceğinize inanmıyorum.
Issac Kelly

2
Bu işe yarar, ancak bunu başarmak için özel bir API'ya ("_" ön eki olarak bağlı olduğundan) bağlı olmamalısınız. Özel API'ye güvenme sorunu, özel yöntemlerin sürümden sürüme çalışacağının garanti edilmemesidir.
Devy

1
Şablonlardan alt çizgi ile başlayan özniteliklere erişmememiz gerektiği için bu yöntemin tercih edilmemesi gerektiğini düşünüyorum
GP92

72

Sen Django'nın kullanabilirsiniz to-piton queryset serileştiricisini kullanabilirsiniz.

Aşağıdaki kodu görünümünüze eklemeniz yeterlidir:

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

Ve sonra şablonda:

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

En büyük avantajı ilişki alanlarını ele almasıdır.

Alanların alt kümesi için şunu deneyin:

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

Bu harika - ancak bu yöntemle, sonuçlar yalnızca belirli alanlarla nasıl sınırlanır?
Herman Schaaf

2
Bu kesin cevap olmalı, yabancı anahtarları idare etmeli ve özel api çağrıları olmamalıdır. Harika cevap, teşekkürler.
Yunti

3
Serileştirme kullanmak gerekli değildir. Bir sözlük döndüren bir queryset değerleri () yöntemini kullanabilirsiniz . Ayrıca, bu yöntem altküme yapılacak alanların bir listesini kabul eder. Bkz. Bağlantı . Tam cevabımı görün.
user3062149

Bunu bir döngüde işlemek yerine yalnızca .fields'e gönderecek şekilde güncelleyebilir miyiz? Model / tablo adlarını göstermek istemiyorum
Loser Coder

Bu yöntem verbose_namealanın geçirilmesine izin veriyor mu?
alias51

71

Sonunda geliştirici listesinde iyi bir çözüm buldu :

Görünümde şunu ekleyin:

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

şablonda ekleyin:

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

1
İyi bir çözüm, ancak ForeignKey alanları için bir model_to_dict değil, unicode sonucu döndürdüğü için çok genel değil , bu yüzden karmaşık nesneyi dikte halinde serileştiremezsiniz
Vestel

22
Nesneyi geçersiz kılmak tehlikelidir, başka bir değişken adı kullanmalısınız.
Emil Stenström

Teşekkür ederim! ForeignKey ile başa çıkabilmek için Django'nun model_to_dict () yöntemini değiştirdim. Lütfen ayrı cevabımı görün (Yorumlar kod biçimlendirmeyi desteklemediğinden önceki yorumumu sildim. Üzgünüm, bunu bilmiyordum.)
Magnus Gustavsson

2
Burada bunun FooFormbir olduğunu varsayarsak ModelForm, sadece yapmak daha kolay olmaz mıydı FooForm(instance=Foo.objects.get(pk=object_id)))?
beruic

Bu yöntemle yalnızca düzenlenebilir alanları nasıl görüntüleyeceğinize dair bir fikriniz var mı?
alias51

22

Django 1.8'in yayınlanması (ve Model _meta API'sının resmileştirilmesi) ışığında bunu daha yeni bir cevapla güncelleyeceğimi düşündüm.

Aynı modeli varsayarsak:

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+ (resmi Model _meta API'sı)

Django 1.8'de değiştirildi:

Model _metaAPI her zaman bir Django dahili olarak mevcuttu, ancak resmi olarak belgelenmedi ve desteklenmedi. Bu API'yı herkese açık hale getirme çabasının bir parçası olarak, mevcut API giriş noktalarından bazıları biraz değişti. Kodunuzu yeni, resmi API'yı kullanacak şekilde dönüştürmenize yardımcı olacak bir taşıma kılavuzu sağlanmıştır.

Aşağıdaki örnekte, biz resmiyet yöntemini kullanacak bir modelin tüm alan örneklerini almak yoluyla 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')]

Aslında, yukarıdakilerin ihtiyaç duyulan şey için biraz fazla olduğu dikkatimi çekti (katılıyorum!). Basit, karmaşık olmaktan iyidir. Yukarıdaki referans için ayrılıyorum. Ancak, şablonda görüntülemek için en iyi yöntem bir ModelForm kullanmak ve bir örnek vermek olacaktır. Form üzerinde yineleme yapabilir (form alanlarının her birinde yineleme işlemine eşdeğer) ve model alanının ayrıntılı_adı'nı almak için label niteliğini kullanabilir ve değeri almak için value yöntemini kullanabilirsiniz:

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

Şimdi, şablondaki alanları oluşturuyoruz:

<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
Yanıtınızı, model alanlarını bir şablona yerleştirmenin "> 1.8" yolunu gösterecek şekilde ayarlamanız harika olurdu. Şu anda cevabınız doğrudan soruyu cevaplamıyor; modelin alanlarının kabuğa nasıl alınacağını gösterir.
Escher

@Escher - Cevabı güncelledi! Önerin için teşekkürler. Bir şey kaçırırsam / bir şeyleri mahvedersem haberim olsun!
Michael B

Upvoted. Alan adlarının yanı sıra değerlerin yazdırılmasını da içerecek şekilde düzenledim. Ne düşündüğünüzü görün.
Escher

Değerleri nereye yazdırıyorsunuz? Sadece adını ve ayrıntılı_adı yazdırdığını görüyorum?
Dr Ernie

@MichaelB Hmm. Çalışmak için "field.value" alamadım; alanlar, gerçek sütun verileri değil, veritabanı alanları gibi görünür. Getattr (nesne, ad) adlı bir filtre kullanmak zorunda kaldı. Bu sizin için hangi Django sürümünü kullanıyor?
Dr Ernie

19

İşte bir model yöntemi kullanan başka bir yaklaşım. Bu sürüm, seçim listesi / seçim alanlarını çözer, boş alanları atlar ve belirli alanları hariç tutmanıza olanak tanır.

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

Ardından şablonunuzda:

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

3
neden ihtiyacın var except User.DoesNotExist:?
Yedi Yıl

AttributeError yerine User.DoesNotExist kullanmaya eğilimli olurum - Neden User.DoesNotExist atar neden göremiyorum.
askvictor

Ayrıca, django 1.8+ 'da resmen maruz kaldığı için self._meta.get_fields () kullanmak daha iyi olabilir. Ancak, koddaki ilişkilerle sonuçlanırsınız, f.is_relation
askvictor

Yanıt, User.DoesNotExist (bu benim orijinal uygulamadan kalan) yerine AttributeError kullanmak için düzenledim. Teşekkürler. Ben oyalıyorum _meta.get_fields()bunu test edebilirsiniz kadar.
shacker

13

Tamam, bunun biraz geç olduğunu biliyorum, ama doğru cevabı bulmadan önce bunun üzerine tökezlediğimden başka biri de olabilir.

Gönderen Django dokümanlar :

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

Bu cevabı beğendim. Sorgunuz birden fazla kayıt döndürüyorsa ve yalnızca en son kaydı istiyorsanız, aşağıdakileri yapın. 1. çalışmadığından emin olun ve sahip ordering = ['-id']de class Meta:içinde Nesnenizin models.py. 2. sonra kullanınBlog.objects.filter(name__startswith='Beatles').values()[0]
Sevenearths

Zekice fikir. Ancak zaten bir modelnesneniz varsa, alanları almak için veritabanına tekrar vurursunuz. Bunun herhangi bir yolu var mı?
frnhr

@ user1763732 sadece QuerySet'in belgelerine bakın: docs.djangoproject.com/en/dev/ref/models/querysets
olofom

9

Bir sözlük döndüren a values()yöntemini kullanabilirsiniz queryset. Ayrıca, bu yöntem altküme yapılacak alanların bir listesini kabul eder. values()Yöntem ile çalışmaz get()kullanmanız gerekir böylece, filter()(bkz QuerySet API ).

İçinde view...

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

İçinde detail.html...

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

Bir İçin örneklerinin koleksiyonu filtrenin döndürdüğü:

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

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

Bu inanılmaz, teşekkürler! Bir sorum var, bana yardım edebilirsen; Ben tüm nesneleri veri bir koymak table, bu yüzden her keys bir gerekir th. Bunu döngüsüz nasıl yapabilirim? Sadece herhangi bir nesne örneği almak ve keys için yineleme ? Şu anda ayrı ayrı geçiyorum model_to_dict(Model())için th, ama gereksiz bir nesne örnekleme olduğunu düşünüyorum.
Oxwivi

Harika bir cevap. Şahsen bunu hem liste görünümünde hem de ayrıntı görünümünde kullandım. Liste görünümü uygulamak için büyük ölçüde açıktır, ama detay görünümü Ben geçersiz kılma ile get_objectayrıntı görünümünde (yorumlarda nedeniyle satır içi kod sınırlama mangled ve bu konu doymuş nasıl dikkate kendi cevap bu bu yeterlidir gibi hissetmiyorum): def get_object(self, **kwargs): obj = super().get_object(**kwargs) obj = obj.__class__.objects.filter(pk=obj.pk).values()[0] return obj
sdconrox

obj.get_absolute_urlsatırları çoğaltmadan bu listeye nasıl eklersiniz ?
alias51

8

Ben https://stackoverflow.com/a/3431104/2022534 kullandım ancak ForeignKey ile baş edebilmek için Django'nun model_to_dict () yöntemini bununla değiştirdim:

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

İhtiyacım olmayan orijinalin parçalarını çıkararak biraz basitleştirdiğimi lütfen unutmayın. Bunları geri koymak isteyebilirsiniz.


8

İşi sizin için yapacak bir forma sahip olabilirsiniz.

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

Sonra şablonda:

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

3
(A içinde kullanılan DetailView) bu yöntem benim için iyi çalışıyor. Ancak, field.labelbunun yerine kullanmak isteyebilirsiniz field.name.
David Cain

7

Bunu yapmak için gerçekten yerleşik bir yol olmalı. build_pretty_data_viewBir model nesnesi ve form örneği (modelinize dayalı bir form) alan ve bir döndüren bu yardımcı programı yazdımSortedDict .

Bu çözümün faydaları şunları içerir:

  • Django'nun yerleşik özelliğini kullanarak siparişi korur SortedDict .
  • / Verbose_name etiketini almaya çalıştığında, ancak tanımlanmadıysa alan adına geri döner.
  • Ayrıca isteğe bağlı olarak bir exclude() belirli alanları hariç tutmak için alan adlarının listesini .
  • Form sınıfınız bir içerir Meta: exclude(), ancak yine de değerleri döndürmek istiyorsanız, bu alanları isteğe bağlı append()listeye ekleyin .

Bu çözümü kullanmak için, önce bu dosyayı / işlevi bir yere ekleyin, ardından bilgisayarınıza aktarın 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

Yani şimdi senin içinde views.pyböyle bir şey yapabilirsin

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

Şimdi my-template.htmlşablonunuzdaki veriler üzerinde tekrarlayabilirsiniz ...

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

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

{% endfor %}

İyi şanslar. Umarım bu birine yardımcı olur!


7

Aşağıda, shacker'dan esinlenilen benim get_all_fields. Bir model örneğinin bir diksiyonunu alır, eğer ilişki alanı ile karşılaşırsa, alan değerini özyinelemeli olarak atar.

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

Bu işlev temel olarak bir model örneğini json verilerine dökmek için kullanılır:

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

Harika iş! Seçenek desteği eklemeyi önerin ... elif hasattr (alan, 'seçimler'): ağaç [field.name] = dict (field.choices) .get (değer, değer)
oden

5

Her modeli düzenlemek yerine, verilen herhangi bir modelin tüm alanını döndürecek bir şablon etiketi yazmanızı tavsiye ederim . Her nesnenin alan listesi vardır . Her alan nesnesinin adını döndürecek bir özniteliği vardır ve modelinizle birlikte verilen yöntem değerini döndürür. Gerisi Django belgelerinde söylendiği kadar basit .
._meta.fields
namevalue_to_string()object

İşte bu şablon etiketinin nasıl görünebileceğine dair örneğim:

    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

Evet güzel değil, kendi ambalajını yapman gerekecek. Gerçekten ihtiyacınız olan tüm işlevselliğe sahip yerleşik veri tabanı uygulamasına bir göz atın .


Şunu söyleyecektim ... databrowse tam olarak işe yaramaz bir uygulama olduğunu fark etsem de.
mpen

4

Bu bir saldırı olarak kabul edilebilir, ancak bir model örneğini forma dönüştürmek için modelform_factory kullanmadan önce bunu yaptım.

Form sınıfı, içinde tekrarlanması çok kolay olan çok daha fazla bilgiye sahiptir ve aynı amaca biraz daha fazla masraf pahasına hizmet edecektir. Ayarladığınız boyutlar nispeten küçükse, performans etkisinin önemsiz olacağını düşünüyorum.

Elbette kolaylığın yanı sıra avantajı, tabloyu daha sonraki bir tarihte kolayca düzenlenebilir bir veri ızgarasına dönüştürebilmenizdir.


4

Ben her durumda model onunla ilişkili bir ModelForm olacak çünkü benim için çalışan aşağıdaki yöntemi ile geldim.

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)

İşte bu özel görünüm için kullandığım şablondan bir alıntı:

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

Bu yöntemle ilgili güzel bir şey, şablon etiketleri temelinde GetModelData'ya iletilen ve alan adlarını belirterek alan etiketlerini görüntülemek istediğim sıraya göre seçebilmemdir. Bu, aynı zamanda, yalnızca grup aracılığıyla iletilen alan adları son sözlüğe dahil edildiğinden, belirli alanları (örn. Kullanıcı yabancı anahtarı) hariç tutmamı sağlar.

Bunu cevap olarak kabul etmeyeceğim, çünkü eminim ki birisi daha fazla "Djangonic" ile karşılaşabilir :-)

Güncelleme: Bunu son cevap olarak seçiyorum çünkü ihtiyacım olanı yapanlardan en basit olanı. Cevap veren herkese teşekkürler.


3

Benim için Django 1.7 çözümü:

Sorunun tam olarak değişkenleri var, ancak bu örneği kesinlikle inceleyebilmelisiniz

Burada anahtar hemen hemen kullanmaktır .__dict__modeli
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)

şablon :

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

şablonda, dict
filters.py'deki alana erişmek için bir filtre kullandım :

@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

Bunu https://github.com/miracle2k/django-tables kullanıyorum .

<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

Bu yaklaşım, django's ModelForm gibi bir sınıfın ve {{form.as_table}} gibi bir şablon etiketinin nasıl kullanılacağını gösterir, ancak tüm tablonun bir form değil, veri çıktısı gibi görünmesini sağlar.

İlk adım, django'nun TextInput widget'ını alt sınıflamaktı:

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

Sonra salt okunur sürümler için varsayılan widget'ları değiştirmek için django ModelForm alt sınıfta:

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" 

İhtiyacım olan tek aletler bunlardı. Ancak bu fikri diğer widget'lara genişletmek zor olmamalı.


1

@Wonder'ın sadece bir düzenlemesi

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'nun ilgili alanlar dışındaki tüm alanları işlemesine izin verin. Bunun daha kararlı olduğunu hissediyorum



0

Sadece böyle bir şeyi kabukta test ettim ve işini yapıyor gibi görünüyor:

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

Yabancı nesneler için str () temsilini istiyorsanız, str yönteminde tanımlamanız gerektiğini unutmayın . Bundan, nesne için değerleriniz var. Sonra bir tür şablon veya herhangi bir şey oluşturabilirsiniz.


0

Django> = 2.0

Ekle get_fields()adresinden Müşteri 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]

Sonra da diyoruz object.get_fieldssizinle ilgili şu 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
Merhaba ve SO'ya hoş geldiniz. Lütfen kodu sadece cevap göndermeyin. Ayrıca bu sorunun zaten kabul edilmiş bir cevabı var, kod biçimlendirmeniz doğru değil, kullanımdan kaldırılmış html öznitelikleri kullanıyorsunuz ve en önemlisi: Kodunuzun kabul edilenlerden nasıl daha iyi bir çözüm sağladığını açıklamıyorsunuz.
Frieder
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.