Igor Dragushhak
Igor Dragushhak

Reputation: 637

How to do typing in django model field?

With the recent addition of inlay types for python in VS Code I noticed that the typing for a Field will look like this: enter image description here

As you can see it is Field[Unknown, Unknown]. And as you know if you don't provide a type to a field, you won't get attribute hints for the field, and the field will be shown as Unknown. You could just provide an str type if you for example have a CharField, something like this:

field: str = models.CharField()

The problem is, if you want to use a strongly typed linter - it will show you an error, that the assigned value is not of type str.

So I saw this inlay and I started playing around with this generic, and I noticed that the second parameter of the generic will be the type used to represent the field attribute: enter image description here

My question is, does anyone know what is the first parameter of the generic used for, and where is this generic even created, because inside of the package I see that the Field class does not inherit any Generics.

Upvotes: 1

Views: 1289

Answers (4)

TheMechanic
TheMechanic

Reputation: 949

The best solution I've found after a lot of trial and error was to use django_stubs_ext:

Usage and Effect

# models.py
# ...
from django.db.models import BooleanField, TextField, Model
# ...
class Team(Model):

    team_bio: TextField[str] = TextField(
        blank=True,
        help_text="Short biography for the team",
    )
    is_deleted: BooleanField[bool] = BooleanField(default=False)
    # the types in this context are TextField[str] and BooleanField[bool]
    # ...

# views.py
def my_view(request: django.http.HttpRequest):
    # ...
    team = Team.objects.get(name=team_name)
    if team.is_deleted:  # this is recognized simply as boolean
        log.warning("Team is marked for deletion")
    log.info(team.team_bio)  # and this a simple string
    # ...

Setup

poetry add django-stubs-ext django-types
# eq. to pip install ...

poetry add pylint-django --group dev
  • django-types is a fork of django-stubs that I'm using instead of the latter.
  • django-stubs-ext does the monkey patching for django-stubs/django-types at runtime.
  • pylint-django might be of interest if you're using pylint, not required for this example.
# settings.py
import django_stubs_ext

django_stubs_ext.monkeypatch(
    extra_classes=[
        # optional list of Field-like classes to patch
    ],
    include_builtins=True,   # defaults to True, may be omitted.
)

This is working on Django 5.

Upvotes: 0

Steve
Steve

Reputation: 13

u can do like this

somefield = BooleanField(default=False) # type:bool # type:ignore

Upvotes: 0

Igor Dragushhak
Igor Dragushhak

Reputation: 637

I think that the best way to type a field to get attribute hints (methods and attributes) of the value of the field and don't get linting errors when using strong or basic typing would be to use Union and do something like this:

username: str|CharField = CharField()

Upvotes: 0

coderiot
coderiot

Reputation: 173

Django does not allow mutating fields since a change to a field of a model would lead to a database migration.

Nevertheless under the hood many fields use the same types and are basically replaceable. I.e. ImageField just stores a path to a string similar to what i CharField could do. Allthough the inner representation of data, or how the data is stored in the field might be different for some fields.

Still all of the fields come with a huge functionality and are usually deeply embedded and wired into the framework. Therefore django model fields are not generic. I guess your IDE is doing something, ... not appropriate :)

In the documentation you can find additional information on fields. Here you can find a list of all built-in fields.

edit: I was thinking some more about the issue. almost all fields, I believe all of them, extend the models.Field class. So this might be the reason your IDE is doing this. Some polymorphic thingy has been activated in the code generator or something.

Upvotes: -1

Related Questions