Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.0] Add db_default= parameter to models Field classes #1876

Merged
merged 5 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions django-stubs/contrib/gis/db/models/fields.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ from django.contrib.gis.geos import (
Polygon,
)
from django.core.validators import _ValidatorCallable
from django.db.models.expressions import Combinable
from django.db.models.fields import Field, _ErrorMessagesMapping, _FieldChoices
from django.db.models.expressions import Combinable, Expression
from django.db.models.fields import NOT_PROVIDED, Field, _ErrorMessagesMapping, _FieldChoices
from django.utils.functional import _StrOrPromise

# __set__ value type
Expand Down Expand Up @@ -51,6 +51,7 @@ class BaseSpatialField(Field[_ST, _GT]):
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
Expand Down Expand Up @@ -95,6 +96,7 @@ class GeometryField(BaseSpatialField[_ST, _GT]):
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
Expand Down
5 changes: 3 additions & 2 deletions django-stubs/contrib/postgres/fields/array.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ from typing import Any, TypeVar

from django.core.validators import _ValidatorCallable
from django.db.models import Field, Transform
from django.db.models.expressions import Combinable
from django.db.models.fields import _ErrorMessagesDict, _ErrorMessagesMapping, _FieldChoices
from django.db.models.expressions import Combinable, Expression
from django.db.models.fields import NOT_PROVIDED, _ErrorMessagesDict, _ErrorMessagesMapping, _FieldChoices
from django.db.models.fields.mixins import CheckFieldDefaultMixin
from django.utils.functional import _StrOrPromise

Expand Down Expand Up @@ -37,6 +37,7 @@ class ArrayField(CheckFieldDefaultMixin, Field[_ST, _GT]):
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
Expand Down
2 changes: 2 additions & 0 deletions django-stubs/db/backends/base/schema.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ from django.db.models.base import Model
from django.db.models.constraints import BaseConstraint
from django.db.models.fields import Field
from django.db.models.indexes import Index
from django.db.models.sql.compiler import _AsSqlType
from typing_extensions import Self

logger: Logger
Expand Down Expand Up @@ -76,6 +77,7 @@ class BaseDatabaseSchemaEditor(AbstractContextManager[Any]):
def skip_default(self, field: Any) -> bool: ...
def skip_default_on_alter(self, field: Any) -> bool: ...
def prepare_default(self, value: Any) -> Any: ...
def db_default_sql(self, field: Field) -> _AsSqlType: ...
def effective_default(self, field: Field) -> int | str: ...
def quote_value(self, value: Any) -> str: ...
def create_model(self, model: type[Model]) -> None: ...
Expand Down
14 changes: 13 additions & 1 deletion django-stubs/db/models/fields/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ from django.core.checks import CheckMessage
from django.core.exceptions import FieldDoesNotExist as FieldDoesNotExist
from django.db.backends.base.base import BaseDatabaseWrapper
from django.db.models import Model
from django.db.models.expressions import Col, Combinable
from django.db.models.expressions import Col, Combinable, Expression
from django.db.models.fields.reverse_related import ForeignObjectRel
from django.db.models.query_utils import Q, RegisterLookupMixin
from django.forms import Widget
Expand Down Expand Up @@ -144,6 +144,7 @@ class Field(RegisterLookupMixin, Generic[_ST, _GT]):
choices: _ChoicesList | None
db_column: str | None
db_comment: str | None
db_default: type[NOT_PROVIDED] | Expression
column: str
concrete: bool
default: Any
Expand Down Expand Up @@ -182,6 +183,7 @@ class Field(RegisterLookupMixin, Generic[_ST, _GT]):
validators: Iterable[validators._ValidatorCallable] = ...,
error_messages: _ErrorMessagesMapping | None = ...,
db_comment: str | None = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for sitting on this for so long.

When I was thinking about this later, I realized that _ST typevar is usually unbound in model declarations (e.g. field = CharField(db_default=...) rather than field = CharField[str, str](db_default=...); the typevars are resolved later by mypy plugin.

In mypy, this doesn't cause errors at usage location because unbound typevars default to Any in mypy. But I wasn't sure about pyright.

I tested this now, seems that pyright handles it the same way: https://pyright-play.net/?pyrightVersion=1.1.353&pythonVersion=3.12&pythonPlatform=Linux&strict=true&locale=en&code=GYJw9gtgBALgngBwJYDsDmUkQWEMoDiApikSEgMYA0UAKokQGoCGIAUG7VALx0MsgAFACJawgJQcKAG2YBnOVABCsgBYAxJEWkATQcVLkKAbVoBdcQC42UW1B1FgUAPrPUSGK8FztwGjoAjZwdgZgBXaRhLOigAHygAOTBSHigAOgzxKABaAD5E5KJojLSONmAwMFSVZg0tXUFA4MdwyO4ARgAmAGZJAGI7QaG7AD0x8YmJqBQqsnB2IA

I think we can improve this later with typevar defaults on Field classes. There are other reasons as well why that's useful. So I think it's OK to merge this as is.

) -> None: ...
def __set__(self, instance: Any, value: _ST) -> None: ...
# class access
Expand Down Expand Up @@ -282,6 +284,7 @@ class DecimalField(Field[_ST, _GT]):
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
Expand Down Expand Up @@ -310,6 +313,7 @@ class CharField(Field[_ST, _GT]):
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
Expand Down Expand Up @@ -339,6 +343,7 @@ class SlugField(CharField[_ST, _GT]):
blank: bool = ...,
null: bool = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
Expand Down Expand Up @@ -374,6 +379,7 @@ class URLField(CharField[_ST, _GT]):
db_index: bool = ...,
rel: ForeignObjectRel | None = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
serialize: bool = ...,
unique_for_date: str | None = ...,
Expand Down Expand Up @@ -405,6 +411,7 @@ class TextField(Field[_ST, _GT]):
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
Expand Down Expand Up @@ -455,6 +462,7 @@ class GenericIPAddressField(Field[_ST, _GT]):
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
Expand Down Expand Up @@ -489,6 +497,7 @@ class DateField(DateTimeCheckMixin, Field[_ST, _GT]):
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
Expand Down Expand Up @@ -519,6 +528,7 @@ class TimeField(DateTimeCheckMixin, Field[_ST, _GT]):
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
Expand Down Expand Up @@ -553,6 +563,7 @@ class UUIDField(Field[_ST, _GT]):
db_index: bool = ...,
rel: ForeignObjectRel | None = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
serialize: bool = ...,
unique_for_date: str | None = ...,
Expand Down Expand Up @@ -591,6 +602,7 @@ class FilePathField(Field[_ST, _GT]):
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
Expand Down
4 changes: 3 additions & 1 deletion django-stubs/db/models/fields/files.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ from django.core.files.base import File
from django.core.files.images import ImageFile
from django.core.files.storage import Storage
from django.db.models.base import Model
from django.db.models.fields import Field, _ErrorMessagesMapping, _FieldChoices
from django.db.models.expressions import Expression
from django.db.models.fields import NOT_PROVIDED, Field, _ErrorMessagesMapping, _FieldChoices
from django.db.models.query_utils import DeferredAttribute
from django.utils._os import _PathCompatible
from django.utils.functional import _StrOrPromise
Expand Down Expand Up @@ -58,6 +59,7 @@ class FileField(Field):
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | str = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
Expand Down
15 changes: 13 additions & 2 deletions django-stubs/db/models/fields/related.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@ from uuid import UUID

