Django: Obtenez la liste des champs de modèle?

J’ai défini une classe User qui (finalement) hérite des models.Model . Je veux 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 qu’elle renvoie ne contient aucun de ces champs. Il semblerait que Django ait déjà saisi la classe et ajouté tous ses atsortingbuts magiques pour éliminer ce qui a été défini. Alors, comment puis-je obtenir ces champs? Ils ont probablement une fonction pour les récupérer à leurs propres fins internes?

Pour les versions 1.8 et ultérieures de Django:

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

La page de documentation liée ci-dessus fournit une implémentation entièrement rétro-compatible de get_all_field_names() , mais dans la plupart des cas [f.name for f in MyModel._meta.get_fields()] devrait fonctionner [f.name for f in MyModel._meta.get_fields()] .

Pour les versions de Django antérieures à 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()

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

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

Je trouve que l’ajout de ceci aux modèles de django est très utile:

 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 

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 en utilisant Model._meta.local_many_to_many .

 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

MyModel._meta.get_all_field_names() été déprécié à plusieurs resockets et supprimé dans Django 1.10.

Voici la suggestion rétrocompatible des documents :

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

Juste pour append, je me sers d’objects personnels, cela a fonctionné pour moi:

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

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

Utiliser 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 

En utilisant 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__() # eg 'auth.User.id' 

Au moins avec Django 1.9.9 – la version que j’utilise actuellement -, notez que .get_fields() considère également que tout modèle étranger est 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 en résulte que

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

tandis que, comme montré par @Rockallite

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

Pourquoi ne pas simplement utiliser cela:

 manage.py inspectdb 

Exemple de sortie:

 class GuardianUserobjectpermission(models.Model): id = models.IntegerField(primary_key=True) # AutoField? object_pk = models.CharField(max_length=255) content_type = models.ForeignKey(DjangoContentType, models.DO_NOTHING) permission = models.ForeignKey(AuthPermission, models.DO_NOTHING) user = models.ForeignKey(CustomUsers, models.DO_NOTHING) class Meta: managed = False db_table = 'guardian_userobjectpermission' unique_together = (('user', 'permission', 'object_pk'),)