Iterar sobre nomes e valores de campos da instância do modelo no modelo


183

Estou tentando criar um modelo básico para exibir os valores de campo da instância selecionada, juntamente com seus nomes. Pense nisso como apenas uma saída padrão dos valores dessa instância no formato de tabela, com o nome do campo (verbose_name especificamente se especificado no campo) na primeira coluna e o valor desse campo na segunda coluna.

Por exemplo, digamos que temos a seguinte definição de modelo:

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

Eu gostaria que ele fosse produzido no modelo da seguinte forma (assuma uma instância com os valores fornecidos):

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

O que estou tentando alcançar é ser capaz de passar uma instância do modelo para um modelo e poder iterá-lo dinamicamente no modelo, algo como isto:

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

Existe uma maneira elegante e "aprovada pelo Django" de fazer isso? Parece uma tarefa muito comum, e precisarei fazê-lo frequentemente para este projeto em particular.

Respostas:


171

model._meta.get_all_field_names()fornecerá todos os nomes de campo do modelo, você poderá usar model._meta.get_field()o caminho para o nome detalhado e getattr(model_instance, 'field_name')obter o valor do modelo.

NOTA: model._meta.get_all_field_names()está obsoleto no django 1.9. Em vez disso, use model._meta.get_fields()para obter os campos do modelo e field.namepara obter o nome de cada campo.


2
Isso ainda é muito manual, e eu teria que criar algum tipo de meta-objeto na visualização que passo para o modelo, que é mais um truque do que eu gostaria. Certamente deve haver uma maneira mais limpa?
Wayne Koorts

2
Você pode encapsular tudo isso em uma classe, da mesma forma que o ModelForm.
Ignacio Vazquez-Abrams

18
Não acredito que você possa chamar nenhum _ método nos modelos.
Issac Kelly

2
Isso funciona, mas você não deve depender de uma API privada (como prefixa com "_") para alcançá-la. O problema de depender da API privada é que não é garantido que os métodos privados funcionem de versão para versão.
Devy #

1
Eu acho que este método não deve ser preferido como não devemos estar acessando os atributos começando com sublinhado a partir de modelos
GP92

72

Você pode usar o serializador de queryset do Django para python .

Basta colocar o seguinte código em sua exibição:

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

E então no modelo:

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

Sua grande vantagem é o fato de lidar com campos de relações.

Para o subconjunto de campos, tente:

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

Isso é legal - mas com esse método, como limitar os resultados a apenas determinados campos?
Herman Schaaf #

2
Essa deve ser a resposta definitiva, manipula chaves estrangeiras e nenhuma chamada de API privada. Ótima resposta, obrigado.
Yunti

3
Não é necessário usar serializar. Você pode usar o método values ​​() de um conjunto de consultas , que retorna um dicionário. Além disso, este método aceita uma lista de campos para subconjunto. Veja o link . Veja minha resposta completa.
user3062149

Podemos atualizar isso para enviar apenas os campos. Em vez de precisar processá-lo em um loop? Eu não quero expor os nomes de tabela / modelo
Perdedor Coder

Este método permite que verbose_nameo campo seja passado?
alias51 14/01

71

Finalmente encontrei uma boa solução para isso na lista de discussão do desenvolvedor :

Na visualização, adicione:

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

no modelo, adicione:

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

1
Boa solução, mas não muito genérico, pois não retorna um model_to_dict para campos ForeignKey, mas unicode resultado, para que você possa não é fácil serialize complexo objeto em dict
Vestel

22
Perigoso para substituir um objeto, você deve usar outro nome variável.
Emil Stenström

Obrigado! Substituí model_to_dict () do Django para poder lidar com ForeignKey. Por favor, veja a minha resposta em separado (eu deletei meu comentário anterior desde observações não suportam código de formatação Desculpe, eu não sabia disso..)
Magnus Gustavsson

2
Supondo que aqui FooFormseja um ModelForm, não seria mais fácil fazer FooForm(instance=Foo.objects.get(pk=object_id))):?
Beruic

Alguma idéia de como você exibirá apenas campos editáveis ​​com esse método?
alias51 14/01

22

