-
-
Notifications
You must be signed in to change notification settings - Fork 450
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
Add better support for ManyToManyField
's through
model
#1719
Conversation
d49d252
to
be1d46c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not a full review, just some questions.
Thanks for your work!
|
||
class ManyToManyField(RelatedField[Any, Any], Generic[_To, _M]): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make it generic on all the things and simplify our plugin a bit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which parts are you referring to?
The plugin only acts on what is _T
and _M
here, essentially the to=
and through=
argument on ManyToManyField
.
It does however have to sort some stuff out when there was no explicit through=
argument passed, as Django automatically generates a through model behind the scenes in that case.
Additionally it supports resolving lazy references e.g. "myapp.MyModel"
and replaces either _T
or _M
with any found model type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which parts are you referring to?
What I meant to say here was: which other parts should we make generic to simplify the plugin?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_GT, _ST
? Will it help?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, this changes so that those arguments aren't used at all any more, for ManyToManyField
. It's just the parent class that wants them.
The generics of the descriptor class does almost all the work now instead (except when through
is implicit, then the plugin does that part)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit hard to follow, but instead of using _GT
and _ST
and let our plugin do all the work, I've updated the descriptor class ManyToManyDescriptor
to become generic over a model, and that will be the through=
model for a ManyToManyField()
.
And if you now look a bit further, you find: ManyToManyDescriptor.through -> type[_M]
which means that the through=
argument align with the MyModel.m2m_field.through
without any plugin work (again, except for special cases of lazy referencing or not passing the through=
argument, which is all the new plugin code you see in this PR)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corresponding part is the to=
argument, plugin code will only be running for lazy referencing. Previously this was completely managed by the plugin, now it's instead mypy doing the work.
f81debc
to
7a23f4c
Compare
if ( | ||
expr.node.metaclass_type is not None | ||
and expr.node.metaclass_type.type.fullname == fullnames.MODEL_METACLASS_FULLNAME | ||
): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose this could be broken out to a type guard helper, if we want?
ModelTypeInfo = NewType("ModelTypeInfo", TypeInfo)
def is_model_info(info: TypeInfo) -> TypeGuard[ModelTypeInfo]:
return (
info.metaclass_type is not None
and info.metaclass_type.type.fullname == fullnames.MODEL_METACLASS_FULLNAME
)
ffcb377
to
29f9466
Compare
29f9466
to
6b8e4c4
Compare
@sobolevn I know that this is a large addition. I wanted to have it more in pieces but wasn't really able to, I pulled in one end and some stuff started to follow along. Anyways, I've run this on one of our larger projects, hit a few issues that I resolved and it's now green except 1 part, namely: users = ManyToManyField(settings.AUTH_USER_MODEL) But I wanted to keep that as a separate change to avoid piling up even more in here. I'm asking for an opinion here, how could we proceed to make it mergable? Additionally, @ljodal, I know you've previously had possibility to run changes on projects generating a bit more use cases, could you perhaps try this one out? See if we can touch a bit wider surface? Perhaps there's some cheap fixes to be found before anything is merged. All in all this PR should unlock some |
I'll give it a go, we haven't updated django-stubs in a while though, so not sure how much unrelated will pop up |
Additionally I want to emphasize that what I've done here is actually to use more of Starting to use the descriptor class is the trick, it does half of the work when having an implicit others = ManyToManyField(Other) And it does all the work when having an explicit others = ManyToManyField(Other, through=InBetween)
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't looked too closely at the code, but it seems to run fine on our largest project. A couple of new warnings due to the limitations mentioned in separate comments, but nothing major
if "." not in reference: | ||
# <object_name> -- needs prefix of <app_label>. We can't implicitly solve | ||
# what app label this should be, yet. | ||
return None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a case of this at least (the referenced model is defined right below in the file), which now causes "Needs type annotation" errors
Thank you for the help! Great to get more input |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! But, merging this PR would block the release. Can you please open a new issue with new release planning, so we won't forget about it?
I've opened a next release issue: #1740 |
Is this a known issue? When passing argument But diff --git a/tests/typecheck/fields/test_related.yml b/tests/typecheck/fields/test_related.yml
index 8f21557e..3ac3117c 100644
--- a/tests/typecheck/fields/test_related.yml
+++ b/tests/typecheck/fields/test_related.yml
@@ -1133,7 +1133,7 @@
auto_through = models.ManyToManyField(Other, related_name="autos")
# Have multiple M2Ms with implicit through
other_again = models.ManyToManyField(Other, related_name="others_again")
- custom_through = models.ManyToManyField(Other, through=CustomThrough, related_name="customs")
+ custom_through = models.ManyToManyField(Other, through="CustomThrough", related_name="customs")
- case: test_many_to_many_with_lazy_references
main: | Output:
|
Yes, see #1719 (comment) @intgr :) |
Yes, opting out of the lazy reference without "app_label" was intentional, I also implemented the lazy reference resolver for another PR, but had it erroring, and there was a small discussion regarding that: Basically it's non-trivial to figure out the correct implicit app label. So I wanted to push it for later. There might perhaps be shortcuts to take when using the runtime model, but I also wanted to minimise touching the runtime. It's easy to resolve it at least, as it's just to explicitly add the correct app label. |
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [django-stubs](https://togithub.com/typeddjango/django-stubs) ([changelog](https://togithub.com/typeddjango/django-stubs/releases)) | dev | patch | `4.2.3` -> `4.2.7` | --- ### Release Notes <details> <summary>typeddjango/django-stubs (django-stubs)</summary> ### [`v4.2.7`](https://togithub.com/typeddjango/django-stubs/releases/tag/4.2.7) [Compare Source](https://togithub.com/typeddjango/django-stubs/compare/4.2.6...4.2.7) #### Headline changes - **mypy 1.7:** Recommended mypy version updated to 1.7.x - Improved type inference for `ManyToManyField` and `Model.<manytomany>.through` - If you previously imported `RelatedManager` or `ManyRelatedManager`, update those to django-stubs-ext: `from django_stubs_ext.db.models.manager import ManyRelatedManager, RelatedManager` - It's now allowed to override Django's `@cached_property` properties with class variables or `@property` properties. - Even though Django 5.0 was released yesterday, this version does not yet include any changes specific to Django 5.0. #### Plugin improvements - Improved `ManyToManyDescriptor` and fixed `Model.<manytomany>.through` typing by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1805](https://togithub.com/typeddjango/django-stubs/pull/1805) - Fixed `Self`-typed custom queryset methods to be compatible with `QuerySet` by [@​moranabadie](https://togithub.com/moranabadie) in [https://github.com/typeddjango/django-stubs/pull/1852](https://togithub.com/typeddjango/django-stubs/pull/1852) #### django-stubs-ext - django-stubs-ext: Export `RelatedManager`, `ManyRelatedManager` stub-only classes by [@​intgr](https://togithub.com/intgr) in [https://github.com/typeddjango/django-stubs/pull/1834](https://togithub.com/typeddjango/django-stubs/pull/1834) - Updated `TypedModelMeta` `ordering` attribute to allow `OrderBy` objects by [@​HansAarneLiblik](https://togithub.com/HansAarneLiblik) in [https://github.com/typeddjango/django-stubs/pull/1847](https://togithub.com/typeddjango/django-stubs/pull/1847) #### Stubs fixes - Added missing `search_help_text=` parameter to `ChangeList.__init__()` by [@​quinox](https://togithub.com/quinox) in [https://github.com/typeddjango/django-stubs/pull/1801](https://togithub.com/typeddjango/django-stubs/pull/1801) - Allow additional types for SQL parameters in `migrations.RunSQL()` by [@​UnknownPlatypus](https://togithub.com/UnknownPlatypus) in [https://github.com/typeddjango/django-stubs/pull/1803](https://togithub.com/typeddjango/django-stubs/pull/1803) - Allow custom Form class in `SuccessMessageMixin.form_valid()` by [@​SukiCZ](https://togithub.com/SukiCZ) in [https://github.com/typeddjango/django-stubs/pull/1812](https://togithub.com/typeddjango/django-stubs/pull/1812) - Fixed `db_comment=` parameter position for `django.db.models.Field.__init__()` by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1815](https://togithub.com/typeddjango/django-stubs/pull/1815) - Added missing `RelatedField.__init__()` method and removed `ForeignObject.__init__(db_constraint=)` parameter in Field constructors by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1816](https://togithub.com/typeddjango/django-stubs/pull/1816) - Fixed argument types of `assertNumQueries()` and `assertQuerySetEqual()` by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1823](https://togithub.com/typeddjango/django-stubs/pull/1823) - Fixed `get_deleted_objects()` return from `list[Model]` -> `list[str]` by [@​golgor](https://togithub.com/golgor) in [https://github.com/typeddjango/django-stubs/pull/1825](https://togithub.com/typeddjango/django-stubs/pull/1825) - Removed incorrect `django.db.models` re-exports by [@​intgr](https://togithub.com/intgr) in [https://github.com/typeddjango/django-stubs/pull/1835](https://togithub.com/typeddjango/django-stubs/pull/1835) - Fixed `TemplateResponse.cookies` attribute and `SimpleCookie` type by [@​apollo13](https://togithub.com/apollo13) in [https://github.com/typeddjango/django-stubs/pull/1702](https://togithub.com/typeddjango/django-stubs/pull/1702) #### Stubs improvements - Added stubs for `django.contrib.postgres.expressions` by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1765](https://togithub.com/typeddjango/django-stubs/pull/1765) - Improved hints of `django.contrib.gis.gdal.libgdal` by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1811](https://togithub.com/typeddjango/django-stubs/pull/1811) - Simulate `@deconstructible` as a mixin class by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1818](https://togithub.com/typeddjango/django-stubs/pull/1818) - Improved types for `django.db.models.enums.*` modules by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1819](https://togithub.com/typeddjango/django-stubs/pull/1819) - Added `BaseExpression.contains_subquery()` method (update to Django 4.2.7) by [@​intgr](https://togithub.com/intgr) in [https://github.com/typeddjango/django-stubs/pull/1827](https://togithub.com/typeddjango/django-stubs/pull/1827) - Improved types for multiple methods of `QuerySet` by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1822](https://togithub.com/typeddjango/django-stubs/pull/1822) - Improved `Collector` and `NestedObjects` attributes, methods by [@​intgr](https://togithub.com/intgr) in [https://github.com/typeddjango/django-stubs/pull/1826](https://togithub.com/typeddjango/django-stubs/pull/1826) - Added `django.db.models.functions.MD5()` database function by [@​kevinmarsh](https://togithub.com/kevinmarsh) in [https://github.com/typeddjango/django-stubs/pull/1830](https://togithub.com/typeddjango/django-stubs/pull/1830) - Constrained multiple `BaseModelAdmin` attributes to be either list or tuple by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1832](https://togithub.com/typeddjango/django-stubs/pull/1832) - Constrained multiple `BaseModelAdmin` methods to return either list or tuple by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1833](https://togithub.com/typeddjango/django-stubs/pull/1833) - Accurately infer `capfirst()` `None` return by [@​intgr](https://togithub.com/intgr) in [https://github.com/typeddjango/django-stubs/pull/1842](https://togithub.com/typeddjango/django-stubs/pull/1842) - Various improvements in `django.core.management.commands` modules by [@​UnknownPlatypus](https://togithub.com/UnknownPlatypus) in [https://github.com/typeddjango/django-stubs/pull/1829](https://togithub.com/typeddjango/django-stubs/pull/1829) - Added `Model._do_update()` method signature by [@​pfouque](https://togithub.com/pfouque) in [https://github.com/typeddjango/django-stubs/pull/1854](https://togithub.com/typeddjango/django-stubs/pull/1854) ##### Stubs improvements: @​cached_property - Reuse `functools.cached_property` definition instead of defining our own by [@​intgr](https://togithub.com/intgr) in [https://github.com/typeddjango/django-stubs/pull/1771](https://togithub.com/typeddjango/django-stubs/pull/1771) - Updated `@property` attributes to `@cached_property` part 1 by [@​UnknownPlatypus](https://togithub.com/UnknownPlatypus) in [https://github.com/typeddjango/django-stubs/pull/1761](https://togithub.com/typeddjango/django-stubs/pull/1761) - Updated `@property` attributes to `@cached_property` part 2 by [@​UnknownPlatypus](https://togithub.com/UnknownPlatypus) in [https://github.com/typeddjango/django-stubs/pull/1768](https://togithub.com/typeddjango/django-stubs/pull/1768) - Updated Expression classes `output_field` to `@cached_property` or `ClassVar` and improves type by [@​UnknownPlatypus](https://togithub.com/UnknownPlatypus) in [https://github.com/typeddjango/django-stubs/pull/1769](https://togithub.com/typeddjango/django-stubs/pull/1769) #### Housekeeping - Moved plugin generated `<Model>_RelatedManager` entries to allowlist by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1806](https://togithub.com/typeddjango/django-stubs/pull/1806) - Moved `RelatedManager` to `django.db.models.fields.related_descriptors` by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1814](https://togithub.com/typeddjango/django-stubs/pull/1814) - Restored `RelatedManager`, `ManyRelatedManager` to inherit from `Manager` not `BaseManager` by [@​intgr](https://togithub.com/intgr) in [https://github.com/typeddjango/django-stubs/pull/1843](https://togithub.com/typeddjango/django-stubs/pull/1843) - Upgraded to mypy 1.7.0 by [@​intgr](https://togithub.com/intgr) in [https://github.com/typeddjango/django-stubs/pull/1837](https://togithub.com/typeddjango/django-stubs/pull/1837) - Unify plugin check for model type info by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1853](https://togithub.com/typeddjango/django-stubs/pull/1853) - Version 4.2.7 release (django-stubs, django-stubs-ext) by [@​intgr](https://togithub.com/intgr) in [https://github.com/typeddjango/django-stubs/pull/1856](https://togithub.com/typeddjango/django-stubs/pull/1856) #### New Contributors - [@​SukiCZ](https://togithub.com/SukiCZ) made their first contribution in [https://github.com/typeddjango/django-stubs/pull/1812](https://togithub.com/typeddjango/django-stubs/pull/1812) - [@​golgor](https://togithub.com/golgor) made their first contribution in [https://github.com/typeddjango/django-stubs/pull/1825](https://togithub.com/typeddjango/django-stubs/pull/1825) - [@​HansAarneLiblik](https://togithub.com/HansAarneLiblik) made their first contribution in [https://github.com/typeddjango/django-stubs/pull/1847](https://togithub.com/typeddjango/django-stubs/pull/1847) - [@​apollo13](https://togithub.com/apollo13) made their first contribution in [https://github.com/typeddjango/django-stubs/pull/1702](https://togithub.com/typeddjango/django-stubs/pull/1702) - [@​pfouque](https://togithub.com/pfouque) made their first contribution in [https://github.com/typeddjango/django-stubs/pull/1854](https://togithub.com/typeddjango/django-stubs/pull/1854) **Full Changelog**: typeddjango/django-stubs@4.2.6...4.2.7 ### [`v4.2.6`](https://togithub.com/typeddjango/django-stubs/releases/tag/4.2.6) [Compare Source](https://togithub.com/typeddjango/django-stubs/compare/4.2.5...4.2.6) #### Headline changes - Fixed several bugs in version 4.2.5. Thanks to everyone for contributing fixes on a short order! - Removed direct mypy dependency. If you are using mypy, please add an explicit `mypy` dev dependency to your project, or install django-stubs with the extra `django-stubs[compatible-mypy]`. Mypy remains **the only supported type checker**. Improvements for other type checkers may be considered in the future, pull requests welcome. See [#​1628](https://togithub.com/typeddjango/django-stubs/issues/1628) for details. #### Plugin fixes - Fixed `as_manager()` and `from_queryset()` when combined with `Self` types ([#​1788](https://togithub.com/typeddjango/django-stubs/issues/1788)) by [@​moranabadie](https://togithub.com/moranabadie) in [https://github.com/typeddjango/django-stubs/pull/1789](https://togithub.com/typeddjango/django-stubs/pull/1789) - Fix IndexError crash when using `from_queryset()` of custom Manager subclass by [@​moranabadie](https://togithub.com/moranabadie) in [https://github.com/typeddjango/django-stubs/pull/1786](https://togithub.com/typeddjango/django-stubs/pull/1786) - Revert "Use `parse_bool` implementation from mypy" by [@​intgr](https://togithub.com/intgr) in [https://github.com/typeddjango/django-stubs/pull/1792](https://togithub.com/typeddjango/django-stubs/pull/1792) (Turns out this was not necessary and will be reverted) #### Stubs fixes - Fixed `Field.formfield()`, `GeometryField.formfield()` method arguments by [@​brianhelba](https://togithub.com/brianhelba) in [https://github.com/typeddjango/django-stubs/pull/1778](https://togithub.com/typeddjango/django-stubs/pull/1778) #### Stubs improvements - Various improvements in `django.core.management` modules by [@​UnknownPlatypus](https://togithub.com/UnknownPlatypus) in [https://github.com/typeddjango/django-stubs/pull/1787](https://togithub.com/typeddjango/django-stubs/pull/1787) - Various improvments in `django.db.backend.base` modules by [@​UnknownPlatypus](https://togithub.com/UnknownPlatypus) in [https://github.com/typeddjango/django-stubs/pull/1791](https://togithub.com/typeddjango/django-stubs/pull/1791) #### Housekeeping - Drop hard dependency on mypy by [@​intgr](https://togithub.com/intgr) in [https://github.com/typeddjango/django-stubs/pull/1782](https://togithub.com/typeddjango/django-stubs/pull/1782) - Version 4.2.6 release (django-stubs only) by [@​intgr](https://togithub.com/intgr) in [https://github.com/typeddjango/django-stubs/pull/1794](https://togithub.com/typeddjango/django-stubs/pull/1794) **Full Changelog**: typeddjango/django-stubs@4.2.5...4.2.6 ### [`v4.2.5`](https://togithub.com/typeddjango/django-stubs/releases/tag/4.2.5) [Compare Source](https://togithub.com/typeddjango/django-stubs/compare/4.2.4...4.2.5) #### Headline changes - **mypy 1.6:** Recommended mypy version updated to 1.6.x - Next django-stubs version (4.2.6) will remove direct mypy dependency. If you are using mypy, please add an explicit `mypy` dev dependency to your project, or install django-stubs with the extra `django-stubs[compatible-mypy]`. Mypy remains **the only supported type checker**. Improvements for other type checkers may be considered in the future, pull requests welcome. See [#​1628](https://togithub.com/typeddjango/django-stubs/issues/1628) for details. - Officially added Python 3.12 support #### Stubs fixes - Made `default_storage` produce a `Storage` object by [@​brianhelba](https://togithub.com/brianhelba) in [https://github.com/typeddjango/django-stubs/pull/1665](https://togithub.com/typeddjango/django-stubs/pull/1665) - Fixed wrong type hints for `SyndicationFeed` methods by [@​WhyNotHugo](https://togithub.com/WhyNotHugo) in [https://github.com/typeddjango/django-stubs/pull/1705](https://togithub.com/typeddjango/django-stubs/pull/1705) - Fixed variance of `Migration.operations` attribute by [@​asottile](https://togithub.com/asottile) in [https://github.com/typeddjango/django-stubs/pull/1707](https://togithub.com/typeddjango/django-stubs/pull/1707) - Fixed variance of all `Migration` list attributes by [@​brianhelba](https://togithub.com/brianhelba) in [https://github.com/typeddjango/django-stubs/pull/1710](https://togithub.com/typeddjango/django-stubs/pull/1710) - Adjust `bases=` parameter in `CreateModel` migration op to allow for mixins by [@​asottile](https://togithub.com/asottile) in [https://github.com/typeddjango/django-stubs/pull/1708](https://togithub.com/typeddjango/django-stubs/pull/1708) - Fixed `_Composable` protocol for compatibility with `psycopg2-stubs` change by [@​andersk](https://togithub.com/andersk) in [https://github.com/typeddjango/django-stubs/pull/1714](https://togithub.com/typeddjango/django-stubs/pull/1714) - Various fixes and improvements in `django.views` modules by [@​GabDug](https://togithub.com/GabDug) in [https://github.com/typeddjango/django-stubs/pull/1716](https://togithub.com/typeddjango/django-stubs/pull/1716) - Removed `null` and `validators` arguments from `ManyToManyField.__init__` by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1720](https://togithub.com/typeddjango/django-stubs/pull/1720) - Various fixes and improvements in `django.test` modules by [@​UnknownPlatypus](https://togithub.com/UnknownPlatypus) in [https://github.com/typeddjango/django-stubs/pull/1752](https://togithub.com/typeddjango/django-stubs/pull/1752) - Fixed `BaseModelForm`, `ErrorList`, `ErrorDict` constructor `renderer=` parameter by [@​GabDug](https://togithub.com/GabDug) in [https://github.com/typeddjango/django-stubs/pull/1690](https://togithub.com/typeddjango/django-stubs/pull/1690) #### Stubs improvements - Annotated return value of all `deconstruct` methods by [@​brianhelba](https://togithub.com/brianhelba) in [https://github.com/typeddjango/django-stubs/pull/1695](https://togithub.com/typeddjango/django-stubs/pull/1695) - Added missing arguments to `SQLCompiler` methods by [@​ashm-tech](https://togithub.com/ashm-tech) in [https://github.com/typeddjango/django-stubs/pull/1689](https://togithub.com/typeddjango/django-stubs/pull/1689) - Added missing `max_length` attribute to `forms.FileField` by [@​GabDug](https://togithub.com/GabDug) in [https://github.com/typeddjango/django-stubs/pull/1715](https://togithub.com/typeddjango/django-stubs/pull/1715) - Added missing type arguments to various generic classes by [@​GabDug](https://togithub.com/GabDug) in [https://github.com/typeddjango/django-stubs/pull/1717](https://togithub.com/typeddjango/django-stubs/pull/1717) - Added missing `Layer.num_feat` attribute (GeoDjango) by [@​niconoe](https://togithub.com/niconoe) in [https://github.com/typeddjango/django-stubs/pull/1722](https://togithub.com/typeddjango/django-stubs/pull/1722) - Specify `AbstractBaseUser.REQUIRED_FIELDS` as `ClassVar` by [@​WhyNotHugo](https://togithub.com/WhyNotHugo) in [https://github.com/typeddjango/django-stubs/pull/1737](https://togithub.com/typeddjango/django-stubs/pull/1737) - Improve `fields.Field.formfield()` method by [@​WhyNotHugo](https://togithub.com/WhyNotHugo) in [https://github.com/typeddjango/django-stubs/pull/1739](https://togithub.com/typeddjango/django-stubs/pull/1739) - Added `ModelStateFieldsCacheDescriptor.__get__` method by [@​asottile](https://togithub.com/asottile) in [https://github.com/typeddjango/django-stubs/pull/1743](https://togithub.com/typeddjango/django-stubs/pull/1743) - Update `Model._meta` to `ClassVar[Options[Self]]` by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1732](https://togithub.com/typeddjango/django-stubs/pull/1732) - Improved `django.test.signals` types by [@​UnknownPlatypus](https://togithub.com/UnknownPlatypus) in [https://github.com/typeddjango/django-stubs/pull/1751](https://togithub.com/typeddjango/django-stubs/pull/1751) - Updated Django to 4.2.6 and updated stubs by [@​sobolevn](https://togithub.com/sobolevn) in [https://github.com/typeddjango/django-stubs/pull/1757](https://togithub.com/typeddjango/django-stubs/pull/1757) - Require 1 callable argument for `@cached_property` decorated method by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1766](https://togithub.com/typeddjango/django-stubs/pull/1766) - Allow `psycopg2.sql.SQL` in `QuerySet.raw()` by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1767](https://togithub.com/typeddjango/django-stubs/pull/1767) - Added missing stubs in `django.middleware.csrf` module by [@​UnknownPlatypus](https://togithub.com/UnknownPlatypus) in [https://github.com/typeddjango/django-stubs/pull/1770](https://togithub.com/typeddjango/django-stubs/pull/1770) - Various improvements in `django.core.cache` modules by [@​UnknownPlatypus](https://togithub.com/UnknownPlatypus) in [https://github.com/typeddjango/django-stubs/pull/1774](https://togithub.com/typeddjango/django-stubs/pull/1774) - Improved `Field.formfield()`, `GeometryField.formfield()` methods by [@​brianhelba](https://togithub.com/brianhelba) in [https://github.com/typeddjango/django-stubs/pull/1724](https://togithub.com/typeddjango/django-stubs/pull/1724) - Fixed query `F.resolve_expression()` return type by [@​schinckel](https://togithub.com/schinckel) in [https://github.com/typeddjango/django-stubs/pull/1659](https://togithub.com/typeddjango/django-stubs/pull/1659) #### Plugin improvements - Resolve dynamic `Manager` methods through manager MRO by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1701](https://togithub.com/typeddjango/django-stubs/pull/1701) - Use `functools.cached_property` instead of Django's in mypy plugin by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1721](https://togithub.com/typeddjango/django-stubs/pull/1721) - Improved hints for `ReverseOneToOneDescriptor` and start using it by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1733](https://togithub.com/typeddjango/django-stubs/pull/1733) - Add better support for `ManyToManyField`'s `through` model by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1719](https://togithub.com/typeddjango/django-stubs/pull/1719) - Resolve any `settings.AUTH_USER_MODEL` used as `to=` in relation by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1746](https://togithub.com/typeddjango/django-stubs/pull/1746) - Added missing `_default_manager` symbol to generated `through` model by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1745](https://togithub.com/typeddjango/django-stubs/pull/1745) #### Plugin crash fixes - Gracefully handle unwanted types when creating fallback managers by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1728](https://togithub.com/typeddjango/django-stubs/pull/1728) Fixes some `AssertionError` crashes. - Handle mismatching types in queryset method resolving gracefully by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1727](https://togithub.com/typeddjango/django-stubs/pull/1727) Fixes some `AssertionError` crashes. - Fixed crash on bad arguments for model relationship fields by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1735](https://togithub.com/typeddjango/django-stubs/pull/1735) Fixes some `ValueError` crashes. #### Documentation - Fixed link to `django_stubs_ext` by [@​tony](https://togithub.com/tony) in [https://github.com/typeddjango/django-stubs/pull/1747](https://togithub.com/typeddjango/django-stubs/pull/1747) & [https://github.com/typeddjango/django-stubs/pull/1748](https://togithub.com/typeddjango/django-stubs/pull/1748) - Add version 4.2.4 to version compatibility table by [@​intgr](https://togithub.com/intgr) in [https://github.com/typeddjango/django-stubs/pull/1758](https://togithub.com/typeddjango/django-stubs/pull/1758) #### Housekeeping - Removed a bunch of unused code by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1687](https://togithub.com/typeddjango/django-stubs/pull/1687) - Removed redefinition of inherited `deconstruct` methods. by [@​brianhelba](https://togithub.com/brianhelba) in [https://github.com/typeddjango/django-stubs/pull/1693](https://togithub.com/typeddjango/django-stubs/pull/1693) & [https://github.com/typeddjango/django-stubs/pull/1694](https://togithub.com/typeddjango/django-stubs/pull/1694) - Use `parse_bool` implementation from mypy by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1703](https://togithub.com/typeddjango/django-stubs/pull/1703) - Specify error codes in `# type: ignore` comments for plugin code by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1726](https://togithub.com/typeddjango/django-stubs/pull/1726) - Specify error codes in `# type: ignore` comments in stubs files by [@​UnknownPlatypus](https://togithub.com/UnknownPlatypus) in [https://github.com/typeddjango/django-stubs/pull/1734](https://togithub.com/typeddjango/django-stubs/pull/1734) - CI: Enable testing with Python 3.12 by [@​intgr](https://togithub.com/intgr) in [https://github.com/typeddjango/django-stubs/pull/1759](https://togithub.com/typeddjango/django-stubs/pull/1759) - Bump mypy from 1.5.1 to 1.6.0 by [@​dependabot](https://togithub.com/dependabot) in [https://github.com/typeddjango/django-stubs/pull/1764](https://togithub.com/typeddjango/django-stubs/pull/1764) - Tests: Add mypy error codes to typecheck by [@​UnknownPlatypus](https://togithub.com/UnknownPlatypus) in [https://github.com/typeddjango/django-stubs/pull/1773](https://togithub.com/typeddjango/django-stubs/pull/1773) - chore: Migrate from flake8 to ruff by [@​GabDug](https://togithub.com/GabDug) in [https://github.com/typeddjango/django-stubs/pull/1718](https://togithub.com/typeddjango/django-stubs/pull/1718) - Update black version by [@​sobolevn](https://togithub.com/sobolevn) in [https://github.com/typeddjango/django-stubs/pull/1776](https://togithub.com/typeddjango/django-stubs/pull/1776) - Added test to verify that `Manager.from_queryset()` handles invalid argument types by [@​flaeppe](https://togithub.com/flaeppe) in [https://github.com/typeddjango/django-stubs/pull/1731](https://togithub.com/typeddjango/django-stubs/pull/1731) - Version 4.2.5 release (django-stubs, django-stubs-ext) by [@​intgr](https://togithub.com/intgr) in [https://github.com/typeddjango/django-stubs/pull/1777](https://togithub.com/typeddjango/django-stubs/pull/1777) #### New Contributors - [@​ashm-tech](https://togithub.com/ashm-tech) made their first contribution in [https://github.com/typeddjango/django-stubs/pull/1689](https://togithub.com/typeddjango/django-stubs/pull/1689) - [@​WhyNotHugo](https://togithub.com/WhyNotHugo) made their first contribution in [https://github.com/typeddjango/django-stubs/pull/1705](https://togithub.com/typeddjango/django-stubs/pull/1705) - [@​niconoe](https://togithub.com/niconoe) made their first contribution in [https://github.com/typeddjango/django-stubs/pull/1722](https://togithub.com/typeddjango/django-stubs/pull/1722) - [@​schinckel](https://togithub.com/schinckel) made their first contribution in [https://github.com/typeddjango/django-stubs/pull/1659](https://togithub.com/typeddjango/django-stubs/pull/1659) **Full Changelog**: typeddjango/django-stubs@4.2.4...4.2.5 ### [`v4.2.4`](https://togithub.com/typeddjango/django-stubs/releases/tag/4.2.4) [Compare Source](https://togithub.com/typeddjango/django-stubs/compare/4.2.3...4.2.4) Most important changes: - This version add Mypy `1.5.*` support and update `[compatible-mypy]` extra to use `1.5.*`. - We also update our stubs to be compatible with Django `4.2.5` (and all prior versions of `4.2`). - `django_stubs_ext/` folder was renamed to be just `ext/`, it should not affect users (unless you install it from git) - We no longer assume the `objects` attribute to be present on generic Model classes. As per the [django documentation](https://docs.djangoproject.com/en/4.2/topics/db/managers/#django.db.models.Model.\_default_manager), code working with generic models should use the `_default_manager` attribute instead. This time there is no corresponding release of `django-stubs-ext`. #### Plugin changes - We now forbid to instantiate abstract models [https://github.com/typeddjango/django-stubs/pull/1663](https://togithub.com/typeddjango/django-stubs/pull/1663) [@​flaeppe](https://togithub.com/flaeppe) - Manager attributes are now `ClassVar`s [https://github.com/typeddjango/django-stubs/pull/1672](https://togithub.com/typeddjango/django-stubs/pull/1672) [@​flaeppe](https://togithub.com/flaeppe) Thanks a lot to all contributors and maintainers! 🎉 </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://togithub.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy42NC4yIiwidXBkYXRlZEluVmVyIjoiMzcuNjQuMiIsInRhcmdldEJyYW5jaCI6Im1haW4ifQ==--> Co-authored-by: descope[bot] <descope[bot]@users.noreply.github.com>
In newer mypy[1][2], `ManyToManyField`s with lazy (string) models but no app label don't work. For the `to` model, we can just use `Person` directly (and do on the line above), so do that. For the `through` model, add the app label -- Django doesn't care, and it makes mypy happy. Also, in mypy, well-structured wildcard patterns match without a submodule too, so simplify some config. [1] typeddjango/django-stubs#1802 (comment), [2] typeddjango/django-stubs#1719 (comment) [3] https://mypy.readthedocs.io/en/stable/config_file.html#config-file-format
I have made things!
I've modified how
ManyToManyField
is generic and also made theManyToManyDescriptor
generic. This was to get a better description of theManyToManyField
, which requires less plugin interference and results in more accurate types.The most important thing to notice here is a call without any explicit
through
argument makes theManyToManyField
instance only partially declared. This is where the plugin steps in and will detect the call argument is missing and generate a through model definition that aligns with what Django describes under theManyToManyField.through
section in their documentation. Here: https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ManyToManyField.through.ManyToManyField.through
should now be properly resolved to either an implicitly generated through model, or an explicitly passed one. For example, expanding a generated through model looks like below:ManyToManyField()
calls with lazy references (e.g."myapp.MyModel"
) should also be supported,"self"
too.Related issues
Closes: #1549
Closes: #883
Refs: #1638
Refs: #1454
An additional note here is that I'm getting a feeling that the there's a similar adjustment to be done for e.g.
ForeignKey
andOneToOneField
and their descriptors, which could improve their definition in general, while requiring less plugin code.