Skip to content
New issue

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

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support django model type annotations #974

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

rchoquet
Copy link

@rchoquet rchoquet commented Dec 2, 2023

Hey 馃憢

First, thanks a lot for this lib! It really helped us deliver better quality software.

We are developing a (close to) fully typed application using Django. In lots of models we explicitly specify the type of the fields when the basic type is not precise enough, for example:

TaskStatus = Literal["todo", "done"]
class TaskConfiguration(TypedDict):
  foo: int
  bar: str

class Task(models.Model):
  status: TaskStatus = models.CharField()
  configuration: TaskConfiguration = models.JSONField()

The issue arises when we define the associated Pydantic models, we have to redefine the types for those fields:

class TaskSchema(ModelSchema):
  status: TaskStatus
  configuration: TaskConfiguration

  class Meta:
      model = Task
      fields = "__all__"

This PR makes ModelSchema aware of the type annotations and allow the previous schema to be defined as

class TaskSchema(ModelSchema):
  class Meta:
      model = Task
      fields = "__all__"

... so we are not repeating the type and avoid runtime errors when there is a Django model/Pydantic model mismatch.

This is a draft that would require more work/testing, let me know if you think this is an idea worth pursuing.

Cheers!

@vitalik
Copy link
Owner

vitalik commented Dec 2, 2023

Hi @rchoquet

Looks good

  • Could you also add some docs / examples-to-documentation
  • and to support python3.8/3.7 I think you need to import Literal from typing_extensions

@@ -55,7 +55,7 @@ def create_schema(
if key in self.schemas:
return self.schemas[key]

model_fields_list = self._selected_model_fields(model, fields, exclude)
model_fields_list = list(self._selected_model_fields(model, fields, exclude))
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vitalik I added a cast to list here to fix this bug:
If optional_fields was equal to __all__, optional_fields = [f.name for f in model_fields_list] a few lines below was exhausting the model_fields_list iterator, and made for fld in model_fields_list iterate over an empty list, producing an empty Pydantic model.

@rchoquet
Copy link
Author

rchoquet commented Dec 4, 2023

I'll add the doc+examples asap

@rchoquet
Copy link
Author

rchoquet commented Dec 5, 2023

@vitalik should be good now.

@vitalik
Copy link
Owner

vitalik commented Dec 5, 2023

Hi @rchoquet looks good

could you also add docs example with JsonField - as this is actually a pretty often question

@msopacua
Copy link

Question: is this common to type your fields instead of using django-stubs?
Also, if you support this, are you going to support stubs in general?

@rchoquet
Copy link
Author

Question: is this common to type your fields instead of using django-stubs?

I don't know, but I think you have to if you want more than the primitive types (ex: enums of string Literal, json field, ...)

Also, if you support this, are you going to support stubs in general?

What do you mean by that?

@vitalik sorry for the delay, I'll do the doc change today.

@vitalik
Copy link
Owner

vitalik commented Dec 14, 2023

Question: is this common to type your fields instead of using django-stubs?
Also, if you support this, are you going to support stubs in general?

not this has nothing to do with stubs - this let's you overrule default typing annotation when schema is automatically crated from model

@rchoquet
Copy link
Author

@vitalik done

@rchoquet
Copy link
Author

rchoquet commented Jan 2, 2024

Hey @vitalik

Anything left to do on my side to get this merged?

@rchoquet
Copy link
Author

Ping @vitalik

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants