2010-06-23 31 views
124

He definido una clase User que (en última instancia) hereda de models.Model. Quiero obtener una lista de todos los campos definidos para este modelo. Por ejemplo, phone_number = CharField(max_length=20). Básicamente, quiero recuperar todo lo que herede de la clase Field.Django: ¿Obtener lista de campos modelo?

Pensé que sería capaz de recuperar estos aprovechando inspect.getmembers(model), pero la lista que devuelve no contiene ninguno de estos campos. Parece que Django ya se ha hecho con la clase y ha agregado todos sus atributos mágicos y ha eliminado lo que realmente se ha definido. Entonces ... ¿cómo puedo obtener estos campos? Probablemente tienen una función para recuperarlos para sus propios fines internos?

+0

Esto podría ayudar , también https://pypi.python.org/pypi/django-inspect-mo del/0.5 – Paolo

+0

posible duplicado de [Obtener los campos del modelo en Django] (http://stackoverflow.com/questions/3647805/get-models-fields-in-django) – markpasc

Respuesta

216

Para las versiones de Django 1.8 y posteriores:

El método get_all_field_names() es deprecated starting from Django 1.8 and will be removed in 1.10.

La página de documentación vinculada anteriormente proporciona una implementación completamente compatible con versiones anteriores de get_all_field_names(), pero para la mayoría de los propósitos [f.name for f in MyModel._meta.get_fields()] debería funcionar bien.

Para las versiones de Django antes de 1,8:

model._meta.get_all_field_names() 

Que debe hacer el truco.

Eso requiere una instancia de modelo real. Si todo lo que tienes es una subclase de django.db.models.Model, a continuación, usted debe llamar myproject.myapp.models.MyModel._meta.get_all_field_names()

+9

También buscó los objetos, no solo sus nombres. Esto parece estar disponible en 'model._meta.fields' sin embargo, y sus nombres son recuperables con' field.name' parece. Solo espero que esta sea la forma más estable de recuperar esta información :) – mpen

+2

no del todo seguro. El guión bajo parece indicar que es una API interna, sería estupendo si los chicos de Django promocionaran esto hasta una llamada a un método realmente público en 'django.db.models.Model'. Voy a profundizar en él y ver lo que puedo encontrar – rossipedia

+2

Supongo que hacerlo a través del atributo '_meta' es la única manera ... Además, busque' _meta.many_to_many' para muchos campos ManyToMany! –

47

Encuentro añadir esto a django modelos muy útiles:

def __iter__(self): 
    for field_name in self._meta.get_all_field_names(): 
     value = getattr(self, field_name, None) 
     yield (field_name, value) 

Esto le permite hacer:

for field, val in object: 
    print field, val 
+2

¿Qué pasa con ForeignKey? Tengo errores como este 'django.db.models.fields.related.RelatedObjectDoesNotExist: CustomModel no tiene custom_attribute' – SAKrisT

+0

' ForeignKey' funciona bien para mí. Aunque, capturar silenciosamente todas las excepciones es un antipatrón. Mucho mejor para atrapar 'AttributeError', o al menos registrar que alguna excepción fue silenciada silenciosamente. – Sardathrion

6

Esto hace el truco. Solo lo pruebo en Django 1.7.

your_fields = YourModel._meta.local_fields 
your_field_names = [f.name for f in your_fields] 

Model._meta.local_fields no contiene muchos-a-muchos campos. Debería obtenerlos usando Model._meta.local_many_to_many.

42

El método get_all_related_fields() mencionado en este documento ha sido deprecated in 1.8. A partir de ahora es get_fields().

>> from django.contrib.auth.models import User 
>> User._meta.get_fields() 
+0

Esta debería ser la respuesta aceptada. Terse, y al grano. –

+0

Sí, esta es la respuesta. – neuronet

4

MyModel._meta.get_all_field_names() era desuso varias versiones atrás y retira en Django 1,10.

Aquí está la sugerencia compatible hacia atrás from the docs:

from itertools import chain 

list(set(chain.from_iterable(
    (field.name, field.attname) if hasattr(field, 'attname') else (field.name,) 
    for field in MyModel._meta.get_fields() 
    # For complete backwards compatibility, you may want to exclude 
    # GenericForeignKey from the results. 
    if not (field.many_to_one and field.related_model is None) 
))) 
1

Sólo para añadir, estoy usando objeto mismo, esto funcionó para mí:

[f.name for f in self.model._meta.get_fields()] 
2

No está claro si tiene una instancia de la clase o la clase en sí y tratando de recuperar los campos, pero de cualquier manera, considere el siguiente código

Usando un en postura

instance = User.objects.get(username="foo") 
instance.__dict__ # returns a dictionary with all fields and their values 
instance.__dict__.keys() # returns a dictionary with all fields 
list(instance.__dict__.keys()) # returns list with all fields 

Utilizar una clase

User._meta.__dict__.get("fields") # returns the fields 

# to get the field names consider looping over the fields and calling __str__() 
for field in User._meta.__dict__.get("fields"): 
    field.__str__() # e.g. 'auth.User.id' 
1

Al menos con Django 1.9.9 - la versión actualmente estoy usando -, tenga en cuenta que en realidad también .get_fields() "considera" ningún modelo extranjero como una campo, que puede ser problemático. Digamos que tienes:

class Parent(models.Model): 
    id = UUIDField(primary_key=True) 

class Child(models.Model): 
    parent = models.ForeignKey(Parent) 

ello se deduce que

>>> map(lambda field:field.name, Parent._model._meta.get_fields()) 
['id', 'child'] 

mientras que, como se muestra por @Rockallite

>>> map(lambda field:field.name, Parent._model._meta.local_fields) 
['id'] 
2
def __iter__(self): 
    field_names = [f.name for f in self._meta.fields] 
    for field_name in field_names: 
     value = getattr(self, field_name, None) 
     yield (field_name, value) 

Esto funcionó para mí en django==1.11.8

Cuestiones relacionadas