Model _meta API

class Options[source]

模型_meta API是Django ORM的核心。它使系统的其他部分(如查找,查询,表单和管理员)能够了解每个模型的功能。API可通过每个模型类的_meta属性访问,该属性是django.db.models.options.Options对象的实例。

它提供的方法可以用于:

  • 检索模型的所有字段实例
  • 按名称检索模型的单个字段实例
在Django 1.8中更改:

模型_meta API始终以Django内部形式存在,但未正式记录和支持。作为使此API公开的努力的一部分,一些已经存在的API入口点略有改变。已提供migration guide来帮助将您的代码转换为使用新的官方API。

Field access API

Retrieving a single field instance of a model by name

Options.get_field(field_name)[source]

返回给定字段名称的字段实例。

field_name可以是模型上的字段名称,抽象或继承模型上的字段,或在指向模型的另一个模型上定义的字段。在后一种情况下,field_name将是由用户定义的related_name或由Django本身自动生成的名称。

Hidden fields

如果找不到具有给定名称的字段,则会引发FieldDoesNotExist异常。

>>> from django.contrib.auth.models import User

# A field on the model
>>> User._meta.get_field('username')
<django.db.models.fields.CharField: username>

# A field from another model that has a relation with the current model
>>> User._meta.get_field('logentry')
<ManyToOneRel: admin.logentry>

# A non existent field
>>> User._meta.get_field('does_not_exist')
Traceback (most recent call last):
    ...
FieldDoesNotExist: User has no field named 'does_not_exist'

自从1.8版起已弃用: Options.get_field()先前接受了可以设置为Falsemany_to_many参数避免搜索ManyToManyField。旧的行为已保留向后兼容性;但是,参数和此行为已被弃用。

如果您希望过滤出ManyToManyField,您可以在调用get_field()之后检查Field.many_to_many属性。

Retrieving all field instances of a model

Options.get_fields(include_parents=True, include_hidden=False)[source]
Django 1.8中的新功能。

返回与模型关联的字段的元组。get_fields()接受两个参数,可用于控制返回的字段:

include_parents
True递归地包括在父类上定义的字段。如果设置为Falseget_fields()将只搜索在当前模型上直接声明的字段。来自直接从抽象模型或代理类继承的模型的字段被认为是本地的,而不是父级的。
include_hidden
False如果设置为True,则get_fields()将包含用于返回其他字段功能的字段。这还将包括具有以“+”开头的related_name(例如ManyToManyFieldForeignKey)的任何字段。
>>> from django.contrib.auth.models import User
>>> User._meta.get_fields()
(<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>)

# Also include hidden fields.
>>> User._meta.get_fields(include_hidden=True)
(<ManyToOneRel: auth.user_groups>,
 <ManyToOneRel: auth.user_user_permissions>,
 <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>)

Migrating from the old API

作为Model._meta API(从django.db.models.options.Options类)的形式化的一部分,已经弃用了一些方法和属性,将在Django 2.0中删除。

这些旧的API可以复制:

虽然可以对旧方法进行严格等同的替换,但这可能不是最好的方法。花费时间重构任何字段循环以更好地使用新的API - 并且可能包括先前被排除的字段 - 几乎肯定会导致更好的代码。

假设您有一个名为MyModel的模型,可以进行以下替换,将代码转换为新的API:

  • MyModel._meta.get_field(name)

    f = MyModel._meta.get_field(name)
    

    然后检查:

    • f.auto_created == False,因为新的get_field()
    • f.is_relation f.related_model t0 >,因为新的get_field() API会找到GenericForeignKey关系;
  • MyModel._meta.get_field_by_name(name)

    get_field_by_name()返回四个值:(字段, 模型, direct, m2m)

    • field可以通过MyModel._meta.get_field(name)

    • model可以通过字段上的model属性找到。

    • direct可以通过以下方式找到: field.auto_created field.concrete

      auto_created检查排除由Django创建的所有“前进”和“反向”关系,但这也包括代理模型上的AutoFieldOneToOneField我们避免使用concrete属性过滤这些属性。

    • m2m可以通过字段上的many_to_many属性找到。

  • MyModel._meta.get_fields_with_model()

    [
        (f, f.model if f.model != MyModel else None)
        for f in MyModel._meta.get_fields()
        if not f.is_relation
            or f.one_to_one
            or (f.many_to_one and f.related_model)
    ]
    
  • MyModel._meta.get_concrete_fields_with_model()

    [
        (f, f.model if f.model != MyModel else None)
        for f in MyModel._meta.get_fields()
        if f.concrete and (
            not f.is_relation
            or f.one_to_one
            or (f.many_to_one and f.related_model)
        )
    ]
    
  • MyModel._meta.get_m2m_with_model()

    [
        (f, f.model if f.model != MyModel else None)
        for f in MyModel._meta.get_fields()
        if f.many_to_many and not f.auto_created
    ]
    
  • MyModel._meta.get_all_related_objects()

    [
        f for f in MyModel._meta.get_fields()
        if (f.one_to_many or f.one_to_one) and f.auto_created
    ]
    
  • MyModel._meta.get_all_related_objects_with_model()

    [
        (f, f.model if f.model != MyModel else None)
        for f in MyModel._meta.get_fields()
        if (f.one_to_many or f.one_to_one) and f.auto_created
    ]
    
  • MyModel._meta.get_all_related_many_to_many_objects()

    [
        f for f in MyModel._meta.get_fields(include_hidden=True)
        if f.many_to_many and f.auto_created
    ]
    
  • MyModel._meta.get_all_related_m2m_objects_with_model()

    [
        (f, f.model if f.model != MyModel else None)
        for f in MyModel._meta.get_fields(include_hidden=True)
        if f.many_to_many and f.auto_created
    ]
    
  • MyModel._meta.get_all_field_names()

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

    这提供了100%向后兼容的替换,确保包括字段名称和属性名称ForeignKey,但与GenericForeignKey相关联的字段不包括。一个更简单的版本是:

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

    虽然这不是100%向后兼容,但在许多情况下可能就足够了。