Scorrere i nomi e i valori dei campi dell'istanza del modello nel modello


183

Sto cercando di creare un modello di base per visualizzare i valori dei campi dell'istanza selezionata, insieme ai loro nomi. Pensalo come un semplice output dei valori di quell'istanza in formato tabella, con il nome del campo (verbose_name specificamente se specificato nel campo) nella prima colonna e il valore di quel campo nella seconda colonna.

Ad esempio, supponiamo di avere la seguente definizione del modello:

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

Vorrei che fosse emesso nel modello in questo modo (supponiamo un'istanza con i valori indicati):

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

Quello che sto cercando di ottenere è riuscire a passare un'istanza del modello a un modello ed essere in grado di scorrere su di esso dinamicamente nel modello, qualcosa del genere:

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

Esiste un modo pulito e "approvato da Django" per farlo? Sembra un compito molto comune e dovrò farlo spesso per questo particolare progetto.

Risposte:


171

model._meta.get_all_field_names()ti darà tutti i nomi dei campi del modello, quindi puoi usarlo model._meta.get_field()per arrivare al nome dettagliato e getattr(model_instance, 'field_name')ottenere il valore dal modello.

NOTA: model._meta.get_all_field_names()è obsoleto in Django 1.9. Utilizzare invece model._meta.get_fields()per ottenere i campi del modello e field.nameottenere il nome di ciascun campo.


2
Questo è ancora molto manuale e dovrei creare una sorta di meta oggetto nella vista che poi passo nel modello, che è più un hack di quanto vorrei. Sicuramente ci deve essere un modo più ordinato?
Wayne Koorts,

2
Potresti incapsulare tutto ciò in una classe, proprio come ModelForm.
Ignacio Vazquez-Abrams,

18
Non credo che tu possa chiamare alcun metodo _ nei template.
Issac Kelly,

2
Funziona ma non dovresti dipendere da un'API privata (in quanto ha il prefisso "_") per raggiungerla. Il problema di affidarsi all'API privata è che i metodi privati ​​non sono garantiti per funzionare da una versione all'altra.
Devy,

1
Penso che questo metodo non dovrebbe essere preferito in quanto non dovremmo accedere agli attributi a partire dal trattino basso dai modelli
GP92

72

Puoi usare il serializzatore di queryset to-python di Django .

Basta mettere il seguente codice nella tua vista:

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

E poi nel modello:

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

Il suo grande vantaggio è il fatto che gestisce i campi di relazione.

Per il sottoinsieme di campi provare:

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

È fantastico, ma con questo metodo, come si limiterebbero i risultati a determinati campi?
Herman Schaaf,

2
Questa dovrebbe essere la risposta definitiva, gestisce le chiavi esterne e nessuna chiamata API privata. Ottima risposta, grazie.
Yunti

3
Non è necessario utilizzare la serializzazione. È possibile utilizzare il metodo value () di un queryset , che restituisce un dizionario. Inoltre, questo metodo accetta un elenco di campi su cui eseguire il sottoinsieme. Vedi link . Vedi la mia risposta completa.
user3062149

Possiamo aggiornare questo per inviare solo i .fields invece di doverlo elaborare in un ciclo? Non voglio esporre i nomi di modello / tabella
Loser Coder,

Questo metodo consente il passaggio verbose_namedel campo?
alias51

71

Finalmente ho trovato una buona soluzione a questo sulla mailing list degli sviluppatori :

Nella vista aggiungi:

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

nel modello aggiungere:

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

1
Buona soluzione, ma non molto generica in quanto non restituisce un model_to_dict per i campi ForeignKey, ma un risultato unicode , quindi non è possibile serializzare facilmente oggetti complessi in dict
Vestel

22
Pericoloso sovrascrivere un oggetto, dovresti usare qualche altro nome variabile.
Emil Stenström,

Grazie! Ho sostituito model_to_dict () di Django per essere in grado di gestire ForeignKey. Si prega di vedere la mia risposta separata (ho eliminato il mio commento precedente poiché i commenti non supportano la formattazione del codice. Mi dispiace, non lo sapevo.)
Magnus Gustavsson

2
Supponendo che qui FooFormè un ModelForm, Non sarebbe più facile solo per fare: FooForm(instance=Foo.objects.get(pk=object_id)))?
beruic,