from django.core import validators # due to weird mypy.stubtest error
from django.db.models.base import Model
from django.db.models.expressions import Combinable
from django.db.models.fields import Field, _AllLimitChoicesTo, _ErrorMessagesMapping, _FieldChoices, _LimitChoicesTo
from django.db.models.expressions import Combinable, Expression
from django.db.models.fields import (
NOT_PROVIDED,
Field,
_AllLimitChoicesTo,
_ErrorMessagesMapping,
_FieldChoices,
_LimitChoicesTo,
)
from django.db.models.fields.mixins import FieldCacheMixin
from django.db.models.fields.related_descriptors import ForwardManyToOneDescriptor as ForwardManyToOneDescriptor
from django.db.models.fields.related_descriptors import ForwardOneToOneDescriptor as ForwardOneToOneDescriptor
Expand Down Expand Up @@ -56,6 +63,7 @@ class RelatedField(FieldCacheMixin, Field[_ST, _GT]):
db_index: bool = ...,
rel: ForeignObjectRel | None = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
serialize: bool = ...,
unique_for_date: str | None = ...,
Expand Down Expand Up @@ -110,6 +118,7 @@ class ForeignObject(RelatedField[_ST, _GT]):
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
Expand Down Expand Up @@ -166,6 +175,7 @@ class ForeignKey(ForeignObject[_ST, _GT]):
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
Expand Down Expand Up @@ -207,6 +217,7 @@ class OneToOneField(ForeignKey[_ST, _GT]):
null: bool = ...,
db_index: bool = ...,
default: Any = ...,
db_default: type[NOT_PROVIDED] | Expression | _ST = ...,
editable: bool = ...,
auto_created: bool = ...,
serialize: bool = ...,
Expand Down
4 changes: 0 additions & 4 deletions scripts/stubtest/allowlist_todo_django50.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ django.contrib.gis.db.backends.spatialite.schema.SpatialiteSchemaEditor.alter_db
django.contrib.gis.db.models.Case.allowed_default
django.contrib.gis.db.models.ExpressionWrapper.allowed_default
django.contrib.gis.db.models.F.allowed_default
django.contrib.gis.db.models.Field.__init__
django.contrib.gis.db.models.Field._get_flatchoices
django.contrib.gis.db.models.Field.generated
django.contrib.gis.db.models.FilteredRelation.relabeled_clone
Expand Down Expand Up @@ -77,7 +76,6 @@ django.db.backends.base.features.BaseDatabaseFeatures.supports_nulls_distinct_un
django.db.backends.base.features.BaseDatabaseFeatures.supports_stored_generated_columns
django.db.backends.base.features.BaseDatabaseFeatures.supports_virtual_generated_columns
django.db.backends.base.operations.BaseDatabaseOperations.prepare_join_on_clause
django.db.backends.base.schema.BaseDatabaseSchemaEditor.db_default_sql
django.db.backends.mysql.features.DatabaseFeatures.allows_group_by_selected_pks
django.db.backends.mysql.features.DatabaseFeatures.delete_can_self_reference_subquery
django.db.backends.mysql.features.DatabaseFeatures.has_native_uuid_field
Expand Down Expand Up @@ -110,7 +108,6 @@ django.db.migrations.serializer.BaseUnorderedSequenceSerializer
django.db.models.Case.allowed_default
django.db.models.ExpressionWrapper.allowed_default
django.db.models.F.allowed_default
django.db.models.Field.__init__
django.db.models.Field._get_flatchoices
django.db.models.Field.generated
django.db.models.FilteredRelation.relabeled_clone
Expand All @@ -136,7 +133,6 @@ django.db.models.expressions.OrderByList.allowed_default
django.db.models.expressions.RawSQL.allowed_default
django.db.models.expressions.Value.allowed_default
django.db.models.expressions.When.allowed_default
django.db.models.fields.Field.__init__
django.db.models.fields.Field._get_flatchoices
django.db.models.fields.Field.generated
django.db.models.fields.related.ForeignKey.cast_db_type
Expand Down
Loading