mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +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 you don't specify ``primary_key=True`` for any field in your model, Django | ||||
| will automatically add a field to hold the primary key, so you don't need to | ||||
| set ``primary_key=True`` on any of your fields unless you want to override the | ||||
| default primary-key behavior. The type of auto-created primary key fields can | ||||
| be specified per app in :attr:`AppConfig.default_auto_field | ||||
| <django.apps.AppConfig.default_auto_field>` or globally in the | ||||
| :setting:`DEFAULT_AUTO_FIELD` setting. For more, see | ||||
| If you don't specify ``primary_key=True`` for any field in your model and have | ||||
| not defined a composite primary key, Django will automatically add a field to | ||||
| hold the primary key. So, you don't need to set ``primary_key=True`` on any of | ||||
| your fields unless you want to override the default primary-key behavior. The | ||||
| type of auto-created primary key fields can be specified per app in | ||||
| :attr:`AppConfig.default_auto_field <django.apps.AppConfig.default_auto_field>` | ||||
| or globally in the :setting:`DEFAULT_AUTO_FIELD` setting. For more, see | ||||
| :ref:`automatic-primary-key-fields`. | ||||
|  | ||||
| ``primary_key=True`` implies :attr:`null=False <Field.null>` and | ||||
| :attr:`unique=True <Field.unique>`. Only one primary key is allowed on an | ||||
| object. | ||||
| :attr:`unique=True <Field.unique>`. Only one field per model can set | ||||
| ``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 | ||||
| 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 | ||||
| :meth:`deleting <django.db.models.Model.delete>` an object. | ||||
|  | ||||
| .. versionchanged:: 5.2 | ||||
|  | ||||
|     The ``CompositePrimaryKey`` field was added. | ||||
|  | ||||
| ``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 | ||||
| ``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 a single field instance of a model by name | ||||
| * Retrieve all fields that compose the primary key of a model | ||||
|  | ||||
| .. _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.related.ManyToManyField: groups>, | ||||
|          <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 | ||||
|     :attr:`.Field.editable` to ``False`` on all primary key fields to exclude | ||||
|     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