Skip to content

Commit feccb05

Browse files
authored
Rename BaseModelMeta to TypedModelMeta and document it (#1456)
1 parent 3e81d11 commit feccb05

File tree

5 files changed

+36
-25
lines changed

5 files changed

+36
-25
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,28 @@ We rely on different `django` and `mypy` versions:
6969
| 1.1.0 | 0.720 | 2.2.x | ^3.6
7070
| 0.12.x | old semantic analyzer (<0.711), dmypy support | 2.1.x | ^3.6
7171

72+
## Features
73+
74+
### Type checking of Model Meta attributes
75+
76+
By inheriting from the `TypedModelMeta` class, you can ensure you're using correct types for
77+
attributes:
78+
79+
```python
80+
from django.db import models
81+
from django_stubs_ext.db.models import TypedModelMeta
82+
83+
class MyModel(models.Model):
84+
example = models.CharField(max_length=100)
85+
86+
class Meta(TypedModelMeta):
87+
ordering = ["example"]
88+
constraints = [
89+
models.UniqueConstraint(fields=["example"], name="unique_example"),
90+
]
91+
```
92+
93+
7294
## FAQ
7395

7496
### Is this an official Django project?

django_stubs_ext/django_stubs_ext/db/models.py

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,12 @@
88

99
from django_stubs_ext import StrOrPromise
1010

11-
class BaseModelMeta:
11+
class TypedModelMeta:
1212
"""
13-
Typed base class for Django Model `class Meta:` inner class.
13+
Typed base class for Django Model `class Meta:` inner class. At runtime this is just an alias to `object`.
1414
1515
Most attributes are the same as `django.db.models.options.Options`. Options has some additional attributes and
1616
some values are normalized by Django.
17-
18-
Usage::
19-
20-
from django.db import models
21-
from django_stubs_ext.db.models import BaseModelMeta
22-
23-
class MyModel(models.Model):
24-
example = models.CharField(max_length=100)
25-
26-
class Meta(BaseModelMeta):
27-
ordering = ["example"]
2817
"""
2918

3019
abstract: ClassVar[bool] # default: False
@@ -53,4 +42,4 @@ class Meta(BaseModelMeta):
5342
verbose_name_plural: ClassVar[StrOrPromise]
5443

5544
else:
56-
BaseModelMeta = object
45+
TypedModelMeta = object

tests/typecheck/managers/test_managers.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,15 @@
110110
content: |
111111
from typing import TypeVar
112112
from django.db import models
113-
from django_stubs_ext.db.models import BaseModelMeta
113+
from django_stubs_ext.db.models import TypedModelMeta
114114
115115
_T = TypeVar('_T', bound=models.Model)
116116
class Manager1(models.Manager[_T]):
117117
pass
118118
class Manager2(models.Manager[_T]):
119119
pass
120120
class MyModel(models.Model):
121-
class Meta(BaseModelMeta):
121+
class Meta(TypedModelMeta):
122122
default_manager_name = 'm2'
123123
m1 = Manager1['MyModel']()
124124
m2 = Manager2['MyModel']()

tests/typecheck/models/test_meta_options.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,22 +49,22 @@
4949
content: |
5050
from django.db import models
5151
from django.contrib.postgres.fields import ArrayField
52-
from django_stubs_ext.db.models import BaseModelMeta
52+
from django_stubs_ext.db.models import TypedModelMeta
5353
class AbstractModel(models.Model):
54-
class Meta(BaseModelMeta):
54+
class Meta(TypedModelMeta):
5555
abstract = True
5656
class MyModel(AbstractModel):
5757
field = ArrayField(models.IntegerField(), default=[])
5858
- case: base_model_meta_incompatible_types
5959
main: |
6060
from django.db import models
6161
from django.contrib.postgres.fields import ArrayField
62-
from django_stubs_ext.db.models import BaseModelMeta
62+
from django_stubs_ext.db.models import TypedModelMeta
6363
6464
class MyModel(models.Model):
6565
example = models.CharField(max_length=100)
66-
class Meta(BaseModelMeta):
67-
abstract = 7 # E: Incompatible types in assignment (expression has type "int", base class "BaseModelMeta" defined the type as "bool")
68-
verbose_name = ['test'] # E: Incompatible types in assignment (expression has type "List[str]", base class "BaseModelMeta" defined the type as "Union[str, _StrPromise]")
69-
unique_together = {1: 2} # E: Incompatible types in assignment (expression has type "Dict[int, int]", base class "BaseModelMeta" defined the type as "Union[Sequence[Sequence[str]], Sequence[str]]")
66+
class Meta(TypedModelMeta):
67+
abstract = 7 # E: Incompatible types in assignment (expression has type "int", base class "TypedModelMeta" defined the type as "bool")
68+
verbose_name = ['test'] # E: Incompatible types in assignment (expression has type "List[str]", base class "TypedModelMeta" defined the type as "Union[str, _StrPromise]")
69+
unique_together = {1: 2} # E: Incompatible types in assignment (expression has type "Dict[int, int]", base class "TypedModelMeta" defined the type as "Union[Sequence[Sequence[str]], Sequence[str]]")
7070
unknown_attr = True # can't check this

tests/typecheck/models/test_proxy_models.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
- path: myapp/models.py
1313
content: |
1414
from django.db import models
15-
from django_stubs_ext.db.models import BaseModelMeta
15+
from django_stubs_ext.db.models import TypedModelMeta
1616
1717
class Publisher(models.Model):
1818
pass
1919
class PublisherProxy(Publisher):
20-
class Meta(BaseModelMeta):
20+
class Meta(TypedModelMeta):
2121
proxy = True
2222
class Blog(models.Model):
2323
publisher = models.ForeignKey(to=PublisherProxy, on_delete=models.CASCADE)

0 commit comments

Comments
 (0)