django-stubs icon indicating copy to clipboard operation
django-stubs copied to clipboard

Need type annotation for ManyToManyField with string class names

Open jgillard opened this issue 1 year ago • 9 comments

Bug report

What's wrong

I'm looking at updating from 4.2.4 to 4.2.6, and am seeing some new errors that I'm not sure how to handle. They're all in one single models.py file, are all ManyToManyFields, and each of those contain the related class name as a string not as the class itself. For the ones I can convert from strings to classes without having to re-order models, this fixes the error. I don't see this particular issue discussed in a any release notes / issues / MRs hence I'm asking here. Is this expected with this update, and what should I be doing about this error? The fact that I only see this in one file is suspicious to me, but we have very few other ManyToManyFields so I can't narrow it down to something breaking in this file just yet.

models.py destinations = models.ManyToManyField('Destination')

now leads to: error: Need type annotation for "destinations" [var-annotated]

and when I change the model to destinations = models.ManyToManyField(Destination)

the error is gone.

How is that should be

Not sure tbh. If strings are not supported then I'd expect that to be mentioned somewhere (if it is, apologies!)

System information

  • OS: MacOS 13.6
  • python version: 3.11
  • django version: 4.2.6
  • mypy version: 1.6.1
  • django-stubs version: 4.2.6
  • django-stubs-ext version: 4.2.5

jgillard avatar Oct 26 '23 15:10 jgillard

Lazy references are supported if you use the format "<app_label>.<model_name>". Lazy reference with implicit app label isn't supported

flaeppe avatar Oct 26 '23 16:10 flaeppe

Ah OK yes that's the difference between this module and the ManyToManyFields in our other apps. Just to clarify and for the next person that finds this, implicit app name is supported by ForeignKey and OneToOneField, but not ManyToManyField? As I don't see issues with those relationships.

jgillard avatar Oct 26 '23 16:10 jgillard

Same here. I only have this error since I updated mypy from 1.5.1 to 1.6.1 and django-stubs from 4.2.4 to 4.2.6 and ONLY on ManyToManyField (not ForeignKey). Seems weird.

[Edit] Seems closely related to this #1719 change

cpontvieux-systra avatar Oct 31 '23 16:10 cpontvieux-systra

I have a ManyToManyField where the through model is referenced with a string class name. I needed to provide a type annotation as follows:

related_field: models.ManyToManyField[ToModel, 'ThroughModel'] = models.ManyToManyField(to=ToModel, through='ThroughModel')

Sorry, this is slightly unrelated: What's the correct type annotation for the through model when it is not a custom one?

mschoettle avatar Oct 31 '23 20:10 mschoettle

What's the correct type annotation for the through model when it is not a custom one?

Short answer: There is no correct type annotation.

Long answer:

The plugin mimics Django's dynamic creation of the intermediate(through) model, ref: https://github.com/django/django/blob/40b3975e7d3e1464a733c69171ad7d38f8814280/django/db/models/fields/related.py#L1281-L1319

So you'll need a declaration identical to that, but once you type it out you might as well use what you type out explicitly as a through= argument.

flaeppe avatar Oct 31 '23 21:10 flaeppe

any resolution on this issue?

masarliev avatar Nov 15 '23 12:11 masarliev

Hello @masarliev , try with <app_label>.<model_name> e.g.

models.ManyToManyField(
  to='<app_label>.<model_name>',
  ...

asadiqbal08 avatar Jan 09 '24 15:01 asadiqbal08

Hello @masarliev , try with <app_label>.<model_name> e.g.

models.ManyToManyField(
  to='<app_label>.<model_name>',
  ...

not working. for now I changed all relations to field: models.ManyToManyField = models.ManyToManyField..... and works, but I don't like anotating all relations just for mypy

masarliev avatar Jan 09 '24 15:01 masarliev

not working.

Did you do the same for through parameters as well? This fixed the issue for me without annotations, but I had to do both to and through.

jennifer-richards avatar Jan 09 '24 15:01 jennifer-richards