Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Incompatible types with ManyRelatedManager and through Model #2171

Closed
martinlehoux opened this issue May 20, 2024 · 2 comments
Closed

Incompatible types with ManyRelatedManager and through Model #2171

martinlehoux opened this issue May 20, 2024 · 2 comments
Labels
bug Something isn't working

Comments

@martinlehoux
Copy link
Contributor

Hi, when upgrading to version 5.0.0, I get a new error

class Establishment:
	equipments: models.ManyToManyField[Equipment, EquipmentEstablishmentMembership] = models.ManyToManyField(
	        Equipment,
	        through="EquipmentEstablishmentMembership",
	        blank=True,
	        related_name="establishments",
	    )

equipments_manager: manager.ManyRelatedManager[Equipment]
equipments_manager = instance.establishment.equipments # assignment error

The fulle error is Incompatible types in assignment (expression has type "Equipment_ManyRelatedManager[EquipmentEstablishmentMembership]", variable has type "ManyRelatedManager[Equipment, Model]")

When I looked at the source code, it seems that Equipment_ManyRelatedManager is generated by django stubs in certain cases. Is that expected that I receive this type in the calling code?

Thanks!

@martinlehoux martinlehoux added the bug Something isn't working label May 20, 2024
@flaeppe
Copy link
Member

flaeppe commented May 20, 2024

Equipment_ManyRelatedManager is a subclass of ManyRelatedManager and the default manager of your Equipment model.

The runtime names it ManyRelatedManager. But you can see that it's dynamically subclassed (normally by another manager) here:

https://github.com/django/django/blob/8f205acea94e93a463109e08814f78c09307f2b9/django/db/models/fields/related_descriptors.py#L1040

As long as your Establishment class is a subclass of models.Model, could perhaps a solution here be to change the through= to have a full lazy reference? e.g. "<app_label>. EquipmentEstablishmentMembership" Ref: #1802 (comment)

And then remove the explicit type annotation for the field as mypy should be able to infer the type itself.

class Establishment:
-	equipments: models.ManyToManyField[Equipment, EquipmentEstablishmentMembership] = models.ManyToManyField(
+	equipments = models.ManyToManyField(
	        Equipment,
-	        through="EquipmentEstablishmentMembership",
+	        through="<app_label>.EquipmentEstablishmentMembership",
	        blank=True,
	        related_name="establishments",
	    )

Additionally, 5.0.0 included an update to ManyRelatedManager to have 2 type parameters in #2026. If the type hinting is necessary/wanted for equipments_manager you probably want to change:

-equipments_manager: manager.ManyRelatedManager[Equipment]
+equipments_manager: manager.ManyRelatedManager[Equipment, EquipmentEstablishmentMembership]

@martinlehoux
Copy link
Contributor Author

Thanks @flaeppe for your input! I used the lazy reference and removed the type annotation and it works like a charm!

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug Something isn't working
Development

No branches or pull requests

2 participants