2010-09-05 32 views
82

Étant donné un modèle Django, j'essaie d'énumérer tous ses champs. J'ai vu quelques exemples de cela en utilisant l'attribut _meta model, mais le trait de soulignement devant meta n'indique-t-il pas que l'attribut _meta est un attribut privé et ne devrait pas être accédé directement? ... Parce que, par exemple, la mise en page de _meta pourrait changer à l'avenir et ne pas être une API stable?Obtenir les champs du modèle dans Django

Est-ce que _meta est une exception à cette règle? Est-il stable et prêt à l'emploi ou est-ce considéré comme une mauvaise pratique d'y accéder? Ou existe-t-il une fonction ou un autre moyen d'introspecter les champs d'un modèle sans utiliser l'attribut _meta? Vous trouverez ci-dessous une liste de liens illustrant comment utiliser l'attribut _meta.

Un conseil est très apprécié.

django object get/set field

http://www.djangofoo.com/80/get-list-model-fields

How to introspect django model fields?

+0

double possible de [Django: obtenir la liste des champs du modèle?] (Http: // stackoverflow .com/questions/3106295/django-get-list-of-model-fields) – Anto

Répondre

113

_meta est privé, mais il est relativement stable. Il y a des efforts pour le formaliser, le documenter et enlever le trait de soulignement, ce qui pourrait arriver avant 1.3 ou 1.4. J'imagine qu'un effort sera fait pour que les choses soient rétrocompatibles, parce que beaucoup de gens l'utilisent de toute façon.

Si vous êtes particulièrement préoccupé par la compatibilité, écrivez une fonction qui prend un modèle et renvoie les champs. Cela signifie que si quelque chose change dans le futur, il suffit de changer une fonction.

def get_model_fields(model): 
    return model._meta.fields 

Je crois que cela renvoie une liste de Field objets. Pour obtenir la valeur de chaque champ de l'instance, utilisez getattr(instance, field.name).

Mise à jour: Les contributeurs de Django travaillent sur une API pour remplacer l'objet _Meta dans le cadre d'un Google Summer of Code. Voir:
- https://groups.google.com/forum/#!topic/django-developers/hD4roZq0wyk
- https://code.djangoproject.com/wiki/new_meta_api

+40

Vous devez également être conscient du fait que si vous avez également besoin des champs many-to-many, vous devez accéder 'model._meta. many_to_many'! –

+1

Merci Will. Bon à savoir que d'autres personnes utilisent aussi _meta. J'aime l'idée d'avoir une fonction wrapper. Lazerscience, merci aussi. Bon à savoir il y a une bonne méthode pour obtenir les champs many_to_many. Joe –

+1

def get_model_fields (self): retour self._meta.fields utilisé ceci pour retourner facilement tous les champs de modèle ... Merci beaucoup ... – garmoncheg

8

C'est quelque chose qui se fait par Django lui-même lors de la construction d'une forme d'un modèle. Il utilise l'attribut _meta, mais comme Bernhard l'a noté, il utilise à la fois _meta.fields et _meta.many_to_many. En regardant django.forms.models.fields_for_model, voici comment vous pouvez le faire:

opts = model._meta 
for f in sorted(opts.fields + opts.many_to_many): 
    print '%s: %s' % (f.name, f) 
4

Les champs modèles contenus par _meta sont répertoriés dans plusieurs endroits sous forme de listes des objets champ respectifs. Il peut être plus facile de travailler avec eux comme un dictionnaire où les clés sont les noms de champs.

À mon avis, cela est moyen le plus irredondante et expressif pour recueillir et organiser les objets sur le terrain du modèle:

def get_model_fields(model): 
    fields = {} 
    options = model._meta 
    for field in sorted(options.concrete_fields + options.many_to_many + options.virtual_fields): 
    fields[field.name] = field 
    return fields 

(Voir This example usage en django.forms.models.fields_for_model.)

+2

Vous pourriez vouloir accompagner votre code avec une brève description de ce qu'il fait. –

+2

----- done .----- – jxqz

58

Je sais que ce post est assez vieux, mais je pris soin de dire tous ceux qui cherchent la même chose qu'il ya une API publique et officielle de le faire: get_fields() et get_field()

Utilisation:

fields = model._meta.get_fields() 
my_field = model._meta.get_field('my_field') 

https://docs.djangoproject.com/en/1.8/ref/models/meta/

+6

Ceci est en fait la bonne réponse pour une version plus récente de django. – chhantyal

+0

1.10 'get_fields()' https://docs.djangoproject.com/fr/1.10/ref/models/meta/#django.db.models.options.Options.get_fields – Risadinha

1

Que diriez-vous celui-ci.

fields = Model._meta.fields 
+1

J'imagine que l'on pourrait vouloir accéder aux propriétés de un champ. En outre, comme indiqué dans les réponses précédentes, il existe 'many_to_many' et' virtual_fields'. – Jocke

+0

@Jocke vous avez raison. Le besoin peut survenir d'accéder à un autre attribut.Réponse éditée – JDE876

2

Maintenant, il est méthode spéciale - get_fields()

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

Il accepte deux paramètres qui peuvent être utilisés pour contrôler les champs sont renvoyés:

  • include_parents

    True par défaut Inclut récursivement les champs définis sur les classes parentes. Si la valeur est False, get_fields() recherchera uniquement les champs déclarés directement sur le modèle courant. Les champs provenant de modèles qui héritent directement de modèles abstraits ou de classes de proxy sont considérés comme locaux, et non comme parent.

  • include_hidden

    Faux par défaut. Si la valeur est True, get_fields() inclura les champs qui sont utilisés pour sauvegarder la fonctionnalité d'un autre champ. Cela comprendra également tous les champs qui ont un related_name (comme ManyToManyField, ou ForeignKey) qui commencent par un « + »