Loading django/db/models/fields/__init__.py +30 −2 Original line number Diff line number Diff line Loading @@ -626,6 +626,14 @@ class Field(RegisterLookupMixin): except KeyError: return None def rel_db_type(self, connection): """ Return the data type that a related field pointing to this field should use. For example, this method is called by ForeignKey and OneToOneField to determine its data type. """ return self.db_type(connection) def db_parameters(self, connection): """ Extension of db_type(), providing a range of different return Loading Loading @@ -960,6 +968,9 @@ class AutoField(Field): params={'value': value}, ) def rel_db_type(self, connection): return IntegerField().db_type(connection=connection) def validate(self, value, model_instance): pass Loading Loading @@ -2072,7 +2083,24 @@ class NullBooleanField(Field): return super(NullBooleanField, self).formfield(**defaults) class PositiveIntegerField(IntegerField): class PositiveIntegerRelDbTypeMixin(object): def rel_db_type(self, connection): """ Return the data type that a related field pointing to this field should use. In most cases, a foreign key pointing to a positive integer primary key will have an integer column data type but some databases (e.g. MySQL) have an unsigned integer type. In that case (related_fields_match_type=True), the primary key should return its db_type. """ if connection.features.related_fields_match_type: return self.db_type(connection) else: return IntegerField().db_type(connection=connection) class PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField): description = _("Positive integer") def get_internal_type(self): Loading @@ -2084,7 +2112,7 @@ class PositiveIntegerField(IntegerField): return super(PositiveIntegerField, self).formfield(**defaults) class PositiveSmallIntegerField(IntegerField): class PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField): description = _("Positive small integer") def get_internal_type(self): Loading django/db/models/fields/related.py +2 −17 Original line number Diff line number Diff line Loading @@ -18,10 +18,7 @@ from django.utils.functional import cached_property, curry from django.utils.translation import ugettext_lazy as _ from django.utils.version import get_docs_version from . import ( AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, ) from . import Field from .related_descriptors import ( ForwardManyToOneDescriptor, ManyToManyDescriptor, ReverseManyToOneDescriptor, ReverseOneToOneDescriptor, Loading Loading @@ -935,19 +932,7 @@ class ForeignKey(ForeignObject): return super(ForeignKey, self).formfield(**defaults) def db_type(self, connection): # The database column type of a ForeignKey is the column type # of the field to which it points. An exception is if the ForeignKey # points to an AutoField/PositiveIntegerField/PositiveSmallIntegerField, # in which case the column type is simply that of an IntegerField. # If the database needs similar types for key fields however, the only # thing we can do is making AutoField an IntegerField. rel_field = self.target_field if (isinstance(rel_field, AutoField) or (not connection.features.related_fields_match_type and isinstance(rel_field, (PositiveIntegerField, PositiveSmallIntegerField)))): return IntegerField().db_type(connection=connection) return rel_field.db_type(connection=connection) return self.target_field.rel_db_type(connection=connection) def db_parameters(self, connection): return {"type": self.db_type(connection), "check": []} Loading docs/howto/custom-model-fields.txt +25 −8 Original line number Diff line number Diff line Loading @@ -374,14 +374,14 @@ For example:: else: return 'timestamp' The :meth:`~Field.db_type` method is called by Django when the framework constructs the ``CREATE TABLE`` statements for your application -- that is, when you first create your tables. It is also called when constructing a ``WHERE`` clause that includes the model field -- that is, when you retrieve data using QuerySet methods like ``get()``, ``filter()``, and ``exclude()`` and have the model field as an argument. It's not called at any other time, so it can afford to execute slightly complex code, such as the ``connection.settings_dict`` check in the above example. The :meth:`~Field.db_type` and :meth:`~Field.rel_db_type` methods are called by Django when the framework constructs the ``CREATE TABLE`` statements for your application -- that is, when you first create your tables. The methods are also called when constructing a ``WHERE`` clause that includes the model field -- that is, when you retrieve data using QuerySet methods like ``get()``, ``filter()``, and ``exclude()`` and have the model field as an argument. They are not called at any other time, so it can afford to execute slightly complex code, such as the ``connection.settings_dict`` check in the above example. Some database column types accept parameters, such as ``CHAR(25)``, where the parameter ``25`` represents the maximum column length. In cases like these, Loading Loading @@ -423,6 +423,23 @@ over this field. You are then responsible for creating the column in the right table in some other way, of course, but this gives you a way to tell Django to get out of the way. The :meth:`~Field.rel_db_type` method is called by fields such as ``ForeignKey`` and ``OneToOneField`` that point to another field to determine their database column data types. For example, if you have an ``UnsignedAutoField``, you also need the foreign keys that point to that field to use the same data type:: # MySQL unsigned integer (range 0 to 4294967295). class UnsignedAutoField(models.AutoField): def db_type(self, connection): return 'integer UNSIGNED AUTO_INCREMENT' def rel_db_type(self, connection): return 'integer UNSIGNED' .. versionadded:: 1.10 The :meth:`~Field.rel_db_type` method was added. .. _converting-values-to-python-objects: Converting values to Python objects Loading docs/ref/models/fields.txt +12 −1 Original line number Diff line number Diff line Loading @@ -1701,7 +1701,8 @@ Field API reference where the arguments are interpolated from the field's ``__dict__``. To map a ``Field`` to a database-specific type, Django exposes two methods: To map a ``Field`` to a database-specific type, Django exposes several methods: .. method:: get_internal_type() Loading @@ -1717,6 +1718,16 @@ Field API reference See :ref:`custom-database-types` for usage in custom fields. .. method:: rel_db_type(connection) .. versionadded:: 1.10 Returns the database column data type for fields such as ``ForeignKey`` and ``OneToOneField`` that point to the :class:`Field`, taking into account the ``connection``. See :ref:`custom-database-types` for usage in custom fields. There are three main situations where Django needs to interact with the database backend and fields: Loading docs/releases/1.10.txt +4 −0 Original line number Diff line number Diff line Loading @@ -202,6 +202,10 @@ Models accessible as a descriptor on the proxied model class and may be referenced in queryset filtering. * The new :meth:`Field.rel_db_type() <django.db.models.Field.rel_db_type>` method returns the database column data type for fields such as ``ForeignKey`` and ``OneToOneField`` that point to another field. * The :attr:`~django.db.models.Func.arity` class attribute is added to :class:`~django.db.models.Func`. This attribute can be used to set the number of arguments the function accepts. Loading Loading
django/db/models/fields/__init__.py +30 −2 Original line number Diff line number Diff line Loading @@ -626,6 +626,14 @@ class Field(RegisterLookupMixin): except KeyError: return None def rel_db_type(self, connection): """ Return the data type that a related field pointing to this field should use. For example, this method is called by ForeignKey and OneToOneField to determine its data type. """ return self.db_type(connection) def db_parameters(self, connection): """ Extension of db_type(), providing a range of different return Loading Loading @@ -960,6 +968,9 @@ class AutoField(Field): params={'value': value}, ) def rel_db_type(self, connection): return IntegerField().db_type(connection=connection) def validate(self, value, model_instance): pass Loading Loading @@ -2072,7 +2083,24 @@ class NullBooleanField(Field): return super(NullBooleanField, self).formfield(**defaults) class PositiveIntegerField(IntegerField): class PositiveIntegerRelDbTypeMixin(object): def rel_db_type(self, connection): """ Return the data type that a related field pointing to this field should use. In most cases, a foreign key pointing to a positive integer primary key will have an integer column data type but some databases (e.g. MySQL) have an unsigned integer type. In that case (related_fields_match_type=True), the primary key should return its db_type. """ if connection.features.related_fields_match_type: return self.db_type(connection) else: return IntegerField().db_type(connection=connection) class PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField): description = _("Positive integer") def get_internal_type(self): Loading @@ -2084,7 +2112,7 @@ class PositiveIntegerField(IntegerField): return super(PositiveIntegerField, self).formfield(**defaults) class PositiveSmallIntegerField(IntegerField): class PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField): description = _("Positive small integer") def get_internal_type(self): Loading
django/db/models/fields/related.py +2 −17 Original line number Diff line number Diff line Loading @@ -18,10 +18,7 @@ from django.utils.functional import cached_property, curry from django.utils.translation import ugettext_lazy as _ from django.utils.version import get_docs_version from . import ( AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, ) from . import Field from .related_descriptors import ( ForwardManyToOneDescriptor, ManyToManyDescriptor, ReverseManyToOneDescriptor, ReverseOneToOneDescriptor, Loading Loading @@ -935,19 +932,7 @@ class ForeignKey(ForeignObject): return super(ForeignKey, self).formfield(**defaults) def db_type(self, connection): # The database column type of a ForeignKey is the column type # of the field to which it points. An exception is if the ForeignKey # points to an AutoField/PositiveIntegerField/PositiveSmallIntegerField, # in which case the column type is simply that of an IntegerField. # If the database needs similar types for key fields however, the only # thing we can do is making AutoField an IntegerField. rel_field = self.target_field if (isinstance(rel_field, AutoField) or (not connection.features.related_fields_match_type and isinstance(rel_field, (PositiveIntegerField, PositiveSmallIntegerField)))): return IntegerField().db_type(connection=connection) return rel_field.db_type(connection=connection) return self.target_field.rel_db_type(connection=connection) def db_parameters(self, connection): return {"type": self.db_type(connection), "check": []} Loading
docs/howto/custom-model-fields.txt +25 −8 Original line number Diff line number Diff line Loading @@ -374,14 +374,14 @@ For example:: else: return 'timestamp' The :meth:`~Field.db_type` method is called by Django when the framework constructs the ``CREATE TABLE`` statements for your application -- that is, when you first create your tables. It is also called when constructing a ``WHERE`` clause that includes the model field -- that is, when you retrieve data using QuerySet methods like ``get()``, ``filter()``, and ``exclude()`` and have the model field as an argument. It's not called at any other time, so it can afford to execute slightly complex code, such as the ``connection.settings_dict`` check in the above example. The :meth:`~Field.db_type` and :meth:`~Field.rel_db_type` methods are called by Django when the framework constructs the ``CREATE TABLE`` statements for your application -- that is, when you first create your tables. The methods are also called when constructing a ``WHERE`` clause that includes the model field -- that is, when you retrieve data using QuerySet methods like ``get()``, ``filter()``, and ``exclude()`` and have the model field as an argument. They are not called at any other time, so it can afford to execute slightly complex code, such as the ``connection.settings_dict`` check in the above example. Some database column types accept parameters, such as ``CHAR(25)``, where the parameter ``25`` represents the maximum column length. In cases like these, Loading Loading @@ -423,6 +423,23 @@ over this field. You are then responsible for creating the column in the right table in some other way, of course, but this gives you a way to tell Django to get out of the way. The :meth:`~Field.rel_db_type` method is called by fields such as ``ForeignKey`` and ``OneToOneField`` that point to another field to determine their database column data types. For example, if you have an ``UnsignedAutoField``, you also need the foreign keys that point to that field to use the same data type:: # MySQL unsigned integer (range 0 to 4294967295). class UnsignedAutoField(models.AutoField): def db_type(self, connection): return 'integer UNSIGNED AUTO_INCREMENT' def rel_db_type(self, connection): return 'integer UNSIGNED' .. versionadded:: 1.10 The :meth:`~Field.rel_db_type` method was added. .. _converting-values-to-python-objects: Converting values to Python objects Loading
docs/ref/models/fields.txt +12 −1 Original line number Diff line number Diff line Loading @@ -1701,7 +1701,8 @@ Field API reference where the arguments are interpolated from the field's ``__dict__``. To map a ``Field`` to a database-specific type, Django exposes two methods: To map a ``Field`` to a database-specific type, Django exposes several methods: .. method:: get_internal_type() Loading @@ -1717,6 +1718,16 @@ Field API reference See :ref:`custom-database-types` for usage in custom fields. .. method:: rel_db_type(connection) .. versionadded:: 1.10 Returns the database column data type for fields such as ``ForeignKey`` and ``OneToOneField`` that point to the :class:`Field`, taking into account the ``connection``. See :ref:`custom-database-types` for usage in custom fields. There are three main situations where Django needs to interact with the database backend and fields: Loading
docs/releases/1.10.txt +4 −0 Original line number Diff line number Diff line Loading @@ -202,6 +202,10 @@ Models accessible as a descriptor on the proxied model class and may be referenced in queryset filtering. * The new :meth:`Field.rel_db_type() <django.db.models.Field.rel_db_type>` method returns the database column data type for fields such as ``ForeignKey`` and ``OneToOneField`` that point to another field. * The :attr:`~django.db.models.Func.arity` class attribute is added to :class:`~django.db.models.Func`. This attribute can be used to set the number of arguments the function accepts. Loading