django-types
django-types copied to clipboard
Nullable model fields have type error when trying to set None as value
Thank you so much for this package. It really has helped bring so much more visibility into my codebase. 🙏
One thing I'm struggling with is setting the right type when I have a nullable Model field. I find that when i look at an instance of the model, it shows me the value or none, but when trying to set None, i get a type error.
Django version: 3.2.10 Python version: 3.10.1
class MyModel(model.Model):
# hover on variable shows DecimalField[Decimal]
total_cost: Optional[models.DecimalField[Decimal]] = models.DecimalField(max_digits=12, decimal_places=2, null=True)
my_model_instance = MyModel.objects.first()
# hover shows Decimal | None (which is great!)
my_model_instance.total_cost
# hover shows error Cannot assign member "total_cost" for type "MyModel"
# "None" is incompatible with "Decimal | Combinable"
my_model.total_cost = None
Ive tried playing with the annotation and I can't seem to get it to work. I think this may be a bug in how the generic handles None.
class MyModel(model.Model):
# hover on expression shows Expression of type "DecimalField[Decimal]" cannot be assigned to declared type
# "DecimalField[Decimal | None]"
# TypeVar "_DEC@DecimalField" is invariant
# Type "Decimal" cannot be assigned to type "Decimal | None"
# Type cannot be assigned to type "None"
total_cost: models.DecimalField[Optional[Decimal]] = models.DecimalField()
When looking at the stub file for DecimalField, I noticed that i see a type error for the null field.
I think the Literal is the problem and if we use the one from typings
it works for me, but im not sure if there are downstream effects.
I'll submit a PR to showcase what im talking about. Please let me know if this is something im doing wrong, or something we can address to fix. Any help would be super appreciated, thanks!
That's really weird pylance is erroring about Literal
, I think we have some test cases that use that functionality
Locally I've tried importing Literal from typing
rather than typing_extensions
(python 3.9) and that seems to improve things. I think maybe pyright isn't treating typing_extensions.Literal
correctly any more?
I've noted this on the pyright project here: https://github.com/microsoft/pyright/issues/3936
Never mind, this was a bug in my environment.