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