Отримати поля моделі в Django


121

Враховуючи модель Джанго, я намагаюся перерахувати всі її поля. Я бачив кілька прикладів цього за допомогою атрибута _meta model, але чи не підкреслення перед мета вказує на те, що атрибут _meta є приватним атрибутом і до нього не можна звертатися безпосередньо? ... Тому що, наприклад, макет _meta може змінитися в майбутньому і не бути стабільним API?

Чи _meta є винятком із цього правила? Це стабільний і готовий до використання або вважається поганою практикою доступу до нього? Або є функція чи інший спосіб ввести в поле поля моделі без використання атрибута _meta? Нижче наведено список деяких посилань, що показують, як це зробити за допомогою атрибута _meta

Будь-яка порада дуже цінується.

поле отримання / встановлення об'єкта django

http://www.djangofoo.com/80/get-list-model-fields

Як представити поля моделі джанго?


Відповіді:


144

_metaє приватним, але він відносно стабільний. Існують зусилля щодо її формалізації, документування та усунення підкреслення, що може статися до 1.3 або 1.4. Я думаю, що будуть докладені зусилля для того, щоб речі були сумісними назад, тому що багато людей користуються цим.

Якщо вас особливо турбує сумісність, напишіть функцію, яка бере модель та повертає поля. Це означає, що якщо в майбутньому щось зміниться, вам доведеться змінити лише одну функцію.

def get_model_fields(model):
    return model._meta.fields

Я вірю, що це поверне список Fieldоб’єктів. Щоб отримати значення кожного поля з екземпляра, використовуйте getattr(instance, field.name).

Оновлення: Дописувачі Django працюють над API, щоб замінити об’єкт _Meta в рамках Google Summer Code. Дивіться:
- https://groups.google.com/forum/#!topic/django-developers/hD4roZq0wyk
- https://code.djangoproject.com/wiki/new_meta_api


45
Ви також повинні бути обізнані з його фактом, що якщо вам також потрібні багато-багато полів, вам потрібно отримати доступ model._meta.many_to_many!
Бернхард Валлант

1
Дякую, Уілл. Добре знати, що інші люди також використовують _meta. Мені подобається ідея мати функцію обгортки. Лазерна наука, також дякую. Приємно знати, що є приємний метод отримати поля many_to_many. Joe
Jo J

3
django/core/management/commands/loaddata.pyвикористовує _meta для переходу по дереву програм, моделей та полів. Гарний зразок для наслідування ... і ви можете поставити під сумнів, що це "офіційний шлях".
варильні панелі

2
Якщо ви використовуєте загальні закордонні ключі, слід також перевірити_meta.virtual_fields
andrei1089


97

Я знаю , що цей пост досить старий, але я просто дбав сказати всім , хто шукає те ж саме , що є суспільний і офіційний API , щоб зробити це: get_fields()іget_field()

Використання:

fields = model._meta.get_fields()
my_field = model._meta.get_field('my_field')

https://docs.djangoproject.com/en/1.8/ref/models/meta/


6
Це насправді правильна відповідь для нової версії джанго.
chhantyal


3
Одне питання: якщо вони є "державними та офіційними", чому вони все ще знаходяться _meta?
крубо

9

Зараз існує спеціальний метод - get_fields ()

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

Він приймає два параметри, за допомогою яких можна керувати, які поля повертаються:

  • include_parents

    Істинно за замовчуванням. Рекурсивно включає поля, визначені на батьківських класах. Якщо встановлено значення False, get_fields () буде шукати лише поля, оголошені безпосередньо в поточній моделі. Поля з моделей, які безпосередньо успадковуються від абстрактних моделей або проксі-класів, вважаються локальними, а не батьківськими.

  • include_hidden

    Помилка за замовчуванням. Якщо встановлено значення True, get_fields () буде містити поля, які використовуються для підтримки функціональності іншого поля. Сюди також включатимуться будь-які поля, які мають пов’язане ім’я (наприклад, ManyToManyField або ForeignKey), яке починається з "+"


9

get_fields()повертає a tupleі кожен елемент - це Model fieldтип, який не може бути використаний безпосередньо як рядок. Отже, field.nameповерне ім'я поля

