mirror of
				https://github.com/django/django.git
				synced 2025-10-29 00:26:07 +00:00 
			
		
		
		
	Fixed #36075 -- Documented how to introspect composite primary keys.
Document _meta.pk_fields and interactions between Field.primary_key and CompositePrimaryKey. Thanks Mariusz for the review.
This commit is contained in:
		
				
					committed by
					
						 Sarah Boyce
						Sarah Boyce
					
				
			
			
				
	
			
			
			
						parent
						
							f2a1dcaa53
						
					
				
				
					commit
					e580926d74
				
			| @@ -542,18 +542,20 @@ cross-site scripting attack. | |||||||
|  |  | ||||||
| If ``True``, this field is the primary key for the model. | If ``True``, this field is the primary key for the model. | ||||||
|  |  | ||||||
| If you don't specify ``primary_key=True`` for any field in your model, Django | If you don't specify ``primary_key=True`` for any field in your model and have | ||||||
| will automatically add a field to hold the primary key, so you don't need to | not defined a composite primary key, Django will automatically add a field to | ||||||
| set ``primary_key=True`` on any of your fields unless you want to override the | hold the primary key. So, you don't need to set ``primary_key=True`` on any of | ||||||
| default primary-key behavior. The type of auto-created primary key fields can | your fields unless you want to override the default primary-key behavior. The | ||||||
| be specified per app in :attr:`AppConfig.default_auto_field | type of auto-created primary key fields can be specified per app in | ||||||
| <django.apps.AppConfig.default_auto_field>` or globally in the | :attr:`AppConfig.default_auto_field <django.apps.AppConfig.default_auto_field>` | ||||||
| :setting:`DEFAULT_AUTO_FIELD` setting. For more, see | or globally in the :setting:`DEFAULT_AUTO_FIELD` setting. For more, see | ||||||
| :ref:`automatic-primary-key-fields`. | :ref:`automatic-primary-key-fields`. | ||||||
|  |  | ||||||
| ``primary_key=True`` implies :attr:`null=False <Field.null>` and | ``primary_key=True`` implies :attr:`null=False <Field.null>` and | ||||||
| :attr:`unique=True <Field.unique>`. Only one primary key is allowed on an | :attr:`unique=True <Field.unique>`. Only one field per model can set | ||||||
| object. | ``primary_key=True``. Composite primary keys must be defined using | ||||||
|  | :class:`CompositePrimaryKey` instead of setting this flag to ``True`` for all | ||||||
|  | fields to maintain this invariant. | ||||||
|  |  | ||||||
| The primary key field is read-only. If you change the value of the primary | The primary key field is read-only. If you change the value of the primary | ||||||
| key on an existing object and then save it, a new object will be created | key on an existing object and then save it, a new object will be created | ||||||
| @@ -562,6 +564,10 @@ alongside the old one. | |||||||
| The primary key field is set to ``None`` when | The primary key field is set to ``None`` when | ||||||
| :meth:`deleting <django.db.models.Model.delete>` an object. | :meth:`deleting <django.db.models.Model.delete>` an object. | ||||||
|  |  | ||||||
|  | .. versionchanged:: 5.2 | ||||||
|  |  | ||||||
|  |     The ``CompositePrimaryKey`` field was added. | ||||||
|  |  | ||||||
| ``unique`` | ``unique`` | ||||||
| ---------- | ---------- | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,10 +13,11 @@ understand the capabilities of each model. The API is accessible through | |||||||
| the ``_meta`` attribute of each model class, which is an instance of an | the ``_meta`` attribute of each model class, which is an instance of an | ||||||
| ``django.db.models.options.Options`` object. | ``django.db.models.options.Options`` object. | ||||||
|  |  | ||||||
| Methods that it provides can be used to: | Methods and attributes that it provides can be used to: | ||||||
|  |  | ||||||
| * Retrieve all field instances of a model | * Retrieve all field instances of a model | ||||||
| * Retrieve a single field instance of a model by name | * Retrieve a single field instance of a model by name | ||||||
|  | * Retrieve all fields that compose the primary key of a model | ||||||
|  |  | ||||||
| .. _model-meta-field-api: | .. _model-meta-field-api: | ||||||
|  |  | ||||||
| @@ -118,3 +119,42 @@ Retrieving all field instances of a model | |||||||
|          <django.db.models.fields.DateTimeField: date_joined>, |          <django.db.models.fields.DateTimeField: date_joined>, | ||||||
|          <django.db.models.fields.related.ManyToManyField: groups>, |          <django.db.models.fields.related.ManyToManyField: groups>, | ||||||
|          <django.db.models.fields.related.ManyToManyField: user_permissions>) |          <django.db.models.fields.related.ManyToManyField: user_permissions>) | ||||||
|  |  | ||||||
|  | Retrieving fields composing the primary key of a model | ||||||
|  | ------------------------------------------------------ | ||||||
|  |  | ||||||
|  | .. versionadded:: 5.2 | ||||||
|  |  | ||||||
|  | .. attribute:: Options.pk_fields | ||||||
|  |  | ||||||
|  |     Returns a list of the fields composing the primary key of a model. | ||||||
|  |  | ||||||
|  |     When a :class:`composite primary key <django.db.models.CompositePrimaryKey>` | ||||||
|  |     is defined on a model it will contain all the | ||||||
|  |     :class:`fields <django.db.models.Field>` referenced by it. | ||||||
|  |  | ||||||
|  |     .. code-block:: python | ||||||
|  |  | ||||||
|  |         from django.db import models | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         class TenantUser(models.Model): | ||||||
|  |             pk = models.CompositePrimaryKey("tenant_id", "id") | ||||||
|  |             tenant_id = models.IntegerField() | ||||||
|  |             id = models.IntegerField() | ||||||
|  |  | ||||||
|  |     .. code-block:: pycon | ||||||
|  |  | ||||||
|  |         >>> TenantUser._meta.pk_fields | ||||||
|  |         [ | ||||||
|  |             <django.db.models.fields.IntegerField: tenant_id>, | ||||||
|  |             <django.db.models.fields.IntegerField: id> | ||||||
|  |         ] | ||||||
|  |  | ||||||
|  |     Otherwise it will contain the single field declared as the | ||||||
|  |     :attr:`primary key <django.db.models.Field.primary_key>` of the model. | ||||||
|  |  | ||||||
|  |     .. code-block:: pycon | ||||||
|  |  | ||||||
|  |         >>> User._meta.pk_fields | ||||||
|  |         [<django.db.models.fields.AutoField: id>] | ||||||
|   | |||||||
| @@ -185,3 +185,52 @@ field :exc:`.FieldError`. | |||||||
|     This is also true of composite primary keys. Hence, you may want to set |     This is also true of composite primary keys. Hence, you may want to set | ||||||
|     :attr:`.Field.editable` to ``False`` on all primary key fields to exclude |     :attr:`.Field.editable` to ``False`` on all primary key fields to exclude | ||||||
|     them from ModelForms. |     them from ModelForms. | ||||||
|  |  | ||||||
|  | Building composite primary key ready applications | ||||||
|  | ================================================= | ||||||
|  |  | ||||||
|  | Prior to the introduction of composite primary keys, the single field composing | ||||||
|  | the primary key of a model could be retrieved by introspecting the | ||||||
|  | :attr:`primary key <django.db.models.Field.primary_key>` attribute of its | ||||||
|  | fields: | ||||||
|  |  | ||||||
|  | .. code-block:: pycon | ||||||
|  |  | ||||||
|  |     >>> pk_field = None | ||||||
|  |     >>> for field in Product._meta.get_fields(): | ||||||
|  |     ...     if field.primary_key: | ||||||
|  |     ...         pk_field = field | ||||||
|  |     ...         break | ||||||
|  |     ... | ||||||
|  |     >>> pk_field | ||||||
|  |     <django.db.models.fields.AutoField: id> | ||||||
|  |  | ||||||
|  | Now that a primary key can be composed of multiple fields the | ||||||
|  | :attr:`primary key <django.db.models.Field.primary_key>` attribute can no | ||||||
|  | longer be relied upon to identify members of the primary key as it will be set | ||||||
|  | to ``False`` to maintain the invariant that at most one field per model will | ||||||
|  | have this attribute set to ``True``: | ||||||
|  |  | ||||||
|  | .. code-block:: pycon | ||||||
|  |  | ||||||
|  |     >>> pk_fields = [] | ||||||
|  |     >>> for field in OrderLineItem._meta.get_fields(): | ||||||
|  |     ...     if field.primary_key: | ||||||
|  |     ...         pk_fields.append(field) | ||||||
|  |     ... | ||||||
|  |     >>> pk_fields | ||||||
|  |     [] | ||||||
|  |  | ||||||
|  | In order to build application code that properly handles composite primary | ||||||
|  | keys the :attr:`_meta.pk_fields <django.db.models.options.Options.pk_fields>` | ||||||
|  | attribute should be used instead: | ||||||
|  |  | ||||||
|  | .. code-block:: pycon | ||||||
|  |  | ||||||
|  |     >>> Product._meta.pk_fields | ||||||
|  |     [<django.db.models.fields.AutoField: id>] | ||||||
|  |     >>> OrderLineItem._meta.pk_fields | ||||||
|  |     [ | ||||||
|  |         <django.db.models.fields.ForeignKey: product>, | ||||||
|  |         <django.db.models.fields.ForeignKey: order> | ||||||
|  |     ] | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user