plain.models 0.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. plain_models-0.0.0/LICENSE +61 -0
  2. plain_models-0.0.0/PKG-INFO +11 -0
  3. plain_models-0.0.0/plain/models/README.md +94 -0
  4. plain_models-0.0.0/plain/models/__init__.py +152 -0
  5. plain_models-0.0.0/plain/models/aggregates.py +202 -0
  6. plain_models-0.0.0/plain/models/backends/README.md +1 -0
  7. plain_models-0.0.0/plain/models/backends/__init__.py +0 -0
  8. plain_models-0.0.0/plain/models/backends/base/__init__.py +0 -0
  9. plain_models-0.0.0/plain/models/backends/base/base.py +783 -0
  10. plain_models-0.0.0/plain/models/backends/base/client.py +28 -0
  11. plain_models-0.0.0/plain/models/backends/base/creation.py +343 -0
  12. plain_models-0.0.0/plain/models/backends/base/features.py +386 -0
  13. plain_models-0.0.0/plain/models/backends/base/introspection.py +214 -0
  14. plain_models-0.0.0/plain/models/backends/base/operations.py +779 -0
  15. plain_models-0.0.0/plain/models/backends/base/schema.py +1810 -0
  16. plain_models-0.0.0/plain/models/backends/base/validation.py +29 -0
  17. plain_models-0.0.0/plain/models/backends/ddl_references.py +254 -0
  18. plain_models-0.0.0/plain/models/backends/dummy/__init__.py +0 -0
  19. plain_models-0.0.0/plain/models/backends/dummy/base.py +74 -0
  20. plain_models-0.0.0/plain/models/backends/dummy/features.py +6 -0
  21. plain_models-0.0.0/plain/models/backends/mysql/__init__.py +0 -0
  22. plain_models-0.0.0/plain/models/backends/mysql/base.py +436 -0
  23. plain_models-0.0.0/plain/models/backends/mysql/client.py +72 -0
  24. plain_models-0.0.0/plain/models/backends/mysql/compiler.py +83 -0
  25. plain_models-0.0.0/plain/models/backends/mysql/creation.py +86 -0
  26. plain_models-0.0.0/plain/models/backends/mysql/features.py +261 -0
  27. plain_models-0.0.0/plain/models/backends/mysql/introspection.py +349 -0
  28. plain_models-0.0.0/plain/models/backends/mysql/operations.py +456 -0
  29. plain_models-0.0.0/plain/models/backends/mysql/schema.py +255 -0
  30. plain_models-0.0.0/plain/models/backends/mysql/validation.py +70 -0
  31. plain_models-0.0.0/plain/models/backends/postgresql/__init__.py +0 -0
  32. plain_models-0.0.0/plain/models/backends/postgresql/base.py +457 -0
  33. plain_models-0.0.0/plain/models/backends/postgresql/client.py +64 -0
  34. plain_models-0.0.0/plain/models/backends/postgresql/creation.py +86 -0
  35. plain_models-0.0.0/plain/models/backends/postgresql/features.py +111 -0
  36. plain_models-0.0.0/plain/models/backends/postgresql/introspection.py +298 -0
  37. plain_models-0.0.0/plain/models/backends/postgresql/operations.py +412 -0
  38. plain_models-0.0.0/plain/models/backends/postgresql/psycopg_any.py +108 -0
  39. plain_models-0.0.0/plain/models/backends/postgresql/schema.py +374 -0
  40. plain_models-0.0.0/plain/models/backends/signals.py +3 -0
  41. plain_models-0.0.0/plain/models/backends/sqlite3/__init__.py +0 -0
  42. plain_models-0.0.0/plain/models/backends/sqlite3/_functions.py +509 -0
  43. plain_models-0.0.0/plain/models/backends/sqlite3/base.py +340 -0
  44. plain_models-0.0.0/plain/models/backends/sqlite3/client.py +10 -0
  45. plain_models-0.0.0/plain/models/backends/sqlite3/creation.py +157 -0
  46. plain_models-0.0.0/plain/models/backends/sqlite3/features.py +91 -0
  47. plain_models-0.0.0/plain/models/backends/sqlite3/introspection.py +436 -0
  48. plain_models-0.0.0/plain/models/backends/sqlite3/operations.py +438 -0
  49. plain_models-0.0.0/plain/models/backends/sqlite3/schema.py +564 -0
  50. plain_models-0.0.0/plain/models/backends/utils.py +320 -0
  51. plain_models-0.0.0/plain/models/base.py +2368 -0
  52. plain_models-0.0.0/plain/models/cli.py +76 -0
  53. plain_models-0.0.0/plain/models/config.py +8 -0
  54. plain_models-0.0.0/plain/models/constants.py +12 -0
  55. plain_models-0.0.0/plain/models/constraints.py +443 -0
  56. plain_models-0.0.0/plain/models/database_url.py +188 -0
  57. plain_models-0.0.0/plain/models/db.py +295 -0
  58. plain_models-0.0.0/plain/models/default_settings.py +30 -0
  59. plain_models-0.0.0/plain/models/deletion.py +524 -0
  60. plain_models-0.0.0/plain/models/enums.py +92 -0
  61. plain_models-0.0.0/plain/models/expressions.py +1836 -0
  62. plain_models-0.0.0/plain/models/fields/README.md +1 -0
  63. plain_models-0.0.0/plain/models/fields/__init__.py +2459 -0
  64. plain_models-0.0.0/plain/models/fields/json.py +562 -0
  65. plain_models-0.0.0/plain/models/fields/mixins.py +60 -0
  66. plain_models-0.0.0/plain/models/fields/proxy.py +18 -0
  67. plain_models-0.0.0/plain/models/fields/related.py +1915 -0
  68. plain_models-0.0.0/plain/models/fields/related_descriptors.py +1424 -0
  69. plain_models-0.0.0/plain/models/fields/related_lookups.py +199 -0
  70. plain_models-0.0.0/plain/models/fields/reverse_related.py +396 -0
  71. plain_models-0.0.0/plain/models/forms.py +851 -0
  72. plain_models-0.0.0/plain/models/functions/__init__.py +190 -0
  73. plain_models-0.0.0/plain/models/functions/comparison.py +177 -0
  74. plain_models-0.0.0/plain/models/functions/datetime.py +430 -0
  75. plain_models-0.0.0/plain/models/functions/math.py +176 -0
  76. plain_models-0.0.0/plain/models/functions/mixins.py +41 -0
  77. plain_models-0.0.0/plain/models/functions/text.py +313 -0
  78. plain_models-0.0.0/plain/models/functions/window.py +120 -0
  79. plain_models-0.0.0/plain/models/indexes.py +297 -0
  80. plain_models-0.0.0/plain/models/lookups.py +740 -0
  81. plain_models-0.0.0/plain/models/management/commands/flush.py +93 -0
  82. plain_models-0.0.0/plain/models/management/commands/makemigrations.py +529 -0
  83. plain_models-0.0.0/plain/models/management/commands/migrate.py +526 -0
  84. plain_models-0.0.0/plain/models/management/commands/optimizemigration.py +131 -0
  85. plain_models-0.0.0/plain/models/management/commands/showmigrations.py +176 -0
  86. plain_models-0.0.0/plain/models/management/commands/squashmigrations.py +268 -0
  87. plain_models-0.0.0/plain/models/manager.py +211 -0
  88. plain_models-0.0.0/plain/models/migrations/README.md +1 -0
  89. plain_models-0.0.0/plain/models/migrations/__init__.py +2 -0
  90. plain_models-0.0.0/plain/models/migrations/autodetector.py +1646 -0
  91. plain_models-0.0.0/plain/models/migrations/exceptions.py +60 -0
  92. plain_models-0.0.0/plain/models/migrations/executor.py +411 -0
  93. plain_models-0.0.0/plain/models/migrations/graph.py +334 -0
  94. plain_models-0.0.0/plain/models/migrations/loader.py +388 -0
  95. plain_models-0.0.0/plain/models/migrations/migration.py +239 -0
  96. plain_models-0.0.0/plain/models/migrations/operations/__init__.py +42 -0
  97. plain_models-0.0.0/plain/models/migrations/operations/base.py +146 -0
  98. plain_models-0.0.0/plain/models/migrations/operations/fields.py +353 -0
  99. plain_models-0.0.0/plain/models/migrations/operations/models.py +1115 -0
  100. plain_models-0.0.0/plain/models/migrations/operations/special.py +208 -0
  101. plain_models-0.0.0/plain/models/migrations/optimizer.py +71 -0
  102. plain_models-0.0.0/plain/models/migrations/questioner.py +349 -0
  103. plain_models-0.0.0/plain/models/migrations/recorder.py +104 -0
  104. plain_models-0.0.0/plain/models/migrations/serializer.py +386 -0
  105. plain_models-0.0.0/plain/models/migrations/state.py +953 -0
  106. plain_models-0.0.0/plain/models/migrations/utils.py +129 -0
  107. plain_models-0.0.0/plain/models/migrations/writer.py +305 -0
  108. plain_models-0.0.0/plain/models/options.py +920 -0
  109. plain_models-0.0.0/plain/models/preflight.py +275 -0
  110. plain_models-0.0.0/plain/models/query.py +2482 -0
  111. plain_models-0.0.0/plain/models/query_utils.py +436 -0
  112. plain_models-0.0.0/plain/models/signals.py +56 -0
  113. plain_models-0.0.0/plain/models/sql/__init__.py +6 -0
  114. plain_models-0.0.0/plain/models/sql/compiler.py +2085 -0
  115. plain_models-0.0.0/plain/models/sql/constants.py +24 -0
  116. plain_models-0.0.0/plain/models/sql/datastructures.py +218 -0
  117. plain_models-0.0.0/plain/models/sql/query.py +2650 -0
  118. plain_models-0.0.0/plain/models/sql/subqueries.py +171 -0
  119. plain_models-0.0.0/plain/models/sql/where.py +355 -0
  120. plain_models-0.0.0/plain/models/transaction.py +323 -0
  121. plain_models-0.0.0/plain/models/utils.py +69 -0
  122. plain_models-0.0.0/pyproject.toml +17 -0