Hai idea di come visualizzeresti solo campi modificabili con questo metodo?
alias51

22

Alla luce del rilascio di Django 1.8 (e della formalizzazione dell'API Model _meta , ho pensato di aggiornarlo con una risposta più recente.

Supponendo lo stesso modello:

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 formalizzata Model _meta)

Modificato in Django 1.8:

L' _metaAPI modello è sempre esistita come interno di Django, ma non è stata formalmente documentata e supportata. Come parte dello sforzo di rendere pubblica questa API, alcuni dei punti di ingresso API già esistenti sono leggermente cambiati. È stata fornita una guida alla migrazione per aiutare a convertire il codice per utilizzare la nuova API ufficiale.

Nell'esempio seguente, utilizzeremo il metodo formalizzato per recuperare tutte le istanze di campo di un modello tramite 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')]

In realtà, è stato portato alla mia attenzione che quanto sopra è leggermente esagerato per ciò che era necessario (sono d'accordo!). Semplice è meglio di complesso. Lascio quanto sopra per riferimento. Tuttavia, per visualizzare nel modello, il metodo migliore sarebbe utilizzare un ModelForm e passare un'istanza. È possibile iterare sul modulo (equivalente di iterare su ciascuno dei campi del modulo) e utilizzare l'attributo label per recuperare il verbose_name del campo modello e utilizzare il metodo value per recuperare il valore:

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

Ora, rendiamo i campi nel modello:

<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
Sarebbe bello se modifichi la tua risposta per mostrare il modo "> 1.8" per inserire i campi del modello in un modello. Al momento la tua risposta non risponde direttamente alla domanda; mostra come ottenere i campi del modello nella shell.
Escher,

@Escher - Aggiornata la risposta! Grazie per il suggerimento Fammi sapere se ho perso qualcosa / incasinato qualcosa!
Michael B

Upvoted. Ho modificato per includere la stampa dei valori e dei nomi dei campi. Vedi cosa ne pensi.
Escher,

Dove stampi i valori? Lo vedo solo stampando il nome e verbose_name?
Dr. Ernie

@MichaelB Hmm. Non sono stato in grado di far funzionare "field.value"; i campi sembrano essere campi del database, non i dati effettivi della colonna. Ho dovuto usare un filtro chiamato getattr (oggetto, nome). Quale versione di Django funziona per te?
Dr. Ernie

19

Ecco un altro approccio che utilizza un metodo modello. Questa versione risolve i campi elenco / scelta, salta i campi vuoti e consente di escludere campi specifici.

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

Quindi nel tuo modello:

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

3
perché hai bisogno del except User.DoesNotExist:?
Sevenearths,

Sarei propenso a usare AttributeError invece di User.DoesNotExist: non vedo perché genererebbe User.DoesNotExist.
askvictor

Inoltre, potrebbe essere meglio usare self._meta.get_fields () poiché questo è ufficialmente esposto in django 1.8+. Tuttavia, poi finisci con le relazioni nel codice, che dovresti filtrare controllando f.is_relation
askvictor

Ho modificato la risposta per utilizzare AttributeError anziché User.DoesNotExist (che era rimasto dalla mia implementazione originale). Grazie. Sto resistendo _meta.get_fields()finché non riesco a provarlo.
shacker,

13

Ok, lo so che è un po 'tardi, ma dal momento che mi sono imbattuto in questo prima di trovare la risposta corretta, anche qualcun altro potrebbe farlo.

Dai documenti di 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.'}]

Mi piace questa risposta. Se la tua query restituisce più di un record e desideri solo l'ultimo, procedi come segue. 1. Assicurarsi di avere ordering = ['-id']in class Meta:del vostro oggetto in models.py. 2. quindi utilizzareBlog.objects.filter(name__startswith='Beatles').values()[0]
Sevenearths,

Idea intelligente. Ma se hai già un modeloggetto, allora colpiresti di nuovo il database solo per ottenere i campi. Qualche modo per aggirare questo?
dal

@ user1763732 basta controllare le documentazioni per il QuerySet: docs.djangoproject.com/en/dev/ref/models/querysets
olofom

9

È possibile utilizzare il values()metodo di a queryset, che restituisce un dizionario. Inoltre, questo metodo accetta un elenco di campi su cui eseguire il sottoinsieme. Il values()metodo non funzionerà get(), quindi è necessario utilizzare filter()(fare riferimento all'API QuerySet ).

In view...

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

In detail.html...

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

Per una raccolta di istanze restituite dal filtro:

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

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

Questo è fantastico, grazie! Ho una domanda, se mi potresti aiutare; Sto inserendo tutti i dati degli oggetti in a table, quindi ho bisogno di ognuno di essi keyin a th. Come posso farlo senza loop? Basta prendere qualsiasi istanza di oggetto e scorrere attraverso di essa per keys? Attualmente sto passando separatamente model_to_dict(Model())per il th, ma penso che sia un'istanza di oggetto non necessaria.
Oxwivi,

Risposta fantastica. Personalmente, l'ho usato sia in una vista elenco che in una vista dettagliata. La vista elenco è in gran parte ovvia da implementare, ma con la vista di dettaglio ho la precedenza get_objectsulla vista di dettaglio (alterata a causa della limitazione del codice in linea sui commenti, e non mi sembra che questo sia sufficiente per la sua risposta considerando quanto sia saturo questo thread): def get_object(self, **kwargs): obj = super().get_object(**kwargs) obj = obj.__class__.objects.filter(pk=obj.pk).values()[0] return obj
sdconrox,

come aggiungeresti obj.get_absolute_urla questo elenco senza duplicare le righe?
alias51

8

Ho usato https://stackoverflow.com/a/3431104/2022534 ma ho sostituito il model_to_dict () di Django con questo per essere in grado di gestire 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

Si noti che l'ho semplificato un po 'rimuovendo le parti dell'originale che non mi servivano. Potresti voler rimetterli.


8

Puoi avere un modulo per fare il lavoro per te.

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

Quindi nel modello:

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

3
Questo metodo (impiegato all'interno di a DetailView) funziona bene per me. Tuttavia, potresti voler utilizzare field.labelinvece di field.name.
David Cain,

7

Dovrebbe esserci davvero un modo integrato per farlo. Ho scritto questa utility build_pretty_data_viewche accetta un oggetto modello e un'istanza del modulo (un modulo basato sul modello) e restituisce a SortedDict.

I vantaggi di questa soluzione includono:

  • Conserva l'ordine usando il Django integrato SortedDict.
  • Quando tenta di ottenere l'etichetta / verbose_name, ma torna al nome del campo se non è definito.
  • Opzionalmente prenderà anche un exclude()elenco di nomi di campi per escludere determinati campi.
  • Se la classe del modulo include a Meta: exclude(), ma si desidera comunque restituire i valori, aggiungere tali campi append()all'elenco facoltativo .

Per utilizzare questa soluzione, prima aggiungi questo file / funzione da qualche parte, quindi importalo nel tuo 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

Quindi ora nel tuo views.pypotresti fare qualcosa del genere

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

Ora nel tuo my-template.htmlmodello puoi scorrere i dati in questo modo ...

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

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

{% endfor %}

In bocca al lupo. Spero che questo aiuti qualcuno!


7

Di seguito è il mio, ispirato a Shacker's get_all_fields . Ottiene un dict di un'istanza del modello, se incontra un campo relazione, quindi assegna ricorsivamente il valore del campo a un dict.

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

Questa funzione viene utilizzata principalmente per scaricare un'istanza del modello in dati json:

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

Ottimo lavoro! Suggerisci l'aggiunta del supporto delle scelte ... elif hasattr (field, 'options'): tree [field.name] = dict (field.choices) .get (value, value)
oden

5

Invece di modificare ogni modello, consiglierei di scrivere un tag modello che restituirà tutti i campi di qualsiasi modello dato.
Ogni oggetto ha un elenco di campi ._meta.fields.
Ogni oggetto campo ha un attributo nameche restituirà il suo nome e il metodo value_to_string()fornito con il modello objectrestituirà il suo valore.
Il resto è semplice come si dice nella documentazione di Django .

Ecco il mio esempio di come potrebbe apparire questo templatetag:

    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

Sì, non è carino, dovrai creare il tuo involucro. Dai un'occhiata all'app databrowse integrata , che ha tutte le funzionalità di cui hai davvero bisogno.


Stavo per dire ... databrowse fa proprio questo, anche se l'ho trovato un'app completamente inutile.
apre il

4

Questo può essere considerato un trucco, ma l'ho già fatto prima di utilizzare modelform_factory per trasformare un'istanza del modello in un modulo.

La classe Form ha molte più informazioni al suo interno che è super facile da ripetere e servirà allo stesso scopo a spese di un po 'più di spese generali. Se le dimensioni del tuo set sono relativamente ridotte, penso che l'impatto sulle prestazioni sarebbe trascurabile.

L'unico vantaggio oltre alla praticità ovviamente è che puoi facilmente trasformare la tabella in un datagrid modificabile in un secondo momento.


4

Ho escogitato il seguente metodo, che funziona per me perché in ogni caso al modello sarà associato un ModelForm.

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)

Ecco un estratto dal modello che sto usando per questa vista particolare:

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

La cosa bella di questo metodo è che posso scegliere su base modello per modello l'ordine in cui vorrei visualizzare le etichette dei campi, usando la tupla passata a GetModelData e specificando i nomi dei campi. Ciò mi consente anche di escludere determinati campi (ad es. Una chiave esterna dell'utente) poiché solo i nomi dei campi passati tramite la tupla sono integrati nel dizionario finale.

Non accetterò questa come risposta perché sono sicuro che qualcuno può inventare qualcosa di più "Djangonic" :-)

