Django:モデルフィールドのリストを取得しますか?


196

User(最終的に)から継承するクラスを定義しましたmodels.Model。このモデルに定義されているすべてのフィールドのリストを取得したい。たとえば、phone_number = CharField(max_length=20)。基本的には、Fieldクラスから継承するものをすべて取得したいと思います。

を利用してこれらを取得できると思いましたinspect.getmembers(model)が、返されるリストにはこれらのフィールドが含まれていません。Djangoはすでにクラスを取得していて、そのすべての魔法の属性を追加して、実際に定義されているものを取り除いているようです。だから...これらのフィールドを取得するにはどうすればよいですか?彼らはおそらく彼ら自身の内部目的のためにそれらを検索する機能を持っていますか?


これも役立つかもしれませんpypi.python.org/pypi/django-inspect-model/0.5
Paolo

回答:


46

ほとんどの回答が古くなっているので、私はDjango 2.2 であなたを更新しようとしますここの投稿-アプリ(投稿、ブログ、ショップなど)

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 = bp._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

1
私はこれが正しいと仮定し、それを新しい答えとして受け入れます。更新していただきありがとうございます!
mpen

@mpen Wontは、それを最善の方法または最もpythonicであると主張していますが、以下では、uがビューに表示する値を取得する/する必要があります。get_fields()がタプルを返すと、uはそれを反復してappname.Model.field_nameのような値を取得できます。以下では、2番目のドットから値をクリーンアップします。フィールド名にアンダースコアが使用された場合も含まれます。タイトルにするだけでなく、状況ごとに必要に応じて変更してください。 clean_field_names = [str(h).split('.')[2].replace("_", " ").title() for h in all_fields]
アレハンドロスアレス

1
インスタンスの例からする必要があります:all_fields = bp._meta.fields
ジョージのKettleborough

@GeorgeKettleboroughポイントがわかります。クラスから直接動作しませんか?テストする例はありません。それは.__ class__ BPから、あるいは少なくとも塩基対でなければなりませんので、とにかく一例では、インスタンスについてです
MAKS

294

Djangoバージョン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より前のDjangoバージョン:

model._meta.get_all_field_names()

これでうまくいくはずです。

これには実際のモデルインスタンスが必要です。あなたが持っているすべてがのサブクラスであるdjango.db.models.Modelなら、あなたは呼び出す必要がありますmyproject.myapp.models.MyModel._meta.get_all_field_names()


11
名前だけでなく、オブジェクトも必要でした。これは利用できるようですmodel._meta.fieldsが、それらの名前はfield.nameそれで取得できます。これがこの情報を取得する最も安定した方法であることを願っています:)
mpen

2
よくわからない アンダースコアは、それが内部APIであることを示しているようです。Djangoの連中がこれを実際のパブリックメソッドの呼び出しに昇格させた場合は、すばらしいでしょうdjango.db.models.Model。私はそれを掘り下げて、私が見つけることができるものを見ます
rossipedia

2
_meta属性を介してそれを行うことが唯一の方法だ_meta.many_to_manyと思います...さらに、ManyToManyフィールドを調べてください!
Bernhard Vallant 2010年

3
これは良い解決策ですが、この方法には、Reverse ForeignKeyなどの逆関係フィールドが含まれており、これらは厳密には「フィールド」ではありません。誰でも実際のフィールドを区別する方法を知っていますか?
ビリディス2013年

2
@rossipedia:(それは、この答えが最初に書き込まれたとき、おそらく、プライベートにするために使用が)だけでは._meta APIが公開されていることに注意:docs.djangoproject.com/en/1.8/ref/models/meta/...
ニック・S


55

これを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

2
ForeignKeyはどうですか?私はこのようなエラーがありますdjango.db.models.fields.related.RelatedObjectDoesNotExist: CustomModel has no custom_attribute.
SAKrisT 2014年

ForeignKey私にとってはうまくいきます。ただし、すべての例外を静かにキャッチすることはアンチパターンです。キャッチAttributeErrorするか、少なくともいくつかの例外が黙って飲み込まれたことを記録する方がはるかに良い。
サルダトリオン-SEの乱用に対して2015年

1
self._meta.get_all_field_names()減価償却され削除されました。あなたは、のようなものを使用することができfor field in self._meta.get_fields()、その後とyield (field.name, field.value_from_object(self))
MackM

13

これでうまくいきます。私は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


10

クラスのインスタンスまたはクラス自体があり、フィールドを取得しようとしているのかどうかは明らかではありませんが、どちらの方法でも、次のコードを検討してください

インスタンスを使用する

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'

10
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


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

6

追加するために、私は自己オブジェクトを使用しています、これは私のために働きました:

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

5

少なくとも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']

4

したがって、この投稿を見つける前に、これが機能することを確認しました。

Model._meta.fields

それは同じように機能します

Model._meta.get_fields()

結果に違いがあるかどうかはわかりません。私はこのループを実行し、同じ出力を得ました。

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

-2

なぜそれを使わないのですか?

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

1
これは質問に対する答えではありません。
Shayne
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.