Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

Джанго версии 1.8 и позже:

Вы должны использовать get_fields():

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

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

Страница документации, ссылка на которую приведена выше, обеспечивает полностью обратно совместимую реализацию get_all_field_names(), но для большинства целей предыдущий пример должен работать просто отлично.


Джанго версии до 1.8:

model._meta.get_all_field_names()

Это должно делать свое дело.

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

Ответ 3

Я считаю, что это очень удобно для моделей 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

Ответ 4

Это трюк. Я тестирую его только в 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.

Ответ 5

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

Ответ 6

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

Ответ 7

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

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

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'

Ответ 8

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

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

Ответ 9

По крайней мере, Django 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']

Ответ 10

Поэтому, прежде чем я нашел этот пост, я успешно нашел, что это работает.

Model._meta.fields

Это работает так же, как

Model._meta.get_fields()

Я не уверен, какая разница в результатах, если таковые имеются. Я запустил этот цикл и получил тот же вывод.

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

Ответ 11

Поскольку большинство ответов устарели, я постараюсь обновить вас в Django 2.2. Здесь posts- ваше приложение (записи, блог, магазин и т.д.)

1) Из ссылки на модель: 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()

Обратите внимание, что:

all_fields=BlogPost._meta.get_fields()

Также получит некоторые отношения, которые, например, Вы не можете отобразить в представлении.
Как в моем случае:

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

а также

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

2) Из экземпляра

from posts.model import BlogPost

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

3) От родительской модели

Предположим, у нас есть Post как родительская модель, и вы хотите видеть все поля в списке, а родительские поля должны быть доступны только для чтения в режиме редактирования.

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

Ответ 12

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

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