Skip to content

Commit 2f88b8b

Browse files
allow blank CharField to be nullable in the constructor, but the underlying type
is str (unless `null=True`)
1 parent 90dc663 commit 2f88b8b

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

mypy_django_plugin/transformers/init_create.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,13 @@ def extract_expected_types(ctx: FunctionContext, model: TypeInfo,
183183
False):
184184
field_type = helpers.make_optional(field_type)
185185

186+
# if CharField(blank=True,...) and not nullable, then field can be None in __init__
187+
elif (
188+
helpers.has_any_of_bases(typ.type, (helpers.CHAR_FIELD_FULLNAME,)) and is_init and
189+
field_metadata.get('blank', False) and not field_metadata.get('null', False)
190+
):
191+
field_type = helpers.make_optional(field_type)
192+
186193
expected_types[name] = field_type
187194

188195
return expected_types

test-data/typecheck/fields.test

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,28 @@ reveal_type(MyModel().id) # E: Revealed type is 'uuid.UUID*'
114114
from django.db import models
115115
class MyModel(models.Model):
116116
text = models.CharField(max_length=30, blank=True)
117-
MyModel(text=None) # E: Incompatible type for "text" of "MyModel" (got "None", expected "Union[str, int, Combinable]")
117+
MyModel(text=None) # Should allow None in constructor
118118
MyModel(text="")
119+
MyModel().text = None # E: Incompatible types in assignment (expression has type "None", variable has type "Union[str, int, Combinable]")
119120
reveal_type(MyModel().text) # E: Revealed type is 'builtins.str*'
120121
[/CASE]
122+
123+
[CASE blank_and_null_char_field_allows_none]
124+
from django.db import models
125+
class MyModel(models.Model):
126+
nulltext=models.CharField(max_length=1, blank=True, null=True)
127+
MyModel(nulltext="")
128+
MyModel(nulltext=None)
129+
MyModel().nulltext=None
130+
reveal_type(MyModel().nulltext) # E: Revealed type is 'Union[builtins.str, None]'
131+
[/CASE]
132+
133+
[CASE blank_and_not_null_charfield_does_not_allow_none]
134+
from django.db import models
135+
class MyModel(models.Model):
136+
notnulltext=models.CharField(max_length=1, blank=True, null=False)
137+
MyModel(notnulltext=None) # Should allow None in constructor
138+
MyModel(notnulltext="")
139+
MyModel().notnulltext = None # E: Incompatible types in assignment (expression has type "None", variable has type "Union[str, int, Combinable]")
140+
reveal_type(MyModel().notnulltext) # E: Revealed type is 'builtins.str*'
141+
[/CASE]

0 commit comments

Comments
 (0)