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.

4voto

Wayne Koorts Punkte 10492

Ich habe mir die folgende Methode ausgedacht, die für mich funktioniert, weil dem Modell in jedem Fall ein ModelForm zugeordnet wird.

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)

Hier ist ein Auszug aus der Vorlage, die ich für diese spezielle Ansicht verwende:

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

Das Schöne an dieser Methode ist, dass ich die Reihenfolge, in der ich die Feldbezeichnungen anzeigen möchte, für jede Vorlage einzeln festlegen kann, indem ich das an GetModelData übergebene Tupel verwende und die Feldnamen festlege. Auf diese Weise kann ich auch bestimmte Felder ausschließen (z. B. einen User-Fremdschlüssel), da nur die über das Tupel übergebenen Feldnamen in das endgültige Wörterbuch aufgenommen werden.

Ich werde das nicht als Antwort akzeptieren, denn ich bin sicher, dass jemandem etwas "Djangonischeres" einfällt :-)

Aktualisierung: Ich wähle dies als endgültige Antwort, weil es die einfachste der gegebenen Antworten ist, die das tut, was ich brauche. Vielen Dank an alle, die Antworten beigetragen haben.

2voto

Chuck Punkte 1069

Dieser Ansatz zeigt, wie man eine Klasse wie django's ModelForm und ein Template-Tag wie {{ form.as_table }} verwendet, aber die Tabelle wie eine Datenausgabe und nicht wie ein Formular aussehen lässt.

Der erste Schritt bestand darin, das TextInput-Widget von django zu unterklassifizieren:

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

Dann habe ich django's ModelForm subclassed, um die Standard-Widgets für readonly Versionen auszutauschen:

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" 

Das waren die einzigen Widgets, die ich brauchte. Aber es sollte nicht schwierig sein, diese Idee auf andere Widgets auszuweiten.

2voto

Renyi Punkte 173

Ich benutze das hier, 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>

1voto

Shivam Goyal Punkte 133

Nur eine Bearbeitung von @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

Lassen Sie Django alle anderen Felder außer den Bezugsfeldern bearbeiten. Ich denke, das ist stabiler

0voto

idle sign Punkte 1134

Werfen Sie einen Blick auf django-etc Anwendung. Sie hat model_field_verbose_name Template-Tag, um ausführliche Feldnamen aus Templates zu erhalten: http://django-etc.rtfd.org/en/latest/models.html#model-field-template-tags

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