plain.models 0.41.1__py3-none-any.whl → 0.43.0__py3-none-any.whl

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.
plain/models/query.py CHANGED
@@ -255,9 +255,8 @@ class FlatValuesListIterable(BaseIterable):
255
255
  class QuerySet:
256
256
  """Represent a lazy database lookup for a set of objects."""
257
257
 
258
- def __init__(self, model=None, query=None, hints=None):
258
+ def __init__(self, *, model=None, query=None):
259
259
  self.model = model
260
- self._hints = hints or {}
261
260
  self._query = query or sql.Query(self.model)
262
261
  self._result_cache = None
263
262
  self._sticky_filter = False
@@ -284,17 +283,6 @@ class QuerySet:
284
283
  self._iterable_class = ValuesIterable
285
284
  self._query = value
286
285
 
287
- def as_manager(cls):
288
- # Address the circular dependency between `Queryset` and `Manager`.
289
- from plain.models.manager import Manager
290
-
291
- manager = Manager.from_queryset(cls)()
292
- manager._built_with_as_manager = True
293
- return manager
294
-
295
- as_manager.queryset_only = True
296
- as_manager = classmethod(as_manager)
297
-
298
286
  ########################
299
287
  # PYTHON MAGIC METHODS #
300
288
  ########################
@@ -425,12 +413,12 @@ class QuerySet:
425
413
  query = (
426
414
  self
427
415
  if self.query.can_filter()
428
- else self.model._base_manager.filter(id__in=self.values("id"))
416
+ else self.model._meta.base_queryset.filter(id__in=self.values("id"))
429
417
  )
430
418
  combined = query._chain()
431
419
  combined._merge_known_related_objects(other)
432
420
  if not other.query.can_filter():
433
- other = other.model._base_manager.filter(id__in=other.values("id"))
421
+ other = other.model._meta.base_queryset.filter(id__in=other.values("id"))
434
422
  combined.query.combine(other.query, sql.OR)
435
423
  return combined
436
424
 
@@ -444,12 +432,12 @@ class QuerySet:
444
432
  query = (
445
433
  self
446
434
  if self.query.can_filter()
447
- else self.model._base_manager.filter(id__in=self.values("id"))
435
+ else self.model._meta.base_queryset.filter(id__in=self.values("id"))
448
436
  )
449
437
  combined = query._chain()
450
438
  combined._merge_known_related_objects(other)
451
439
  if not other.query.can_filter():
452
- other = other.model._base_manager.filter(id__in=other.values("id"))
440
+ other = other.model._meta.base_queryset.filter(id__in=other.values("id"))
453
441
  combined.query.combine(other.query, sql.XOR)
454
442
  return combined
455
443
 
@@ -957,8 +945,6 @@ class QuerySet:
957
945
  self._result_cache = None
958
946
  return deleted, _rows_count
959
947
 
960
- delete.queryset_only = True
961
-
962
948
  def _raw_delete(self):
963
949
  """
964
950
  Delete objects found from the given queryset in single direct SQL
@@ -1027,8 +1013,6 @@ class QuerySet:
1027
1013
  self._result_cache = None
1028
1014
  return query.get_compiler().execute_sql(CURSOR)
1029
1015
 
1030
- _update.queryset_only = False
1031
-
1032
1016
  def exists(self):
1033
1017
  """
1034
1018
  Return True if the QuerySet would have any results, False otherwise.
@@ -1201,7 +1185,7 @@ class QuerySet:
1201
1185
  def all(self):
1202
1186
  """
1203
1187
  Return a new QuerySet that is a copy of the current one. This allows a
1204
- QuerySet to proxy for a model manager in some cases.
1188
+ QuerySet to proxy for a model queryset in some cases.
1205
1189
  """
1206
1190
  return self._chain()
1207
1191
 
@@ -1565,8 +1549,6 @@ class QuerySet:
1565
1549
  query.insert_values(fields, objs, raw=raw)
1566
1550
  return query.get_compiler().execute_sql(returning_fields)
1567
1551
 