my_model_fields = [field.name for field in MyModel._meta.get_fields()]
Вищевказаний код поверне список, який поєднує всі назви полів

Приклад

In [11]: from django.contrib.auth.models import User

In [12]: User._meta.get_fields()
Out[12]: 
(<ManyToOneRel: admin.logentry>,
 <django.db.models.fields.AutoField: id>,
 <django.db.models.fields.CharField: password>,
 <django.db.models.fields.DateTimeField: last_login>,
 <django.db.models.fields.BooleanField: is_superuser>,
 <django.db.models.fields.CharField: username>,
 <django.db.models.fields.CharField: first_name>,
 <django.db.models.fields.CharField: last_name>,
 <django.db.models.fields.EmailField: email>,
 <django.db.models.fields.BooleanField: is_staff>,
 <django.db.models.fields.BooleanField: is_active>,
 <django.db.models.fields.DateTimeField: date_joined>,
 <django.db.models.fields.related.ManyToManyField: groups>,
 <django.db.models.fields.related.ManyToManyField: user_permissions>)

In [13]: [field.name for field in User._meta.get_fields()]
Out[13]: 
['logentry',
 'id',
 'password',
 'last_login',
 'is_superuser',
 'username',
 'first_name',
 'last_name',
 'email',
 'is_staff',
 'is_active',
 'date_joined',
 'groups',
 'user_permissions']

Чудова відповідь! Дякую!
Tms91

8

Це те, що робиться самим Джанго, будуючи форму з моделі. Він використовує атрибут _meta, але, як зазначив Бернхард, він використовує і _meta.fields, і _meta.many_to_many. Дивлячись на django.forms.models.fields_for_model, ось як це можна зробити:

opts = model._meta
for f in sorted(opts.fields + opts.many_to_many):
    print '%s: %s' % (f.name, f)

4

Поля моделі, що містяться _meta, перераховані в декількох місцях як списки відповідних об'єктів поля. Працювати з ними може бути простіше, як зі словником, де клавішами є назви полів.

На мою думку, це найбільш непомірний та виразний спосіб збирання та впорядкування модельних об'єктів поля:

def get_model_fields(model):
  fields = {}
  options = model._meta
  for field in sorted(options.concrete_fields + options.many_to_many + options.virtual_fields):
    fields[field.name] = field
  return fields

(Дивіться цей приклад використання в django.forms.models.fields_for_model.)


2
Ви можете супроводжувати свій код коротким описом того, що він робить.
Bas van Dijk

2

Як щодо цього.

fields = Model._meta.fields

1
Я думаю, що можна отримати доступ до властивостей поля. Також, як вказувалося в попередніх відповідях, є many_to_manyі virtual_fields.
Jocke

@Jocke правий ти. Може виникнути потреба у доступі до іншого атрибуту. Відповідь відредаговано.
JDE876

2

Відповідно до документації на django 2.2 ви можете використовувати:

Щоб отримати всі поля: Model._meta.get_fields()

Щоб отримати індивідуальне поле: Model._meta.get_field('field name')

колишній Session._meta.get_field('expire_date')


1

Якщо вам це потрібно для вашого веб-сайту адміністратора , існує також ModelAdmin.get_fieldsметод ( docs ), який повертає a listім'я поля strings.

Наприклад:

class MyModelAdmin(admin.ModelAdmin):
    # extending change_view, just as an example
    def change_view(self, request, object_id=None, form_url='', extra_context=None):
        # get the model field names
        field_names = self.get_fields(request)
        # use the field names
        ...

0

Інший спосіб - додавати функції до моделі, і коли ви хочете змінити дату, ви можете викликати функцію.

class MyModel(models.Model):
    name = models.CharField(max_length=256)
    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

    def set_created_date(self, created_date):
        field = self._meta.get_field('created')
        field.auto_now_add = False
        self.created = created_date

    def set_modified_date(self, modified_date):
        field = self._meta.get_field('modified')
        field.auto_now = False
        self.modified = modified_date

my_model = MyModel(name='test')
my_model.set_modified_date(new_date)
my_model.set_created_date(new_date)
my_model.save()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.