Aggiornamento: sto scegliendo questa come risposta finale perché è la più semplice tra quelle date che fa quello di cui ho bisogno. Grazie a tutti coloro che hanno contribuito con le risposte.


3

Soluzione Django 1.7 per me:

Ci sono variabili esatte alla domanda, ma dovresti sicuramente essere in grado di sezionare questo esempio

La chiave qui è di usare praticamente .__dict__il modello
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)

modello :

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

nel modello ho usato un filtro per accedere al campo in dict
filters.py :

@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

Sto usando questo, 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

Questo approccio mostra come utilizzare una classe come ModelForm di django e un tag modello come {{form.as_table}}, ma avere tutta la tabella come output di dati, non un modulo.

Il primo passo è stato la sottoclasse del widget TextInput di 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))

Quindi ho eseguito la sottoclasse di ModelForm di Django per scambiare i widget predefiniti con le versioni di sola lettura:

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" 

Erano gli unici widget di cui avevo bisogno. Ma non dovrebbe essere difficile estendere questa idea ad altri widget.


1

Solo una modifica di @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

Lascia che Django gestisca tutti gli altri campi diversi dai campi correlati. Sento che è più stabile



0

Ho appena provato qualcosa di simile in shell e sembra fare il suo lavoro:

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

Notare che se si desidera la rappresentazione str () per oggetti estranei, è necessario definirla nel loro metodo str . Da questo hai dettato i valori per l'oggetto. Quindi puoi eseguire il rendering di un tipo di modello o altro.


0

Django> = 2.0

Aggiungi get_fields()a 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]

Quindi chiamalo come object.get_fieldssul tuo 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
Ciao e benvenuto in SO. Si prega di non inviare solo risposte al codice. Anche questa domanda ha già una risposta accettata, la formattazione del codice non è corretta, stai utilizzando attributi html obsoleti e, cosa più importante: non stai spiegando come il tuo codice offre una soluzione migliore di quella accettata.
Frieder,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.