@@ -0,0 +1,61 @@
1
+ ## Plain is released under the BSD 3-Clause License
2
+
3
+ BSD 3-Clause License
4
+
5
+ Copyright (c) 2023, Dropseed, LLC
6
+
7
+ Redistribution and use in source and binary forms, with or without
8
+ modification, are permitted provided that the following conditions are met:
9
+
10
+ 1. Redistributions of source code must retain the above copyright notice, this
11
+ list of conditions and the following disclaimer.
12
+
13
+ 2. Redistributions in binary form must reproduce the above copyright notice,
14
+ this list of conditions and the following disclaimer in the documentation
15
+ and/or other materials provided with the distribution.
16
+
17
+ 3. Neither the name of the copyright holder nor the names of its
18
+ contributors may be used to endorse or promote products derived from
19
+ this software without specific prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+
32
+
33
+ ## This package contains code forked from github.com/django/django
34
+
35
+ Copyright (c) Django Software Foundation and individual contributors.
36
+ All rights reserved.
37
+
38
+ Redistribution and use in source and binary forms, with or without modification,
39
+ are permitted provided that the following conditions are met:
40
+
41
+ 1. Redistributions of source code must retain the above copyright notice,
42
+ this list of conditions and the following disclaimer.
43
+
44
+ 2. Redistributions in binary form must reproduce the above copyright
45
+ notice, this list of conditions and the following disclaimer in the
46
+ documentation and/or other materials provided with the distribution.
47
+
48
+ 3. Neither the name of Django nor the names of its contributors may be used
49
+ to endorse or promote products derived from this software without
50
+ specific prior written permission.
51
+
52
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
53
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
54
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
55
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
56
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
57
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
58
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
59
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
61
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.1
2
+ Name: plain.models
3
+ Version: 0.0.0
4
+ Summary:
5
+ Author: Dave Gaeddert
6
+ Author-email: dave.gaeddert@dropseed.dev
7
+ Requires-Python: >=3.11,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Requires-Dist: sqlparse (>=0.3.1)
@@ -0,0 +1,94 @@
1
+ # plain-models
2
+
3
+ Model your data and store it in a database.
4
+
5
+ ```python
6
+ # app/users/models.py
7
+ from plain import models
8
+ from plain.passwords.models import PasswordField
9
+
10
+
11
+ class User(models.Model):
12
+ email = models.EmailField(unique=True)
13
+ password = PasswordField()
14
+ is_staff = models.BooleanField(default=False)
15
+ created_at = models.DateTimeField(auto_now_add=True)
16
+
17
+ def __str__(self):
18
+ return self.email
19
+ ```
20
+
21
+ Create, update, and delete instances of your models:
22
+
23
+ ```python
24
+ from .models import User
25
+
26
+
27
+ # Create a new user
28
+ user = User.objects.create(
29
+ email="test@example.com",
30
+ password="password",
31
+ )
32
+
33
+ # Update a user
34
+ user.email = "new@example.com"
35
+ user.save()
36
+
37
+ # Delete a user
38
+ user.delete()
39
+
40
+ # Query for users
41
+ staff_users = User.objects.filter(is_staff=True)
42
+ ```
43
+
44
+ ## Installation
45
+
46
+ ```python
47
+ # app/settings.py
48
+ INSTALLED_PACKAGES = [
49
+ ...
50
+ "plain.models",
51
+ ]
52
+ ```
53
+
54
+ To connect to a database, you can provide a `DATABASE_URL` environment variable.
55
+
56
+ ```sh
57
+ DATABASE_URL=postgresql://user:password@localhost:5432/dbname
58
+ ```
59
+
60
+ Or you can manually define the `DATABASES` setting.
61
+
62
+ ```python
63
+ # app/settings.py
64
+ DATABASES = {
65
+ "default": {
66
+ "ENGINE": "plain.models.backends.postgresql",
67
+ "NAME": "dbname",
68
+ "USER": "user",
69
+ "PASSWORD": "password",
70
+ "HOST": "localhost",
71
+ "PORT": "5432",
72
+ }
73
+ }
74
+ ```
75
+
76
+ [Multiple backends are supported, including Postgres, MySQL, and SQLite.](./backends/README.md)
77
+
78
+ ## Querying
79
+
80
+ ## Migrations
81
+
82
+ [Migration docs](./migrations/README.md)
83
+
84
+ ## Fields
85
+
86
+ [Field docs](./fields/README.md)
87
+
88
+ ## Validation
89
+
90
+ ## Indexes and constraints
91
+
92
+ ## Managers
93
+
94
+ ## Forms
@@ -0,0 +1,152 @@
1
+ from plain.exceptions import ObjectDoesNotExist
2
+
3
+ from . import (
4
+ preflight, # noqa
5
+ )
6
+ from .aggregates import * # NOQA
7
+ from .aggregates import __all__ as aggregates_all
8
+ from .constraints import * # NOQA
9
+ from .constraints import __all__ as constraints_all
10
+ from .db import (
11
+ DEFAULT_DB_ALIAS,
12
+ PLAIN_VERSION_PICKLE_KEY,
13
+ DatabaseError,
14
+ DataError,
15
+ Error,
16
+ IntegrityError,
17
+ InterfaceError,
18
+ InternalError,
19
+ NotSupportedError,
20
+ OperationalError,
21
+ ProgrammingError,
22
+ close_old_connections,
23
+ connection,
24
+ connections,
25
+ reset_queries,
26
+ router,
27
+ )
28
+ from .deletion import (
29
+ CASCADE,
30
+ DO_NOTHING,
31
+ PROTECT,
32
+ RESTRICT,
33
+ SET,
34
+ SET_DEFAULT,
35
+ SET_NULL,
36
+ ProtectedError,
37
+ RestrictedError,
38
+ )
39
+ from .enums import * # NOQA
40
+ from .enums import __all__ as enums_all
41
+ from .expressions import (
42
+ Case,
43
+ Exists,
44
+ Expression,
45
+ ExpressionList,
46
+ ExpressionWrapper,
47
+ F,
48
+ Func,
49
+ OrderBy,
50
+ OuterRef,
51
+ RowRange,
52
+ Subquery,
53
+ Value,
54
+ ValueRange,
55
+ When,
56
+ Window,
57
+ WindowFrame,
58
+ )
59
+ from .fields import * # NOQA
60
+ from .fields import __all__ as fields_all
61
+ from .fields.json import JSONField
62
+ from .fields.proxy import OrderWrt
63
+ from .indexes import * # NOQA
64
+ from .indexes import __all__ as indexes_all
65
+ from .lookups import Lookup, Transform
66
+ from .manager import Manager
67
+ from .query import Prefetch, QuerySet, prefetch_related_objects
68
+ from .query_utils import FilteredRelation, Q
69
+
70
+ # Imports that would create circular imports if sorted
71
+ from .base import DEFERRED, Model # isort:skip
72
+ from .fields.related import ( # isort:skip
73
+ ForeignKey,
74
+ ForeignObject,
75
+ OneToOneField,
76
+ ManyToManyField,
77
+ ForeignObjectRel,
78
+ ManyToOneRel,
79
+ ManyToManyRel,
80
+ OneToOneRel,
81
+ )
82
+
83
+
84
+ __all__ = aggregates_all + constraints_all + enums_all + fields_all + indexes_all
85
+ __all__ += [
86
+ "ObjectDoesNotExist",
87
+ "CASCADE",
88
+ "DO_NOTHING",
89
+ "PROTECT",
90
+ "RESTRICT",
91
+ "SET",
92
+ "SET_DEFAULT",
93
+ "SET_NULL",
94
+ "ProtectedError",
95
+ "RestrictedError",
96
+ "Case",
97
+ "Exists",
98
+ "Expression",
99
+ "ExpressionList",
100
+ "ExpressionWrapper",
101
+ "F",
102
+ "Func",
103
+ "OrderBy",
104
+ "OuterRef",
105
+ "RowRange",
106
+ "Subquery",
107
+ "Value",
108
+ "ValueRange",
109
+ "When",
110
+ "Window",
111
+ "WindowFrame",
112
+ "JSONField",
113
+ "OrderWrt",
114
+ "Lookup",
115
+ "Transform",
116
+ "Manager",
117
+ "Prefetch",
118
+ "Q",
119
+ "QuerySet",
120
+ "prefetch_related_objects",
121
+ "DEFERRED",
122
+ "Model",
123
+ "FilteredRelation",
124
+ "ForeignKey",
125
+ "ForeignObject",
126
+ "OneToOneField",
127
+ "ManyToManyField",
128
+ "ForeignObjectRel",
129
+ "ManyToOneRel",
130
+ "ManyToManyRel",
131
+ "OneToOneRel",
132
+ ]
133
+
134
+ # DB-related exports
135
+ __all__ += [
136
+ "connection",
137
+ "connections",
138
+ "router",
139
+ "reset_queries",
140
+ "close_old_connections",
141
+ "DatabaseError",
142
+ "IntegrityError",
143
+ "InternalError",
144
+ "ProgrammingError",
145
+ "DataError",
146
+ "NotSupportedError",
147
+ "Error",
148
+ "InterfaceError",
149
+ "OperationalError",
150
+ "DEFAULT_DB_ALIAS",
151
+ "PLAIN_VERSION_PICKLE_KEY",
152
+ ]
@@ -0,0 +1,202 @@
1
+ """
2
+ Classes to represent the definitions of aggregate functions.
3
+ """
4
+ from plain.exceptions import FieldError, FullResultSet
5
+ from plain.models.expressions import Case, Func, Star, Value, When
6
+ from plain.models.fields import IntegerField
7
+ from plain.models.functions.comparison import Coalesce
8
+ from plain.models.functions.mixins import (
9
+ FixDurationInputMixin,
10
+ NumericOutputFieldMixin,
11
+ )
12
+
13
+ __all__ = [
14
+ "Aggregate",
15
+ "Avg",
16
+ "Count",
17
+ "Max",
18
+ "Min",
19
+ "StdDev",
20
+ "Sum",
21
+ "Variance",
22
+ ]
23
+
24
+
25
+ class Aggregate(Func):
26
+ template = "%(function)s(%(distinct)s%(expressions)s)"
27
+ contains_aggregate = True
28
+ name = None
29
+ filter_template = "%s FILTER (WHERE %%(filter)s)"
30
+ window_compatible = True
31
+ allow_distinct = False
32
+ empty_result_set_value = None
33
+
34
+ def __init__(
35
+ self, *expressions, distinct=False, filter=None, default=None, **extra
36
+ ):
37
+ if distinct and not self.allow_distinct:
38
+ raise TypeError("%s does not allow distinct." % self.__class__.__name__)
39
+ if default is not None and self.empty_result_set_value is not None:
40
+ raise TypeError(f"{self.__class__.__name__} does not allow default.")
41
+ self.distinct = distinct
42
+ self.filter = filter
43
+ self.default = default
44
+ super().__init__(*expressions, **extra)
45
+
46
+ def get_source_fields(self):
47
+ # Don't return the filter expression since it's not a source field.
48
+ return [e._output_field_or_none for e in super().get_source_expressions()]
49
+
50
+ def get_source_expressions(self):
51
+ source_expressions = super().get_source_expressions()
52
+ if self.filter:
53
+ return source_expressions + [self.filter]
54
+ return source_expressions
55
+
56
+ def set_source_expressions(self, exprs):
57
+ self.filter = self.filter and exprs.pop()
58
+ return super().set_source_expressions(exprs)
59
+
60
+ def resolve_expression(
61
+ self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False
62
+ ):
63
+ # Aggregates are not allowed in UPDATE queries, so ignore for_save
64
+ c = super().resolve_expression(query, allow_joins, reuse, summarize)
65
+ c.filter = c.filter and c.filter.resolve_expression(
66
+ query, allow_joins, reuse, summarize
67
+ )
68
+ if not summarize:
69
+ # Call Aggregate.get_source_expressions() to avoid
70
+ # returning self.filter and including that in this loop.
71
+ expressions = super(Aggregate, c).get_source_expressions()
72
+ for index, expr in enumerate(expressions):
73
+ if expr.contains_aggregate:
74
+ before_resolved = self.get_source_expressions()[index]
75
+ name = (
76
+ before_resolved.name
77
+ if hasattr(before_resolved, "name")
78
+ else repr(before_resolved)
79
+ )
80
+ raise FieldError(
81
+ f"Cannot compute {c.name}('{name}'): '{name}' is an aggregate"
82
+ )
83
+ if (default := c.default) is None:
84
+ return c
85
+ if hasattr(default, "resolve_expression"):
86
+ default = default.resolve_expression(query, allow_joins, reuse, summarize)
87
+ if default._output_field_or_none is None:
88
+ default.output_field = c._output_field_or_none
89
+ else:
90
+ default = Value(default, c._output_field_or_none)
91
+ c.default = None # Reset the default argument before wrapping.
92
+ coalesce = Coalesce(c, default, output_field=c._output_field_or_none)
93
+ coalesce.is_summary = c.is_summary
94
+ return coalesce
95
+
96
+ @property
97
+ def default_alias(self):
98
+ expressions = self.get_source_expressions()
99
+ if len(expressions) == 1 and hasattr(expressions[0], "name"):
100
+ return f"{expressions[0].name}__{self.name.lower()}"
101
+ raise TypeError("Complex expressions require an alias")
102
+
103
+ def get_group_by_cols(self):
104
+ return []
105
+
106
+ def as_sql(self, compiler, connection, **extra_context):
107
+ extra_context["distinct"] = "DISTINCT " if self.distinct else ""
108
+ if self.filter:
109
+ if connection.features.supports_aggregate_filter_clause:
110
+ try:
111
+ filter_sql, filter_params = self.filter.as_sql(compiler, connection)
112
+ except FullResultSet:
113
+ pass
114
+ else:
115
+ template = self.filter_template % extra_context.get(
116
+ "template", self.template
117
+ )
118
+ sql, params = super().as_sql(
119
+ compiler,
120
+ connection,
121
+ template=template,
122
+ filter=filter_sql,
123
+ **extra_context,
124
+ )
125
+ return sql, (*params, *filter_params)
126
+ else:
127
+ copy = self.copy()
128
+ copy.filter = None
129
+ source_expressions = copy.get_source_expressions()
130
+ condition = When(self.filter, then=source_expressions[0])
131
+ copy.set_source_expressions([Case(condition)] + source_expressions[1:])
132
+ return super(Aggregate, copy).as_sql(
133
+ compiler, connection, **extra_context
134
+ )
135
+ return super().as_sql(compiler, connection, **extra_context)
136
+
137
+ def _get_repr_options(self):
138
+ options = super()._get_repr_options()
139
+ if self.distinct:
140
+ options["distinct"] = self.distinct
141
+ if self.filter:
142
+ options["filter"] = self.filter
143
+ return options
144
+
145
+
146
+ class Avg(FixDurationInputMixin, NumericOutputFieldMixin, Aggregate):
147
+ function = "AVG"
148
+ name = "Avg"
149
+ allow_distinct = True
150
+
151
+
152
+ class Count(Aggregate):
153
+ function = "COUNT"
154
+ name = "Count"
155
+ output_field = IntegerField()
156
+ allow_distinct = True
157
+ empty_result_set_value = 0
158
+
159
+ def __init__(self, expression, filter=None, **extra):
160
+ if expression == "*":
161
+ expression = Star()
162
+ if isinstance(expression, Star) and filter is not None:
163
+ raise ValueError("Star cannot be used with filter. Please specify a field.")
164
+ super().__init__(expression, filter=filter, **extra)
165
+
166
+
167
+ class Max(Aggregate):
168
+ function = "MAX"
169
+ name = "Max"
170
+
171
+
172
+ class Min(Aggregate):
173
+ function = "MIN"
174
+ name = "Min"
175
+
176
+
177
+ class StdDev(NumericOutputFieldMixin, Aggregate):
178
+ name = "StdDev"
179
+
180
+ def __init__(self, expression, sample=False, **extra):
181
+ self.function = "STDDEV_SAMP" if sample else "STDDEV_POP"
182
+ super().__init__(expression, **extra)
183
+
184
+ def _get_repr_options(self):
185
+ return {**super()._get_repr_options(), "sample": self.function == "STDDEV_SAMP"}
186
+
187
+
188
+ class Sum(FixDurationInputMixin, Aggregate):
189
+ function = "SUM"
190
+ name = "Sum"
191
+ allow_distinct = True
192
+
193
+
194
+ class Variance(NumericOutputFieldMixin, Aggregate):
195
+ name = "Variance"
196
+
197
+ def __init__(self, expression, sample=False, **extra):
198
+ self.function = "VAR_SAMP" if sample else "VAR_POP"
199
+ super().__init__(expression, **extra)
200
+
201
+ def _get_repr_options(self):
202
+ return {**super()._get_repr_options(), "sample": self.function == "VAR_SAMP"}
@@ -0,0 +1 @@
1
+ # Backends
File without changes