Djangoでモデルのフィールドを取得する


121

Djangoモデルを前提として、そのすべてのフィールドをリストしようとしています。_metaモデル属性を使用してこれを行う例をいくつか見ましたが、メタの前にある下線は、_meta属性がプライベート属性であり、直接アクセスしてはならないことを示していませんか?...たとえば、_metaのレイアウトが将来変更され、安定したAPIにならない可能性があるためですか?

_metaはこのルールの例外ですか?それは安定していてすぐに使用できますか、それともアクセスするのは悪い習慣と考えられていますか?または、_meta属性を使用せずにモデルのフィールドをイントロスペクトする関数または他の方法がありますか?以下は、_meta属性を使用してこれを行う方法を示すいくつかのリンクのリストです

アドバイスは大歓迎です。

djangoオブジェクトの取得/設定フィールド

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

djangoモデルフィールドをイントロスペクトするにはどうすればよいですか?


回答:


144

_meta非公開ですが、比較的安定しています。これを形式化し、文書化し、アンダースコアを削除する努力があります。これは1.3または1.4より前に発生する可能性があります。とにかく多くの人が使っているので、後方互換性を確保するための努力がなされると思います。

特に互換性が気になる場合は、モデルを取得してフィールドを返す関数を記述します。つまり、将来何かが変わっても、1つの機能を変更するだけで済みます。

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

これはFieldオブジェクトのリストを返すと思います。インスタンスから各フィールドの値を取得するには、を使用しますgetattr(instance, field.name)

更新:Djangoの寄稿者は、Google Summer of Codeの一部として_Metaオブジェクトを置き換えるAPIに取り組んでいます。参照:-https : //groups.google.com/forum/#!topic / django
- developers
/ hD4roZq0wyk - https : //code.djangoproject.com/wiki/new_meta_api


45
また、多対多のフィールドも必要な場合は、アクセスする必要があることを知っておく必要がありますmodel._meta.many_to_many
Bernhard Vallant

1
ウィルありがとう。他の人も_metaを使用していることを知っておくと便利です。ラッパー関数を持つというアイデアが好きです。Lazerscience、ありがとうございます。many_to_manyフィールドを取得する素晴らしい方法があることを知っておくと良いでしょう。ジョー
ジョーJ

3
django/core/management/commands/loaddata.pyアプリ、モデル、フィールドのツリーをウォークするために_metaを使用します。従うのに最適なパターン...そして、それは「公式な方法」だと思うでしょう。
ホブ、

2
汎用外部キーを使用している場合は、次も確認する必要があります_meta.virtual_fields
andrei1089

7
_meta正式なサポート対象API(Django 1.8の新機能)になりました
mgalgs

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
これは実際には新しいバージョンのdjangoに対する正しい答えです。
チャンティアル2015


3
1つの質問:これらが「公的かつ公的」である場合、なぜ彼らはまだ下にあるの_metaですか?
krubo

9

今特別なメソッドがあります-get_fields()

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

返されるフィールドを制御するために使用できる2つのパラメーターを受け入れます。

  • include_parents

    デフォルトではTrue。親クラスで定義されたフィールドを再帰的に含めます。Falseに設定すると、get_fields()は現在のモデルで直接宣言されたフィールドのみを検索します。抽象モデルまたはプロキシクラスから直接継承するモデルのフィールドは、親ではなくローカルと見なされます。

  • include_hidden

    デフォルトではfalse。Trueに設定すると、get_fields()には、他のフィールドの機能をサポートするために使用されるフィールドが含まれます。これには、「+」で始まるrelated_name(ManyToManyField、ForeignKeyなど)を持つフィールドも含まれます


9

get_fields()を返し、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

これは、モデルからフォームを構築するときにDjango自体によって行われるものです。_meta属性を使用していますが、Bernhardが指摘したように、_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 2016

@Jockeそうです。別の属性にアクセスする必要が生じる場合があります。回答を編集しました。
JDE876 2016

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)もあります。liststrings

例えば:

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

もう1つの方法は、モデルに関数を追加することです。日付をオーバーライドする場合は、関数を呼び出すことができます。

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()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.