Django: получить список полей модели?

я определил User класс, который (в конечном счете) наследует от models.Model. Я хочу получить список всех полей, определенных для этой модели. Например, phone_number = CharField(max_length=20). В принципе, я хочу получить все, что наследуется от Field класса.

Я думал, что смогу получить их, воспользовавшись inspect.getmembers(model), но он возвращает список не содержит ни одного из этих полей. Похоже, что Django уже завладел классом и добавил все его магические атрибуты и вычеркнуто то, что на самом деле было определено. Так... как я могу получить эти поля? Вероятно, у них есть функция для извлечения их для своих внутренних целей?

10 ответов


для Django версии 1.8 и более поздних версий:

на get_all_field_names() метод устаревший начиная с Django 1.8 и будет удален в 1.10.

страница документации, связанная выше, обеспечивает полностью обратно совместимую реализацию get_all_field_names(), но для большинства целей [f.name for f in MyModel._meta.get_fields()] должно работать нормально.

для версий Django до 1.8:

model._meta.get_all_field_names()

это должно сделать трюк.

для этого требуется фактическая модель пример. Если у вас есть подкласс django.db.models.Model, тогда вы должны позвонить myproject.myapp.models.MyModel._meta.get_all_field_names()


на get_all_related_fields() метод, упомянутый здесь, был осуждается в 1.8. Отныне это get_fields().

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

Я считаю, что добавление этого в модели django довольно полезно:

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

Это позволяет делать:

for field, val in object:
    print field, val

Это делает трюк. Я тестирую его только в Django 1.7.

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

Model._meta.local_fields Не содержит полей "многие ко многим". Вы должны получить их с помощью 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)

это сработало для меня в django==1.11.8


MyModel._meta.get_all_field_names() был устаревший несколько версий назад и удалены в Django 1.10.

вот обратно совместимое предложение документы:

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

чтобы добавить, я использую self object, это сработало для меня:

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

непонятно, есть ли у вас экземпляр класса или сам класс и пытаются извлечь поля, но в любом случае, рассмотрим следующий код

использованием экземпляра

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

использование класса

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.9.9 Джанго -- версия, которую я сейчас использую --, обратите внимание, что .get_fields() фактически также "рассматривает" любую иностранную модель как поле, что может быть проблематичным. Скажите, что у вас есть:

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

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

следует, что

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

хотя, как показал @Rockallite

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

почему бы просто не использовать:

manage.py inspectdb

пример:

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