123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- ===================
- Model ``_meta`` API
- ===================
- .. module:: django.db.models.options
- :synopsis: Model meta-class layer
- .. class:: Options
- The model ``_meta`` API is at the core of the Django ORM. It enables other
- parts of the system such as lookups, queries, forms, and the admin to
- understand the capabilities of each model. The API is accessible through
- the ``_meta`` attribute of each model class, which is an instance of an
- ``django.db.models.options.Options`` object.
- Methods that it provides can be used to:
- * Retrieve all field instances of a model
- * Retrieve a single field instance of a model by name
- .. _model-meta-field-api:
- Field access API
- ================
- Retrieving a single field instance of a model by name
- -----------------------------------------------------
- .. method:: Options.get_field(field_name)
- Returns the field instance given a name of a field.
- ``field_name`` can be the name of a field on the model, a field
- on an abstract or inherited model, or a field defined on another
- model that points to the model. In the latter case, the ``field_name``
- will be the ``related_name`` defined by the user or the name automatically
- generated by Django itself.
- :attr:`Hidden fields <django.db.models.Field.hidden>` cannot be retrieved
- by name.
- If a field with the given name is not found a
- :class:`~django.core.exceptions.FieldDoesNotExist` exception will be
- raised.
- .. code-block:: python
- >>> 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'
- Retrieving all field instances of a model
- -----------------------------------------
- .. method:: Options.get_fields(include_parents=True, include_hidden=False)
- Returns a tuple of fields associated with a model. ``get_fields()`` accepts
- two parameters that can be used to control which fields are returned:
- ``include_parents``
- ``True`` by default. Recursively includes fields defined on parent
- classes. If set to ``False``, ``get_fields()`` will only search for
- fields declared directly on the current model. Fields from models that
- directly inherit from abstract models or proxy classes are considered
- to be local, not on the parent.
- ``include_hidden``
- ``False`` by default. If set to ``True``, ``get_fields()`` will include
- fields that are used to back other field's functionality. This will
- also include any fields that have a ``related_name`` (such
- as :class:`~django.db.models.ManyToManyField`, or
- :class:`~django.db.models.ForeignKey`) that start with a "+".
- .. code-block:: python
- >>> 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-old-meta-api:
- Migrating from the old API
- ==========================
- As part of the formalization of the ``Model._meta`` API (from the
- :class:`django.db.models.options.Options` class), a number of methods and
- properties have been deprecated and will be removed in Django 1.10.
- These old APIs can be replicated by either:
- * invoking :meth:`Options.get_field()
- <django.db.models.options.Options.get_field()>`, or;
- * invoking :meth:`Options.get_fields()
- <django.db.models.options.Options.get_fields()>` to retrieve a list of all
- fields, and then filtering this list using the :ref:`field attributes
- <model-field-attributes>` that describe (or retrieve, in the case of
- ``_with_model`` variants) the properties of the desired fields.
- Although it's possible to make strictly equivalent replacements of the old
- methods, that might not be the best approach. Taking the time to refactor any
- field loops to make better use of the new API - and possibly include fields
- that were previously excluded - will almost certainly result in better code.
- Assuming you have a model named ``MyModel``, the following substitutions
- can be made to convert your code to the new API:
- * ``MyModel._meta.get_field(name)`` becomes::
- f = MyModel._meta.get_field(name)
- then check if:
- - ``f.auto_created == False``, because the new ``get_field()``
- API will find "reverse" relations, and:
- - ``f.is_relation and f.related_model is None``, because the new
- ``get_field()`` API will find
- :class:`~django.contrib.contenttypes.fields.GenericForeignKey` relations.
- * ``MyModel._meta.get_field_by_name(name)`` returns a tuple of these four
- values with the following replacements:
- - ``field`` can be found by ``MyModel._meta.get_field(name)``
- - ``model`` can be found through the
- :attr:`~django.db.models.Field.model` attribute on the field.
- - ``direct`` can be found by: ``not field.auto_created or field.concrete``
- The :attr:`~django.db.models.Field.auto_created` check excludes
- all "forward" and "reverse" relations that are created by Django, but
- this also includes ``AutoField`` and ``OneToOneField`` on proxy models.
- We avoid filtering out these attributes using the
- :attr:`concrete <django.db.models.Field.concrete>` attribute.
- - ``m2m`` can be found through the
- :attr:`~django.db.models.Field.many_to_many` attribute on the field.
- * ``MyModel._meta.get_fields_with_model()`` becomes::
- [
- (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()`` becomes::
- [
- (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()`` becomes::
- [
- (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()`` becomes::
- [
- 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()`` becomes::
- [
- (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()`` becomes::
- [
- 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()`` becomes::
- [
- (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()`` becomes::
- 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)
- )))
- This provides a 100% backwards compatible replacement, ensuring that both
- field names and attribute names ``ForeignKey``\s are included, but fields
- associated with ``GenericForeignKey``\s are not. A simpler version would be::
- [f.name for f in MyModel._meta.get_fields()]
- While this isn't 100% backwards compatible, it may be sufficient in many
- situations.
|