À luz do lançamento do Django 1.8 (e da formalização da API Model _meta , achei que atualizaria isso com uma resposta mais recente.

Assumindo o mesmo modelo:

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+ (Modelo formalizado _meta API)

Alterado no Django 1.8:

A _metaAPI do modelo sempre existiu como um interno do Django, mas não foi formalmente documentada e suportada. Como parte do esforço para tornar essa API pública, alguns dos pontos de entrada da API já existentes mudaram um pouco. Um guia de migração foi fornecido para ajudar na conversão do seu código para usar a nova API oficial.

No exemplo abaixo, utilizaremos o método formalizado para recuperar todas as instâncias de campo de um modelo por meio de 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')]

Na verdade, soube que o exposto acima é um pouco exagerado para o que era necessário (eu concordo!). Simples é melhor que complexo. Estou deixando o acima para referência. No entanto, para exibir no modelo, o melhor método seria usar um ModelForm e passar em uma instância. Você pode iterar sobre o formulário (equivalente a iterar sobre cada um dos campos do formulário) e usar o atributo label para recuperar o verbose_name do campo de modelo e usar o método value para recuperar o valor:

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

Agora, renderizamos os campos no modelo:

<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
Seria ótimo se você ajustasse sua resposta para mostrar a maneira "> 1.8" para colocar os campos do modelo em um modelo. No momento, sua resposta não responde diretamente à pergunta; mostra como obter os campos do modelo no shell.
Escher

@Escher - Atualizado a resposta! Obrigado pela sugestão. Deixe-me saber se eu perdi alguma coisa / estraguei tudo!
22716 Michael B #

Votado. Editei para incluir a impressão dos valores e nomes dos campos. Veja o que você pensa.
Escher

Onde você imprime os valores? Eu só vejo isso imprimindo o nome e verbose_name?
Dr. Ernie

@MichaelB Hmm. Não consegui fazer com que "field.value" funcionasse; os campos parecem ser campos do banco de dados, não os dados reais da coluna. Eu tive que usar um filtro chamado getattr (objeto, nome). Qual versão do Django funciona para você?
Dr. Ernie

19

Aqui está outra abordagem usando um método de modelo. Esta versão resolve campos de lista de opções / opções, ignora campos vazios e permite excluir campos específicos.

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

Em seguida, no seu modelo:

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

3
por que você precisa do except User.DoesNotExist:?
Sevenearths 27/10/11

Eu estaria inclinado a usar AttributeError em vez de User.DoesNotExist - não consigo ver por que ele lançaria User.DoesNotExist.
askvictor

Além disso, pode ser melhor usar self._meta.get_fields (), pois isso é oficialmente exposto no django 1.8+. No entanto, em seguida, você acabar com as relações no código, que você tem que filtrar, verificando f.is_relation
askvictor

Eu editei a resposta para usar AttributeError em vez de User.DoesNotExist (que foi uma sobra da minha implementação original). Obrigado. Estou esperando _meta.get_fields()até que eu possa testá-lo.
shacker 6/09/16

13

Ok, eu sei que é um pouco tarde, mas desde que me deparei com isso antes de encontrar a resposta correta, o mesmo poderia acontecer com outra pessoa.

Nos documentos do 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.'}]

Eu gosto desta resposta. Se sua consulta retornar mais de um registro e você desejar apenas o mais recente, faça o seguinte. 1. Certifique-se que você tem ordering = ['-id']na class Meta:do seu objeto em models.py. 2. use entãoBlog.objects.filter(name__startswith='Beatles').values()[0]
Sevenearths

Ideia inteligente. Mas se você já tem um modelobjeto, acessaria o banco de dados novamente apenas para obter os campos. Alguma maneira de contornar isso?
frnhr

@ user1763732 basta verificar as documentações para os QuerySet: docs.djangoproject.com/en/dev/ref/models/querysets
olofom

9

Você pode usar o values()método de a queryset, que retorna um dicionário. Além disso, este método aceita uma lista de campos para subconjunto. O values()método não funcionará get(), portanto, você deve usar filter()(consulte a API QuerySet ).

Em view...

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

Em detail.html...

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

Para uma coleção de instâncias retornadas pelo filtro:

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

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

Isso é incrível, obrigado! Eu tenho uma pergunta, se você puder me ajudar; Estou colocando todos os dados de objetos em um table, então preciso de cada keys em um th. Como faço isso sem loops? Basta pegar qualquer instância de objeto e iterar por keys? Atualmente, estou passando separadamente model_to_dict(Model())pelo th, mas acho que é uma instanciação de objeto desnecessária.
Oxwivi

Resposta fantástica. Pessoalmente, usei isso na exibição de lista e na exibição de detalhes. A exibição em lista é bastante óbvia para implementar, mas, com a exibição detalhada, eu substituo get_objecta exibição detalhada (confusa devido à limitação de código embutido nos comentários, e não sinto que isso seja suficiente para sua própria resposta, considerando a saturação desse encadeamento): def get_object(self, **kwargs): obj = super().get_object(**kwargs) obj = obj.__class__.objects.filter(pk=obj.pk).values()[0] return obj
sdconrox

como você adicionaria obj.get_absolute_urla essa lista sem duplicar as linhas?
alias51 6/01

8

Eu usei https://stackoverflow.com/a/3431104/2022534, mas substitui model_to_dict () do Django por isso para poder lidar com 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

Observe que simplifiquei bastante removendo as partes do original que não precisava. Você pode querer colocá-los de volta.


8

Você pode ter um formulário fazendo o trabalho para você.

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

Então no modelo:

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

3
Este método (empregado em a DetailView) funciona bem para mim. No entanto, você pode usar em field.labelvez de field.name.
David Cain

7

Realmente deve haver uma maneira integrada de fazer isso. Eu escrevi esse utilitário build_pretty_data_viewque pega um objeto de modelo e uma instância de formulário (um formulário com base no seu modelo) e retorna a SortedDict.

Os benefícios desta solução incluem:

  • Ele preserva a ordem usando o built-in do Django SortedDict.
  • Quando tenta obter o rótulo / verbose_name, mas volta ao nome do campo se um não estiver definido.
  • Opcionalmente, também será necessária uma exclude()lista de nomes de campos para excluir determinados campos.
  • Se sua classe de formulário incluir a Meta: exclude(), mas você ainda desejar retornar os valores, adicione esses campos à append()lista opcional .

Para usar esta solução, primeiro adicione este arquivo / função em algum lugar e depois importe-o para o seu 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

Então agora views.pyvocê pode fazer algo assim

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

Agora, no seu my-template.htmlmodelo, você pode interagir com os dados dessa forma ...

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

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

{% endfor %}

Boa sorte. Espero que isso ajude alguém!


7

Abaixo está o meu, inspirado no shacker's get_all_fields . Ele obtém o ditado de uma instância do modelo, se encontrar um campo de relação, e atribuir o valor do campo a um dict recursivamente.

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

Esta função é usada principalmente para despejar uma instância de modelo nos dados json:

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

Ótimo trabalho! Sugerir a adição escolhas apoiar ... hasattr elif (campo, 'escolhas'): Árvore [field.name] = dict (field.choices) .get (valor, valor)
Oden

5

Em vez de editar todos os modelos, recomendo escrever uma tag de modelo que retorne todos os campos de qualquer modelo fornecido.
Todo objeto tem uma lista de campos ._meta.fields.
Todo objeto de campo possui um atributo nameque retornará seu nome e o método value_to_string()fornecido com seu modelo objectretornará seu valor.
O resto é tão simples como é dito na documentação do Django .

Aqui está o meu exemplo de como esse modelo de tag pode parecer:

    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

Sim, não é bonito, você terá que fazer seu próprio invólucro. Dê uma olhada no aplicativo interno databrowse , que tem toda a funcionalidade que você realmente precisa.


Eu diria ... o databrowse faz exatamente isso, embora eu ache que é um aplicativo completamente inútil.
MPEN

4

Isso pode ser considerado um hack, mas eu fiz isso antes de usar modelform_factory para transformar uma instância de modelo em um formulário.

A classe Form possui muito mais informações internas, que são super fáceis de iterar e servirão ao mesmo objetivo à custa de um pouco mais de sobrecarga. Se o tamanho do seu conjunto for relativamente pequeno, acho que o impacto no desempenho seria insignificante.

A única vantagem, além da conveniência, é que você pode facilmente transformar a tabela em um datagrid editável posteriormente.


4

Eu vim com o método a seguir, que funciona para mim, porque em todos os casos o modelo terá um ModelForm associado a ele.

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)

