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

`choices` Field Support

Open RW21 opened this issue 1 year ago • 6 comments

I noticed that Django-ninja doesn't support some fields with choices when converted with ModelSchema. Is there a reason why Django-ninja doesn't support these fields?

Also, I haven't yet tried, but is it feasible to extract the choices from the model and create a custom TYPES from ninja/orm/fields.py, like done here https://github.com/vitalik/django-ninja/issues/694#issuecomment-1456543192 .

Below is an example of choices not being picked up.

from ninja import NinjaAPI, Schema, ModelSchema
from .models import TestModel

api = NinjaAPI()

class TestSchema(ModelSchema):
    class Meta:
        model = TestModel
        exclude = ['id']


@api.get("/hello")
def test(request, test: TestSchema):
    return "Hello world"
from django.db import models

class TestSelections(models.TextChoices):
    ONE = '1', 'one'
    TWO = '2', 'two'

class TestModel(models.Model):
    name = models.CharField(max_length=20)
    selection = models.CharField(max_length=20, choices=TestSelections.choices)

The resulting TestSchema and the openapi schema does not recognize the TextChoices set as the field for selection, and will only set it as a string field. It will pick it up if we manually set a field like below.

class TestSchema(ModelSchema):
   selection: TestSelections
    class Meta:
        model = TestModel
        exclude = ['id']

Btw, I love using your Django-ninja! It makes using Django for rest apis so much easier.

RW21 avatar Feb 10 '24 07:02 RW21

(Actually I quickly came to realize that it may not be feasible with modifying TYPES)

RW21 avatar Feb 10 '24 07:02 RW21

I have observed the same issue, I think the solution here is to use Pydantic's Enum option as described here with ModelSchema.

JPGarCar avatar Feb 23 '24 05:02 JPGarCar

Yeah, it works when you manually set it. But I feel like ModelSchema should automatically pick this up.

RW21 avatar Feb 24 '24 02:02 RW21

I noticed the same issue. Setting it manually works, but it'd be nice if it did it automatically. Also, how can I make it display the "label" instead of the "value" of the TextChoices?

For example:

class Status(models.TextChoices):
        DRAFT = "draft", "Draft"
        REVIEW = "review", "Review"
        PUBLISHED = "published", "Published"

When setting the field in the schema manually - status: Status - it display it as "draft", but it should display the human-readable label of "Draft" instead. This "label" functionality of Django's TextChoices is really important for localization.

MalachiDraven avatar Mar 08 '24 23:03 MalachiDraven

To be honest I totally agree this is something that should be automatically detected from the Django field choices. It is really weird that is not happening already :(

mconventi avatar Mar 19 '24 16:03 mconventi

This looks like it would have had some trouble until Django 5, because Django 4 and below required you to pass in your choices using the .choices property ex. my_type = models.CharField(max_length=20, choices=MyEnum.choices). The .choices property is an iterable so the name of the enum is unknown. Now that Django 5 supports just passing in the enum on its own choices=MyEnum this is probably easier to do.

pmdevita avatar Apr 15 '24 19:04 pmdevita