1568
- _insert.queryset_only = False
1569
-
1570
1552
  def _batched_insert(
1571
1553
  self,
1572
1554
  objs,
@@ -1622,7 +1604,6 @@ class QuerySet:
1622
1604
  c = self.__class__(
1623
1605
  model=self.model,
1624
1606
  query=self.query.chain(),
1625
- hints=self._hints,
1626
1607
  )
1627
1608
  c._sticky_filter = self._sticky_filter
1628
1609
  c._for_write = self._for_write
@@ -1678,15 +1659,6 @@ class QuerySet:
1678
1659
  query = self.query.resolve_expression(*args, **kwargs)
1679
1660
  return query
1680
1661
 
1681
- resolve_expression.queryset_only = True
1682
-
1683
- def _add_hints(self, **hints):
1684
- """
1685
- Update hinting information for use by routers. Add new key/values or
1686
- overwrite existing key/values.
1687
- """
1688
- self._hints.update(hints)
1689
-
1690
1662
  def _has_filters(self):
1691
1663
  """
1692
1664
  Check if this QuerySet has any filtering going on. This isn't
@@ -1747,11 +1719,9 @@ class RawQuerySet:
1747
1719
  query=None,
1748
1720
  params=(),
1749
1721
  translations=None,
1750
- hints=None,
1751
1722
  ):
1752
1723
  self.raw_query = raw_query
1753
1724
  self.model = model
1754
- self._hints = hints or {}
1755
1725
  self.query = query or sql.RawQuery(sql=raw_query, params=params)
1756
1726
  self.params = params
1757
1727
  self.translations = translations or {}
@@ -1797,7 +1767,6 @@ class RawQuerySet:
1797
1767
  query=self.query,
1798
1768
  params=self.params,
1799
1769
  translations=self.translations,
1800
- hints=self._hints,
1801
1770
  )
1802
1771
  c._prefetch_related_lookups = self._prefetch_related_lookups[:]
1803
1772
  return c
@@ -2180,7 +2149,7 @@ def prefetch_one_level(instances, prefetcher, lookup, level):
2180
2149
  for additional_lookup in getattr(rel_qs, "_prefetch_related_lookups", ())
2181
2150
  ]
2182
2151
  if additional_lookups:
2183
- # Don't need to clone because the manager should have given us a fresh
2152
+ # Don't need to clone because the queryset should have given us a fresh
2184
2153
  # instance, so we access an internal instead of using public interface
2185
2154
  # for performance reasons.
2186
2155
  rel_qs._prefetch_related_lookups = ()
@@ -2231,11 +2200,11 @@ def prefetch_one_level(instances, prefetcher, lookup, level):
2231
2200
  if as_attr:
2232
2201
  setattr(obj, to_attr, vals)
2233
2202
  else:
2234
- manager = getattr(obj, to_attr)
2203
+ queryset = getattr(obj, to_attr)
2235
2204
  if leaf and lookup.queryset is not None:
2236
- qs = manager._apply_rel_filters(lookup.queryset)
2205
+ qs = queryset._apply_rel_filters(lookup.queryset)
2237
2206
  else:
2238
- qs = manager.get_queryset()
2207
+ qs = queryset.__class__(model=queryset.model)
2239
2208
  qs._result_cache = vals
2240
2209
  # We don't want the individual qs doing prefetch_related now,
2241
2210
  # since we have merged this into the current work.
@@ -361,7 +361,7 @@ def check_rel_lookup_compatibility(model, target_opts, field):
361
361
  # model is ok, too. Consider the case:
362
362
  # class Restaurant(models.Model):
363
363
  # place = OneToOneField(Place, primary_key=True):
364
- # Restaurant.objects.filter(id__in=Restaurant.objects.all()).
364
+ # Restaurant.query.filter(id__in=Restaurant.query.all()).
365
365
  # If we didn't have the primary key check, then id__in (== place__in) would
366
366
  # give Place's opts as the target opts, but Restaurant isn't compatible
367
367
  # with that. This logic applies only to primary keys, as when doing __in=qs,
@@ -98,20 +98,20 @@ class SQLCompiler:
98
98
  then it is correct".
99
99
  """
100
100
  # Some examples:
101
- # SomeModel.objects.annotate(Count('somecol'))
101
+ # SomeModel.query.annotate(Count('somecol'))
102
102
  # GROUP BY: all fields of the model
103
103
  #
104
- # SomeModel.objects.values('name').annotate(Count('somecol'))
104
+ # SomeModel.query.values('name').annotate(Count('somecol'))
105
105
  # GROUP BY: name
106
106
  #
107
- # SomeModel.objects.annotate(Count('somecol')).values('name')
107
+ # SomeModel.query.annotate(Count('somecol')).values('name')
108
108
  # GROUP BY: all cols of the model
109
109
  #
110
- # SomeModel.objects.values('name', 'id')
110
+ # SomeModel.query.values('name', 'id')
111
111
  # .annotate(Count('somecol')).values('id')
112
112
  # GROUP BY: name, id
113
113
  #
114
- # SomeModel.objects.values('name').annotate(Count('somecol')).values('id')
114
+ # SomeModel.query.values('name').annotate(Count('somecol')).values('id')
115
115
  # GROUP BY: name, id
116
116
  #
117
117
  # In fact, the self.query.group_by is the minimal set to GROUP BY. It
plain/models/sql/query.py CHANGED
@@ -1174,9 +1174,9 @@ class Query(BaseExpression):
1174
1174
  """Check the type of object passed to query relations."""
1175
1175
  if field.is_relation:
1176
1176
  # Check that the field and the queryset use the same model in a
1177
- # query like .filter(author=Author.objects.all()). For example, the
1177
+ # query like .filter(author=Author.query.all()). For example, the
1178
1178
  # opts would be Author's (from the author field) and value.model
1179
- # would be Author.objects.all() queryset's .model (Author also).
1179
+ # would be Author.query.all() queryset's .model (Author also).
1180
1180
  # The field is the related field on the lhs side.
1181
1181
  if (
1182
1182
  isinstance(value, Query)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plain.models
3
- Version: 0.41.1
3
+ Version: 0.43.0
4
4
  Summary: Model your data and store it in a database.
5
5
  Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
6
6
  License-File: LICENSE
@@ -20,7 +20,7 @@ Description-Content-Type: text/markdown
20
20
  - [Fields](#fields)
21
21
  - [Validation](#validation)
22
22
  - [Indexes and constraints](#indexes-and-constraints)
23
- - [Managers](#managers)
23
+ - [Custom QuerySets](#custom-querysets)
24
24
  - [Forms](#forms)
25
25
  - [Sharing fields across models](#sharing-fields-across-models)
26
26
  - [Installation](#installation)
@@ -54,7 +54,7 @@ from .models import User
54
54
 
55
55
 
56
56
  # Create a new user
57
- user = User.objects.create(
57
+ user = User.query.create(
58
58
  email="test@example.com",
59
59
  password="password",
60
60
  )
@@ -67,7 +67,7 @@ user.save()
67
67
  user.delete()
68
68
 
69
69
  # Query for users
70
- admin_users = User.objects.filter(is_admin=True)
70
+ admin_users = User.query.filter(is_admin=True)
71
71
  ```
72
72
 
73
73
  ## Database connection
@@ -96,30 +96,30 @@ Multiple backends are supported, including Postgres, MySQL, and SQLite.
96
96
 
97
97
  ## Querying
98
98
 
99
- Models come with a powerful query API through their [`Manager`](./manager.py#Manager) interface:
99
+ Models come with a powerful query API through their [`QuerySet`](./query.py#QuerySet) interface:
100
100
 
101
101
  ```python
102
102
  # Get all users
103
- all_users = User.objects.all()
103
+ all_users = User.query.all()
104
104
 
105
105
  # Filter users
106
- admin_users = User.objects.filter(is_admin=True)
107
- recent_users = User.objects.filter(created_at__gte=datetime.now() - timedelta(days=7))
106
+ admin_users = User.query.filter(is_admin=True)
107
+ recent_users = User.query.filter(created_at__gte=datetime.now() - timedelta(days=7))
108
108
 
109
109
  # Get a single user
110
- user = User.objects.get(email="test@example.com")
110
+ user = User.query.get(email="test@example.com")
111
111
 
112
112
  # Complex queries with Q objects
113
113
  from plain.models import Q
114
- users = User.objects.filter(
114
+ users = User.query.filter(
115
115
  Q(is_admin=True) | Q(email__endswith="@example.com")
116
116
  )
117
117
 
118
118
  # Ordering
119
- users = User.objects.order_by("-created_at")
119
+ users = User.query.order_by("-created_at")
120
120
 
121
121
  # Limiting results
122
- first_10_users = User.objects.all()[:10]
122
+ first_10_users = User.query.all()[:10]
123
123
  ```
124
124
 
125
125
  For more advanced querying options, see the [`QuerySet`](./query.py#QuerySet) class.
@@ -222,28 +222,71 @@ class User(models.Model):
222
222
  ]
223
223
  ```
224
224
 
225
- ## Managers
225
+ ## Custom QuerySets
226
226
 
227
- [`Manager`](./manager.py#Manager) objects provide the interface for querying models:
227
+ With the Manager functionality now merged into QuerySet, you can customize [`QuerySet`](./query.py#QuerySet) classes to provide specialized query methods. There are several ways to use custom QuerySets:
228
+
229
+ ### Setting a default QuerySet for a model
230
+
231
+ Use `Meta.queryset_class` to set a custom QuerySet that will be used by `Model.query`:
232
+
233
+ ```python
234
+ class PublishedQuerySet(models.QuerySet):
235
+ def published_only(self):
236
+ return self.filter(status="published")
237
+
238
+ def draft_only(self):
239
+ return self.filter(status="draft")
240
+
241
+ @models.register_model
242
+ class Article(models.Model):
243
+ title = models.CharField(max_length=200)
244
+ status = models.CharField(max_length=20)
245
+
246
+ class Meta:
247
+ queryset_class = PublishedQuerySet
248
+
249
+ # Usage - all methods available on Article.objects
250
+ all_articles = Article.query.all()
251
+ published_articles = Article.query.published_only()
252
+ draft_articles = Article.query.draft_only()
253
+ ```
254
+
255
+ ### Using custom QuerySets without formal attachment
256
+
257
+ You can also use custom QuerySets manually without setting them as the default:
228
258
 
229
259
  ```python
230
- class PublishedManager(models.Manager):
231
- def get_queryset(self):
232
- return super().get_queryset().filter(status="published")
260
+ class SpecialQuerySet(models.QuerySet):
261
+ def special_filter(self):
262
+ return self.filter(special=True)
233
263
 
264
+ # Create and use the QuerySet manually
265
+ special_qs = SpecialQuerySet(model=Article)
266
+ special_articles = special_qs.special_filter()
267
+ ```
268
+
269
+ ### Using classmethods for convenience
270
+
271
+ For even cleaner API, add classmethods to your model:
272
+
273
+ ```python
274
+ @models.register_model
234
275
  class Article(models.Model):
235
276
  title = models.CharField(max_length=200)
236
277
  status = models.CharField(max_length=20)
237
278
 
238
- # Default manager
239
- objects = models.Manager()
279
+ @classmethod
280
+ def published(cls):
281
+ return PublishedQuerySet(model=cls).published_only()
240
282
 
241
- # Custom manager
242
- published = PublishedManager()
283
+ @classmethod
284
+ def drafts(cls):
285
+ return PublishedQuerySet(model=cls).draft_only()
243
286
 
244
287
  # Usage
245
- all_articles = Article.objects.all()
246
- published_articles = Article.published.all()
288
+ published_articles = Article.published()
289
+ draft_articles = Article.drafts()
247
290
  ```
248
291
 
249
292
  ## Forms
@@ -1,31 +1,30 @@
1
1
  plain/models/AGENTS.md,sha256=xQQW-z-DehnCUyjiGSBfLqUjoSUdo_W1b0JmwYmWieA,209
2
- plain/models/CHANGELOG.md,sha256=NMKkqzD7d6x3kmJzOL0-3qHGjBlFur1pX39ZR7w2i4Y,11169
3
- plain/models/README.md,sha256=uibhtLwH-JUGzpW3tCFUrQo19i2RAvet1EkpyItdFxM,7269
4
- plain/models/__init__.py,sha256=LJhlJauhTfUySY2hTJ9qBhCbEKMxTDKpeVrjYXZnsCw,2964
2
+ plain/models/CHANGELOG.md,sha256=yPHtgiBY7hwtydus3mAiT945vgMTO5c9pF64KC9V37s,14530
3
+ plain/models/README.md,sha256=lqzWJrEIxBCHC1P8X1YoRjbsMFlu0-kG4ujP76B_ZO4,8572
4
+ plain/models/__init__.py,sha256=aB9HhIKBh0iK3LZztInAE-rDF-yKsdfcjfMtwtN5vnI,2920
5
5
  plain/models/aggregates.py,sha256=P0mhsMl1VZt2CVHMuCHnNI8SxZ9citjDLEgioN6NOpo,7240
6
- plain/models/base.py,sha256=FJlWJ_LUdjk3Bizi45R4IsYzcuLAoiUHS-R3FxxNmWk,66857
7
- plain/models/cli.py,sha256=f6VF49l4wWtPn8feTF6IL6qIrcYxk3x9nTf03BOWSp4,36564
6
+ plain/models/base.py,sha256=Yp08EC4I0wQ65AXGNUe3mgM01zmuJ6B6XfFyCkcsmEc,66161
7
+ plain/models/cli.py,sha256=lhvlw7DVOU3CVoMUpHaj7qIbQ2d6qtSm_l9PdCeCnc0,36404
8
8
  plain/models/config.py,sha256=OF7eIEtXNZyGwgc3eMEpb5uEAup5RXeT-0um60dfBeU,636
9
9
  plain/models/connections.py,sha256=RBNa2FZ0x3C9un6PaYL-IYzH_OesRSpdHNGKvYHGiOM,2276
10
10
  plain/models/constants.py,sha256=ndnj9TOTKW0p4YcIPLOLEbsH6mOgFi6B1-rIzr_iwwU,210
11
- plain/models/constraints.py,sha256=EoJ4kuV_7f-VDiOVMHrAybr6uTDblNykTg0YCtgOboo,16760
11
+ plain/models/constraints.py,sha256=Mm9gm5D7EKmo486dL481-hrTcxi2gxgqyUUtbGrkLjs,16749
12
12
  plain/models/database_url.py,sha256=iidKVhOylf5N6t1EMPRySRQiv6LiuRjYRECB_UJ3MI8,6419
13
13
  plain/models/db.py,sha256=FpdfLYrRX2THUzDy4QdJ_OpSo9IFKLerZIEQ-T2x8zA,1348
14
14
  plain/models/default_settings.py,sha256=cDym1o_DtHySWgDRIdjgEM0YxjgYU51ZqzWVA3vpzTk,569
15
- plain/models/deletion.py,sha256=_S38TDd0TbsVKvmhutpeoZZt2AeA-4HFDpJweVFzaAM,17601
15
+ plain/models/deletion.py,sha256=3eW3bb39NbIlIAp4ZAEtSZuiy9oH4i5e83OK_8oIaxI,17607
16
16
  plain/models/entrypoints.py,sha256=EC14mW19tK9dCumaNHnv4_9jQV8jomQ8jXy8Ib89VBw,191
17
17
  plain/models/enums.py,sha256=Zr-JKt2aeYsSADtAm69fDRfajS7jYwop2vWQVLJ9YYI,2726
18
18
  plain/models/exceptions.py,sha256=IqzK60-hY3TYsgOMxlWwgpVa21E7ydC-gqUG4tNvVJc,2042
19
19
  plain/models/expressions.py,sha256=hN6sfOxqxpP0qmYOUotsFAAn2-bnl35iHwyINyXA7CI,62763
20
- plain/models/forms.py,sha256=FUBgt1P-4JmSQeigdITYqZPYqDI89XZQfPtdr8ffgsc,25816
20
+ plain/models/forms.py,sha256=VreclYMITYh3D-sfZV3iSQH9QjNmwNwIYQL_90owOVM,25805
21
21
  plain/models/indexes.py,sha256=fazIZPJgCX5_Bhwk7MQy3YbWOxpHvaCe1dDLGGldTuY,11540
22
22
  plain/models/lookups.py,sha256=eCsxQXUcOoAa_U_fAAd3edcgXI1wfyFW8hPgUh8TwTo,24776
23
- plain/models/manager.py,sha256=zc2W-vTTk3zkDXCds5-TCXgLhVmM4PdQb-qtu-njeLQ,5827
24
- plain/models/options.py,sha256=1EtFAXG3RqwoT8DzRKUmZvfXlhk98MvCf4q4FG6jBN4,23572
23
+ plain/models/options.py,sha256=BOnu9NDVcgL0tJhan5gBbaK1SWNeg4NVTPNAzkKT3NE,21528
25
24
  plain/models/otel.py,sha256=36QSJS6UXv1YPJTqeSmEvdMVHRkXa_zgqqItJaXc59g,7619
26
25
  plain/models/preflight.py,sha256=PlS1S2YHEpSKZ57KbTP6TbED98dDDXYSBUk6xMIpgsI,8136
27
- plain/models/query.py,sha256=i9wDYzi3hjlLSjUih3yykwERLZT23m1gZ56jqmZth7Y,90520
28
- plain/models/query_utils.py,sha256=Ny7PZJ5GduDrdzAT2ALtcKge780QP3w-ARTBqHNOu6U,14178
26
+ plain/models/query.py,sha256=6t0ow7oQfVB6WiC3fQ3kLme8TBeSOscEt5xl2lu6oOQ,89703
27
+ plain/models/query_utils.py,sha256=zxAdfwDbOmaN_SJODl4Wl9gs-q2EzOjXbsBFTWWhh8g,14174
29
28
  plain/models/registry.py,sha256=5yxVgT_W8GlyL2bsGT2HvMQB5sKolXucP2qrhr7Wlnk,8126
30
29
  plain/models/transaction.py,sha256=KqkRDT6aqMgbPA_ch7qO8a9NyDvwY_2FaxM7FkBkcgY,9357
31
30
  plain/models/utils.py,sha256=rD47CAMH4SsznTe-kUnRUdnaZeZHVv1fwLUiU3KOFW0,1630
@@ -72,13 +71,14 @@ plain/models/backups/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
72
71
  plain/models/backups/cli.py,sha256=AKVh_Go0LxnxFi2jQjmpPEbbJvYCurjJsGCWESm1X8A,2960
73
72
  plain/models/backups/clients.py,sha256=WQ4X4KrkNeiKYJcpGRwnfRiAeeyduHWEnq4tA4mtjvw,4047
74
73
  plain/models/backups/core.py,sha256=09IZUhBEe1Yej3PC8AidtkaI0c8tt7VnqGBCWK-WrFg,3318
75
- plain/models/fields/__init__.py,sha256=PcricU7Z5qxIw-RIJhVZlMgHWWSJStJjuzU6l0P82uk,77949
74
+ plain/models/fields/__init__.py,sha256=HrGTFOeG8Bt5pHWmiClmdn1qZcvCOIcXx4a5RKiIdr4,77938
76
75
  plain/models/fields/json.py,sha256=OdGW4EYBSHQgkuugB-EiIXOqGstUqcMKUvOTOVUHqEQ,18049
77
76
  plain/models/fields/mixins.py,sha256=K_ocrSbb6pPuGwYZeqgzoZskwCIMFIB6IV3T5CrU5J0,1805
78
- plain/models/fields/related.py,sha256=7Zbpz17zzmMwg9jBQhwPH-dyAW01ClaQGJMMwbArWCM,51027
79
- plain/models/fields/related_descriptors.py,sha256=VRWNdR4ptXwxQ0jyBajPV9h2Gv5jc5lzBDl9XZgT4Xk,39094
80
- plain/models/fields/related_lookups.py,sha256=rtDTS-GvN4goka7CP36dMg1ayUyOEAE39VKXyRMV5g0,7785
81
- plain/models/fields/reverse_related.py,sha256=AqHPSx1tZ6uj9rESyy1tN1qT415N7eifkgKZHJZWH2k,10767
77
+ plain/models/fields/related.py,sha256=W5pvb_J0AulyQmd-q8Vzh4b9GT7IDmeAaJNCZhsMqkw,49698
78
+ plain/models/fields/related_descriptors.py,sha256=nsVgLjpOlrha90eTfg7ad_il6_uI_YG0d4bH51LP3Os,15180
79
+ plain/models/fields/related_lookups.py,sha256=9y6AfEcg8xRRZne2LXFP6jym9mecFlB_toYih7lD8Uw,7781
80
+ plain/models/fields/related_managers.py,sha256=XiV2IvuEFLEWnej2KokCu6HFx87UyZTqqsP74v2xIHw,25011
81
+ plain/models/fields/reverse_related.py,sha256=SNFytCI3BeAlB5kY6UQrv6QGqtRMo_aHWPx_-fCkfu4,10404
82
82
  plain/models/functions/__init__.py,sha256=aglCm_JtzDYk2KmxubDN_78CGG3JCfRWnfJ74Oj5YJ4,2658
83
83
  plain/models/functions/comparison.py,sha256=9uAiEuNXZiGFzJKBvktsHwx58Qpa2cPQkr6pUWsGcKo,6554
84
84
  plain/models/functions/datetime.py,sha256=ov1H0Oq9qHSeu8L5CZsln0_SMU2C5M_P5HvKxppA24o,13089
@@ -87,7 +87,7 @@ plain/models/functions/mixins.py,sha256=s6H0Ejugo8707EnxN6zS4givmTbPrFuk3Q_mqCGQ
87
87
  plain/models/functions/text.py,sha256=Vn4Rh-cVJCL4NUaBcj72cwHa6yHap5ql0XPwn0-K_tc,8908
88
88
  plain/models/functions/window.py,sha256=3S0QIZc_pIVcWpE5Qq-OxixmtATLb8rZrWkvCfVtJ7Q,2809
89
89
  plain/models/migrations/__init__.py,sha256=ZAQUGrfr_OxYMIO7vUBIHLs_M3oZ4iQSjDzCHRFUdtI,96
90
- plain/models/migrations/autodetector.py,sha256=8GpvNHdtTshKB05YiP2AWy4Vw5a2ClAm0peA4K7_-WE,61780
90
+ plain/models/migrations/autodetector.py,sha256=MuJEVaU9IZ8c6HfcDsEANNujUrSGMN-iDd5WDPM7ht8,60957
91
91
  plain/models/migrations/exceptions.py,sha256=_bGjIMaBP2Py9ePUxUhiH0p1zXrQM4JhJO4lWfyF8-g,1044
92
92
  plain/models/migrations/executor.py,sha256=2_1bWM7Dp3s8z6PADAEN-Y0KnIiRzAqsUkn_nRQl5TA,6757
93
93
  plain/models/migrations/graph.py,sha256=nrztu_8dU0wAUSxKUqqFWpvZcSQxGEqE6dXWkPytmCU,12570
@@ -95,28 +95,28 @@ plain/models/migrations/loader.py,sha256=qUTmaEYI1_mV6goQPQYZKjSz8rMbE6G1wqvrAsm
95
95
  plain/models/migrations/migration.py,sha256=22YwRHnaRnCkBpW5p7K89tAU6h4QSsG5yiq-o7W-cSI,6505
96
96
  plain/models/migrations/optimizer.py,sha256=HH-uz-jnWw_Ni6F2_rRW1nax1Dxmf1s_F_8s8N2OlVc,3266
97
97
  plain/models/migrations/questioner.py,sha256=qAsePI5JHiSJrlY_kmpgMuK9Dom22q17edov7RtBeGw,11967
98
- plain/models/migrations/recorder.py,sha256=9UfNdzM5meeOXSxMNxTN69uqX0K2uh5Ma7dNA2fL2rI,3655
99
- plain/models/migrations/serializer.py,sha256=IRO1-8ojalOFt27DSfCDhRWjTULQZQ-aSroL-A9MPbk,12947
100
- plain/models/migrations/state.py,sha256=hlHp__1w-oVAeSfoZliaOBTxnjGL3C-C3iJF9_hXdjw,34484
98
+ plain/models/migrations/recorder.py,sha256=_ncIVLJ4ns6AaO0vVmCoXfABlOFXDKu8NTPsutqKjK4,3653
99
+ plain/models/migrations/serializer.py,sha256=yBP9TyUZlSh_8qdw1I4VotbsZqoomz3mBs7ASQLsDH8,12459
100
+ plain/models/migrations/state.py,sha256=Q70cByjFgb8UG-wWqnLntf5s0hNv5DuDv0Bw1ovJ0yg,32116
101
101
  plain/models/migrations/utils.py,sha256=Ih_mu6UbdUSt-ZtHaB0xIXHDrBANuFZyftTQ56BFJYs,4174
102
102
  plain/models/migrations/writer.py,sha256=N8Rnjv5ccsA_CTcS7zZyppzyHFOUQVJy0l6RZYjwF-0,10981
103
- plain/models/migrations/operations/__init__.py,sha256=C8VTJbzvFgt7AXTPvtuY8HF1FC8rqNvsXMOCW26UV9E,802
103
+ plain/models/migrations/operations/__init__.py,sha256=YKZsQsJ4G5iw9F4o6dOSgSCuLiiKuApvneoV4jqjZaA,752
104
104
  plain/models/migrations/operations/base.py,sha256=JsKGjM6ouvEbFHzV14km7YjkpOUC4PoUR1M2yGZ82bE,4323
105
105
  plain/models/migrations/operations/fields.py,sha256=ARL945rbztAnMsbd0lvQRsQJEmxYA3gDof0-4aOTeC4,11255
106
- plain/models/migrations/operations/models.py,sha256=kZc9zYK3Q3NyLV98oj-RYRyocIbFdt4QNyryOrQJAMM,26830
107
- plain/models/migrations/operations/special.py,sha256=SiL_7u3rSj35uhc8JPmFHtItt_k_EgbLhY-TEXfmkaI,5162
106
+ plain/models/migrations/operations/models.py,sha256=jwhck8ygfi8cW8baVeGUB6coVVv4HnGVSFVb2IW_aTU,24947
107
+ plain/models/migrations/operations/special.py,sha256=cKieE9AQcFrpvEw5_TJCum56uu6cfN1p-azY7sKdB7E,4944
108
108
  plain/models/sql/__init__.py,sha256=FoRCcab-kh_XY8C4eldgLy9-zuk-M63Nyi9cFsYjclU,225
109
- plain/models/sql/compiler.py,sha256=UzqJljjKfjidz8TW0tr8CucLF2Y0xmdsW9Rpnm_1Sc4,84701
109
+ plain/models/sql/compiler.py,sha256=FVa_v4Q8izuFc9VQTrW4jAqM1uqRnTVdOeP7IKt3yM8,84691
110
110
  plain/models/sql/constants.py,sha256=usb1LSh9WNGPsurWAGppDkV0wYJJg5GEegKibQdS718,533
111
111
  plain/models/sql/datastructures.py,sha256=FC88CVCukLyU621JrmKLBhmgvotEHgAhIOYfVvJpuR0,7084
112
- plain/models/sql/query.py,sha256=_CiouANls_2qgDxvftKXOzhsOx9FWhUJ5j2rE2-PGm0,108749
112
+ plain/models/sql/query.py,sha256=ASR6jeRTjGlnO5E_hb5cnUYQH2_JrpHa_M545xOG7dg,108745
113
113
  plain/models/sql/subqueries.py,sha256=1YYlgoDrx_mW19MWWawLdgDTJnLgvvkGBQ30YQ702W4,5860
114
114
  plain/models/sql/where.py,sha256=ezE9Clt2BmKo-I7ARsgqZ_aVA-1UdayCwr6ULSWZL6c,12635
115
115
  plain/models/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
116
116
  plain/models/test/pytest.py,sha256=KD5-mxonBxOYIhUh9Ql5uJOIiC9R4t-LYfb6sjA0UdE,3486
117
117
  plain/models/test/utils.py,sha256=S3d6zf3OFWDxB_kBJr0tDvwn51bjwDVWKPumv37N-p8,467
118
- plain_models-0.41.1.dist-info/METADATA,sha256=enNWwlsqHqqrPDy5uzkFcxfT4bcRO4lYKMjN7W7M6hI,7581
119
- plain_models-0.41.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
120
- plain_models-0.41.1.dist-info/entry_points.txt,sha256=IYJAW9MpL3PXyXFWmKmALagAGXC_5rzBn2eEGJlcV04,112
121
- plain_models-0.41.1.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
122
- plain_models-0.41.1.dist-info/RECORD,,
118
+ plain_models-0.43.0.dist-info/METADATA,sha256=1lUO79n5x4G0s1FzZinEIm5izVs3R-ii1NOR8ecaHvA,8884
119
+ plain_models-0.43.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
120
+ plain_models-0.43.0.dist-info/entry_points.txt,sha256=IYJAW9MpL3PXyXFWmKmALagAGXC_5rzBn2eEGJlcV04,112
121
+ plain_models-0.43.0.dist-info/licenses/LICENSE,sha256=m0D5O7QoH9l5Vz_rrX_9r-C8d9UNr_ciK6Qwac7o6yo,3175
122
+ plain_models-0.43.0.dist-info/RECORD,,
plain/models/manager.py DELETED
@@ -1,176 +0,0 @@
1
- import inspect
2
- from functools import wraps
3
- from importlib import import_module
4
-
5
- from plain.models.query import QuerySet
6
-
7
-
8
- class BaseManager:
9
- # To retain order, track each time a Manager instance is created.
10
- creation_counter = 0
11
-
12
- # Set to True for the 'objects' managers that are automatically created.
13
- auto_created = False
14
-
15
- #: If set to True the manager will be serialized into migrations and will
16
- #: thus be available in e.g. RunPython operations.
17
- use_in_migrations = False
18
-
19
- def __new__(cls, *args, **kwargs):
20
- # Capture the arguments to make returning them trivial.
21
- obj = super().__new__(cls)
22
- obj._constructor_args = (args, kwargs)
23
- return obj
24
-
25
- def __init__(self):
26
- super().__init__()
27
- self._set_creation_counter()
28
- self.model = None
29
- self.name = None
30
- self._hints = {}
31
-
32
- def __str__(self):
33
- """Return "package_label.model_label.manager_name"."""
34
- return f"{self.model._meta.label}.{self.name}"
35
-
36
- def __class_getitem__(cls, *args, **kwargs):
37
- return cls
38
-
39
- def deconstruct(self):
40
- """
41
- Return a 5-tuple of the form (as_manager (True), manager_class,
42
- queryset_class, args, kwargs).
43
-
44
- Raise a ValueError if the manager is dynamically generated.
45
- """
46
- qs_class = self._queryset_class
47
- if getattr(self, "_built_with_as_manager", False):
48
- # using MyQuerySet.as_manager()
49
- return (
50
- True, # as_manager
51
- None, # manager_class
52
- f"{qs_class.__module__}.{qs_class.__name__}", # qs_class
53
- None, # args
54
- None, # kwargs
55
- )
56
- else:
57
- module_name = self.__module__
58
- name = self.__class__.__name__
59
- # Make sure it's actually there and not an inner class
60
- module = import_module(module_name)
61
- if not hasattr(module, name):
62
- raise ValueError(
63
- f"Could not find manager {name} in {module_name}.\n"
64
- "Please note that you need to inherit from managers you "
65
- "dynamically generated with 'from_queryset()'."
66
- )
67
- return (
68
- False, # as_manager
69
- f"{module_name}.{name}", # manager_class
70
- None, # qs_class
71
- self._constructor_args[0], # args
72
- self._constructor_args[1], # kwargs
73
- )
74
-
75
- def check(self, **kwargs):
76
- return []
77
-
78
- @classmethod
79
- def _get_queryset_methods(cls, queryset_class):
80
- def create_method(name, method):
81
- @wraps(method)
82
- def manager_method(self, *args, **kwargs):
83
- return getattr(self.get_queryset(), name)(*args, **kwargs)
84
-
85
- return manager_method
86
-
87
- new_methods = {}
88
- for name, method in inspect.getmembers(
89
- queryset_class, predicate=inspect.isfunction
90
- ):
91
- # Only copy missing methods.
92
- if hasattr(cls, name):
93
- continue
94
- # Only copy public methods or methods with the attribute
95
- # queryset_only=False.
96
- queryset_only = getattr(method, "queryset_only", None)
97
- if queryset_only or (queryset_only is None and name.startswith("_")):
98
- continue
99
- # Copy the method onto the manager.
100
- new_methods[name] = create_method(name, method)
101
- return new_methods
102
-
103
- @classmethod
104
- def from_queryset(cls, queryset_class, class_name=None):
105
- if class_name is None:
106
- class_name = f"{cls.__name__}From{queryset_class.__name__}"
107
- return type(
108
- class_name,
109
- (cls,),
110
- {
111
- "_queryset_class": queryset_class,
112
- **cls._get_queryset_methods(queryset_class),
113
- },
114
- )
115
-
116
- def contribute_to_class(self, cls, name):
117
- self.name = self.name or name
118
- self.model = cls
119
-
120
- setattr(cls, name, ManagerDescriptor(self))
121
-
122
- cls._meta.add_manager(self)
123
-
124
- def _set_creation_counter(self):
125
- """
126
- Set the creation counter value for this instance and increment the
127
- class-level copy.
128
- """
129
- self.creation_counter = BaseManager.creation_counter
130
- BaseManager.creation_counter += 1
131
-
132
- #######################
133
- # PROXIES TO QUERYSET #
134
- #######################
135
-
136
- def get_queryset(self):
137
- """
138
- Return a new QuerySet object. Subclasses can override this method to
139
- customize the behavior of the Manager.
140
- """
141
- return self._queryset_class(model=self.model, hints=self._hints)
142
-
143
- def all(self):
144
- # We can't proxy this method through the `QuerySet` like we do for the
145
- # rest of the `QuerySet` methods. This is because `QuerySet.all()`
146
- # works by creating a "copy" of the current queryset and in making said
147
- # copy, all the cached `prefetch_related` lookups are lost. See the
148
- # implementation of `RelatedManager.get_queryset()` for a better
149
- # understanding of how this comes into play.
150
- return self.get_queryset()
151
-
152
- def __eq__(self, other):
153
- return (
154
- isinstance(other, self.__class__)
155
- and self._constructor_args == other._constructor_args
156
- )
157
-
158
- def __hash__(self):
159
- return id(self)
160
-
161
-
162
- class Manager(BaseManager.from_queryset(QuerySet)):
163
- pass
164
-
165
-
166
- class ManagerDescriptor:
167
- def __init__(self, manager):
168
- self.manager = manager
169
-
170
- def __get__(self, instance, cls=None):
171
- if instance is not None:
172
- raise AttributeError(
173
- f"Manager isn't accessible via {cls.__name__} instances"
174
- )
175
-
176
- return cls._meta.managers_map[self.manager.name]