Skip to content

Commit bbaee93

Browse files
committed
Merge Manager into QuerySet, except for related managers
1 parent 6b60a00 commit bbaee93

File tree

24 files changed

+615
-276
lines changed

24 files changed

+615
-276
lines changed

plain-admin/plain/admin/views/models.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from plain import models
44
from plain.exceptions import FieldError
5-
from plain.models import Manager, Q
5+
from plain.models import Q, QuerySet
66

77
from .objects import (
88
AdminCreateView,
@@ -35,8 +35,8 @@ def get_model_field(instance, field):
3535

3636
attr = getattr(instance, field)
3737

38-
if isinstance(attr, Manager):
39-
# Automatically get .all() of related managers
38+
if isinstance(attr, QuerySet):
39+
# Automatically get .all() of related querysets
4040
return attr.all()
4141

4242
return attr

plain-cache/plain/cache/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class CachedItem(models.Model):
2222
updated_at = models.DateTimeField(auto_now=True)
2323

2424
class Meta:
25-
manager_class = CachedItemQuerySet
25+
queryset_class = CachedItemQuerySet
2626
indexes = [
2727
models.Index(fields=["expires_at"]),
2828
]

plain-models/plain/models/README.md

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
- [Fields](#fields)
1010
- [Validation](#validation)
1111
- [Indexes and constraints](#indexes-and-constraints)
12-
- [Managers](#managers)
12+
- [Custom QuerySets](#custom-querysets)
1313
- [Forms](#forms)
1414
- [Sharing fields across models](#sharing-fields-across-models)
1515
- [Installation](#installation)
@@ -85,7 +85,7 @@ Multiple backends are supported, including Postgres, MySQL, and SQLite.
8585

8686
## Querying
8787

88-
Models come with a powerful query API through their [`Manager`](./manager.py#Manager) interface:
88+
Models come with a powerful query API through their [`QuerySet`](./query.py#QuerySet) interface:
8989

9090
```python
9191
# Get all users
@@ -211,28 +211,71 @@ class User(models.Model):
211211
]
212212
```
213213

214-
## Managers
214+
## Custom QuerySets
215215

216-
[`Manager`](./manager.py#Manager) objects provide the interface for querying models:
216+
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:
217+
218+
### Setting a default QuerySet for a model
219+
220+
Use `Meta.queryset_class` to set a custom QuerySet that will be used by `Model.objects`:
221+
222+
```python
223+
class PublishedQuerySet(models.QuerySet):
224+
def published_only(self):
225+
return self.filter(status="published")
226+
227+
def draft_only(self):
228+
return self.filter(status="draft")
229+
230+
@models.register_model
231+
class Article(models.Model):
232+
title = models.CharField(max_length=200)
233+
status = models.CharField(max_length=20)
234+
235+
class Meta:
236+
queryset_class = PublishedQuerySet
237+
238+
# Usage - all methods available on Article.objects
239+
all_articles = Article.objects.all()
240+
published_articles = Article.objects.published_only()
241+
draft_articles = Article.objects.draft_only()
242+
```
243+
244+
### Using custom QuerySets without formal attachment
245+
246+
You can also use custom QuerySets manually without setting them as the default:
217247

218248
```python
219-
class PublishedManager(models.Manager):
220-
def get_queryset(self):
221-
return super().get_queryset().filter(status="published")
249+
class SpecialQuerySet(models.QuerySet):
250+
def special_filter(self):
251+
return self.filter(special=True)
252+
253+
# Create and use the QuerySet manually
254+
special_qs = SpecialQuerySet(model=Article)
255+
special_articles = special_qs.special_filter()
256+
```
257+
258+
### Using classmethods for convenience
259+
260+
For even cleaner API, add classmethods to your model:
222261

262+
```python
263+
@models.register_model
223264
class Article(models.Model):
224265
title = models.CharField(max_length=200)
225266
status = models.CharField(max_length=20)
226267

227-
# Default manager
228-
objects = models.Manager()
268+
@classmethod
269+
def published(cls):
270+
return PublishedQuerySet(model=cls).published_only()
229271

230-
# Custom manager
231-
published = PublishedManager()
272+
@classmethod
273+
def drafts(cls):
274+
return PublishedQuerySet(model=cls).draft_only()
232275

233276
# Usage
234-
all_articles = Article.objects.all()
235-
published_articles = Article.published.all()
277+
published_articles = Article.published()
278+
draft_articles = Article.drafts()
236279
```
237280

238281
## Forms

plain-models/plain/models/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959
from .indexes import * # NOQA
6060
from .indexes import __all__ as indexes_all
6161
from .lookups import Lookup, Transform
62-
from .manager import Manager
6362
from .query import Prefetch, QuerySet, prefetch_related_objects
6463
from .query_utils import FilteredRelation, Q
6564
from .registry import models_registry, register_model
@@ -108,7 +107,6 @@
108107
"JSONField",
109108
"Lookup",
110109
"Transform",
111-
"Manager",
112110
"Prefetch",
113111
"Q",
114112
"QuerySet",

plain-models/plain/models/base.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def _prepare(cls):
169169

170170
@property
171171
def objects(cls):
172-
return cls._meta.manager
172+
return cls._meta.queryset
173173

174174

175175
class ModelStateFieldsCacheDescriptor:
@@ -422,9 +422,7 @@ def refresh_from_db(self, fields=None):
422422
"are not allowed in fields."
423423
)
424424

425-
db_instance_qs = self.__class__._meta.base_manager.get_queryset().filter(
426-
id=self.id
427-
)
425+
db_instance_qs = self.__class__._meta.base_queryset.filter(id=self.id)
428426

429427
# Use provided fields, if not set then reload all non-deferred fields.
430428
deferred_fields = self.get_deferred_fields()
@@ -607,7 +605,7 @@ def _save_table(
607605
force_insert = True
608606
# If possible, try an UPDATE. If that doesn't update anything, do an INSERT.
609607
if id_set and not force_insert:
610-
base_qs = meta.base_manager
608+
base_qs = meta.base_queryset
611609
values = [
612610
(
613611
f,
@@ -631,7 +629,7 @@ def _save_table(
631629
fields = [f for f in fields if f is not id_field]
632630

633631
returning_fields = meta.db_returning_fields
634-
results = self._do_insert(meta.base_manager, fields, returning_fields, raw)
632+
results = self._do_insert(meta.base_queryset, fields, returning_fields, raw)
635633
if results:
636634
for value, field in zip(results[0], returning_fields):
637635
setattr(self, field.attname, value)

plain-models/plain/models/deletion.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ def related_objects(self, related_model, related_fields, objs):
352352
[(f"{related_field.name}__in", objs) for related_field in related_fields],
353353
connector=query_utils.Q.OR,
354354
)
355-
return related_model._meta.base_manager.filter(predicate)
355+
return related_model._meta.base_queryset.filter(predicate)
356356

357357
def sort(self):
358358
sorted_models = []

plain-models/plain/models/fields/related.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ def validate(self, value, model_instance):
669669
if value is None:
670670
return
671671

672-
qs = self.remote_field.model._meta.base_manager.filter(
672+
qs = self.remote_field.model._meta.base_queryset.filter(
673673
**{self.remote_field.field_name: value}
674674
)
675675
qs = qs.complex_filter(self.get_limit_choices_to())

0 commit comments

Comments
 (0)