Aqui está um extrato do modelo que estou usando para esta exibição específica:

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

O bom desse método é que eu posso escolher, modelo por modelo, a ordem em que gostaria de exibir os rótulos dos campos, usando a tupla passada para GetModelData e especificando os nomes dos campos. Isso também permite excluir determinados campos (por exemplo, uma chave estrangeira do usuário), pois apenas os nomes dos campos passados ​​pela tupla são incorporados ao dicionário final.

Não vou aceitar isso como resposta, porque tenho certeza que alguém pode inventar algo mais "Djangonic" :-)

Atualização: estou escolhendo esta como a resposta final, porque é a mais simples dentre as que fornece o que eu preciso. Obrigado a todos que contribuíram com respostas.


3

Solução Django 1.7 para mim:

Existem variáveis ​​exatas para a pergunta, mas você definitivamente deve poder dissecar este exemplo

A chave aqui é usar praticamente .__dict__o modelo
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)

modelo :

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

no modelo, usei um filtro para acessar o campo no 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

Estou usando isso, 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

Essa abordagem mostra como usar uma classe como o ModelForm do django e uma tag de modelo como {{form.as_table}}, mas toda a tabela se parece com saída de dados, não com um formulário.

O primeiro passo foi subclassificar o widget TextInput do 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))

Subclassifiquei o ModelForm do django para trocar os widgets padrão por versões somente leitura:

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" 

Esses eram os únicos widgets que eu precisava. Mas não deve ser difícil estender essa idéia para outros widgets.


1

Apenas uma edição de @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

Deixe o Django manipular todos os outros campos que não sejam os relacionados. Eu sinto que é mais estável



0

Acabei de testar algo assim no shell e parece fazer o trabalho:

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

Observe que se você deseja representação str () para objetos estranhos, deve defini-la no método str . A partir disso, você tem um ditado de valores para o objeto. Então você pode renderizar algum tipo de modelo ou o que for.


0

Django> = 2.0

Adicione get_fields()ao seu 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]

Em seguida, chame-o como object.get_fieldsno seu 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
Olá e bem-vindo ao SO. Por favor, não poste apenas respostas. Além disso, esta pergunta já possui uma resposta aceita, sua formatação do código não está correta, você está usando atributos html obsoletos e o mais importante: Você não está explicando como o seu código fornece uma solução melhor que a aceita.
Frieder 14/02
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.