web-dev-qa-db-fra.com

Django: Obtenir la liste des champs modèles?

J'ai défini une classe User qui hérite (finalement) de models.Model. Je souhaite obtenir une liste de tous les champs définis pour ce modèle. Par exemple, phone_number = CharField(max_length=20). En gros, je veux récupérer tout ce qui hérite de la classe Field.

Je pensais pouvoir les récupérer en tirant parti de inspect.getmembers(model), mais la liste renvoyée ne contient aucun de ces champs. Il semble que Django ait déjà saisi la classe, ajouté tous ses attributs magiques et supprimé ce qui a été défini. Alors ... comment puis-je obtenir ces champs? Ils ont probablement une fonction pour les récupérer pour leurs propres besoins internes?

163
mpen

Comme la plupart des réponses sont obsolètes, je vais essayer de vous mettre à jour sur Django 2.2 . Ici, vous publiez votre application (publications, blog, boutique, etc.)

1) Du modèle lien: https://docs.djangoproject.com/en/2.2/ref/models/meta/ =

from posts.model import BlogPost

all_fields = BlogPost._meta.fields
#or
all_fields = BlogPost._meta.get_fields()

Notez que:

all_fields=BlogPost._meta.get_fields()

Va aussi avoir des relations qui, par ex. vous ne pouvez pas afficher dans une vue.
Comme dans mon cas:

Organisation._meta.fields
(<Django.db.models.fields.AutoField: id>, <Django.db.models.fields.DateField: created>...

et

Organisation._meta.get_fields()
(<ManyToOneRel: crm.activity>, <Django.db.models.fields.AutoField: id>, <Django.db.models.fields.DateField: created>...

2) À partir d'instance

from posts.model import BlogPost

bp = BlogPost()
all_fields = BlogPost._meta.fields

3) Du modèle parent

Supposons que nous ayons Post comme modèle parent et que vous souhaitiez voir tous les champs d'une liste et que les champs du parent soient en lecture seule en mode Édition.

from Django.contrib import admin
from posts.model import BlogPost 




@admin.register(BlogPost)
class BlogPost(admin.ModelAdmin):
    all_fields = [f.name for f Organisation._meta.fields]
    parent_fields = BlogPost.get_deferred_fields(BlogPost)

    list_display = all_fields
    read_only = parent_fields
9
Maks

Django versions 1.8 et ultérieures:

Vous devriez utiliser get_fields():

[f.name for f in MyModel._meta.get_fields()]

La méthode get_all_field_names() est obsolète à partir de Django 1.8 et sera supprimée dans 1.1 .

La page de documentation liée ci-dessus fournit une implémentation entièrement compatible avec la version antérieure de get_all_field_names(), mais dans la plupart des cas, l'exemple précédent devrait parfaitement fonctionner.


Les versions de Django antérieures à la 1.8:

model._meta.get_all_field_names()

Cela devrait faire l'affaire.

Cela nécessite une instance de modèle réelle. Si tout ce que vous avez est une sous-classe de Django.db.models.Model, alors vous devriez appeler myproject.myapp.models.MyModel._meta.get_all_field_names()

276
rossipedia

La méthode get_all_related_fields() mentionnée ici a été obsolète en 1.8 . A partir de maintenant c'est get_fields() .

>> from Django.contrib.auth.models import User
>> User._meta.get_fields()
71
Wil

Il est très utile d’ajouter cela à Django modèles:

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

Cela vous permet de faire:

for field, val in object:
    print field, val
53
bjw

Cela fait l'affaire. Je ne le teste que dans Django 1.7.

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

Model._meta.local_fields ne contient pas de champs plusieurs-à-plusieurs. Vous devriez les obtenir avec Model._meta.local_many_to_many.

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

Cela a fonctionné pour moi dans Django==1.11.8

10
Vivek Anand

Il n'est pas clair si vous avez une instance de la classe ou la classe elle-même et essayez de récupérer les champs, mais de toute façon, considérez le code suivant

en utilisant une instance

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

tiliser une classe

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'
7
Nader Alexan

MyModel._meta.get_all_field_names() était obsolète plusieurs versions et supprimé dans Django 1.10.

Voici la suggestion rétro-compatible de la documentation :

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

Juste pour ajouter, j'utilise l'objet personnel, cela a fonctionné pour moi:

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

Donc avant que je trouve ce post, j'ai trouvé avec succès que cela fonctionne.

Model._meta.fields

Cela fonctionne aussi bien

Model._meta.get_fields()

Je ne suis pas sûr de la différence entre les résultats, s'il en existe un. J'ai couru cette boucle et obtenu la même sortie.

for field in Model._meta.fields:
    print(field.name)
4
Carl Brubaker

Au moins avec Django 1.9.9 - la version que j'utilise actuellement -, notez que .get_fields() "considère également" tout modèle étranger comme un champ, ce qui peut poser problème. Disons que vous avez:

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

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

Il s'ensuit que

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

comme le montre @Rockallite

>>> map(lambda field:field.name, Parent._model._meta.local_fields)
['id']
4
keepAlive