208 Stimmen

Iterieren Sie über die Feldnamen und Werte der Modellinstanz in der Vorlage

Ich versuche, eine einfache Vorlage zu erstellen, um die Feldwerte der ausgewählten Instanz zusammen mit ihren Namen anzuzeigen. Stellen Sie sich das als eine Standardausgabe der Werte dieser Instanz im Tabellenformat vor, mit dem Feldnamen (verbose_name, falls für das Feld angegeben) in der ersten Spalte und dem Wert dieses Feldes in der zweiten Spalte.

Nehmen wir zum Beispiel an, wir haben die folgende Modelldefinition:

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

Ich möchte, dass es in der Vorlage wie folgt ausgegeben wird (nehmen Sie eine Instanz mit den angegebenen Werten an):

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

Was ich zu erreichen versuche, ist in der Lage, eine Instanz des Modells an eine Vorlage zu übergeben und in der Lage sein, über es dynamisch in der Vorlage, etwas wie dieses zu wiederholen:

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

Gibt es eine saubere, "Django-genehmigte" Weise, dies zu tun? Es scheint wie eine sehr häufige Aufgabe, und ich muss es oft für dieses bestimmte Projekt zu tun.

196voto

Ignacio Vazquez-Abrams Punkte 735200

model._meta.get_all_field_names() gibt Ihnen alle Feldnamen des Modells, dann können Sie mit model._meta.get_field() um sich zum ausführlichen Namen vorzuarbeiten, und getattr(model_instance, 'field_name') um den Wert aus dem Modell zu erhalten.

HINWEIS: model._meta.get_all_field_names() ist in django 1.9 veraltet. Verwenden Sie stattdessen model._meta.get_fields() um die Felder des Modells zu erhalten und field.name um jeden Feldnamen zu erhalten.

86voto

Pawel Furmaniak Punkte 4264

Sie können Djangos to-python queryset serializer.

Fügen Sie einfach den folgenden Code in Ihre Ansicht ein:

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

Und dann in der Vorlage:

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

Sein großer Vorteil ist die Tatsache, dass es Beziehungsfelder verarbeitet.

Versuchen Sie es für die Teilmenge der Felder:

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

81voto

Roger Punkte 4511

Endlich habe ich eine gute Lösung für dieses Problem auf die Dev-Mailingliste :

In der Ansicht hinzufügen:

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

in der Vorlage hinzufügen:

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

26voto

shacker Punkte 13440

Hier ist ein weiterer Ansatz, der ein Modellverfahren verwendet. Diese Version löst Auswahllisten-/Wahlfelder auf, überspringt leere Felder und ermöglicht es Ihnen, bestimmte Felder auszuschließen.

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

Dann in Ihrer Vorlage:

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

24voto

Michael B Punkte 4698

In Anbetracht der Veröffentlichung von Django 1.8 (und der Formalisierung der Modell _meta API Ich dachte mir, ich aktualisiere diesen Artikel mit einer neueren Antwort.

Angenommen, es handelt sich um dasselbe Modell:

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+ (formalisiertes Model _meta API)

Geändert in Django 1.8:

Das Modell _meta API hat schon immer als Django-internes Element existiert, wurde aber nicht offiziell dokumentiert und unterstützt. Als Teil der Bemühungen, diese API öffentlich zu machen, wurden einige der bereits bestehenden API-Einstiegspunkte leicht verändert. Es wurde ein Migrationsleitfaden bereitgestellt, der Sie bei der Konvertierung Ihres Codes zur Verwendung der neuen, offiziellen API unterstützt.

Im folgenden Beispiel verwenden wir die formalisierte Methode für Abrufen aller Feldinstanzen eines Modells über 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')]

Ich bin darauf aufmerksam gemacht worden, dass die obigen Ausführungen etwas zu weit gehen (ich stimme zu!). Einfach ist besser als komplex. Ich lasse die obigen Angaben als Referenz. Zur Anzeige in der Vorlage wäre es jedoch am besten, ein ModelForm zu verwenden und eine Instanz zu übergeben. Sie können über das Formular iterieren (gleichbedeutend mit der Iteration über die einzelnen Felder des Formulars) und das Attribut label verwenden, um den verbose_name des Modellfeldes abzurufen, und die Methode value verwenden, um den Wert abzurufen:

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

Jetzt rendern wir die Felder in der Vorlage:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X