Skip to content

ModelSerializer generate ChoicesField will discard default parameter #7469

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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
sankforever opened this issue Aug 7, 2020 · 3 comments · Fixed by #9030
Closed

ModelSerializer generate ChoicesField will discard default parameter #7469

sankforever opened this issue Aug 7, 2020 · 3 comments · Fixed by #9030
Labels
Milestone

Comments

@sankforever
Copy link

sankforever commented Aug 7, 2020

model

class Brand(models.Model):
    name = models.CharField(_("名称"), max_length=50, unique=True)
    status = models.SmallIntegerField(
        verbose_name=_("状态"),
        choices=BrandStatus.choices,
        default=BrandStatus.ENABLE.value,
        help_text=make_markdown_table(BrandStatus.choices)
    )
    description = models.CharField(
        _("描述"), max_length=300, null=True, blank=True
    )
    creator = models.ForeignKey(
        "users.User", on_delete=models.CASCADE, verbose_name=_("拥有者")
    )
    created = models.DateTimeField(_("创建时间"), auto_now_add=True)
    updated = models.DateTimeField(_("更新时间"), auto_now=True)

Serializer

class BrandSerializer(serializers.ModelSerializer):
    name = serializers.CharField(max_length=50, validators=[special_character])
    created = serializers.DateTimeField(read_only=True)
    updated = serializers.DateTimeField(read_only=True)
    creator = serializers.ReadOnlyField(source="creator.username")

    class Meta:
        model = Brand
        fields = "__all__"

swagger
swagger

So i find

Serializers.ModelSerializer

if 'choices' in field_kwargs:
  # Fields with choices get coerced into `ChoiceField`
  # instead of using their regular typed field.
  field_class = self.serializer_choice_field
  # Some model fields may introduce kwargs that would not be valid
  # for the choice field. We need to strip these out.
  # Eg. models.DecimalField(max_digits=3, decimal_places=1, choices=DECIMAL_CHOICES)
  valid_kwargs = {
    'read_only', 'write_only',
    'required', 'default', 'initial', 'source',
    'label', 'help_text', 'style',
    'error_messages', 'validators', 'allow_null', 'allow_blank',
    'choices'
  }
  for key in list(field_kwargs):
    if key not in valid_kwargs:
      field_kwargs.pop(key)

default parameter not in valid_kwargs and will pop, but default in field_kwargs['field_kwargs']

I rewrite

class ModelSerializer(serializers.ModelSerializer):
    def build_standard_field(self, field_name, model_field):
        field_kwargs = get_field_kwargs(field_name, model_field)
        if 'choices' in field_kwargs:
            # Fields with choices get coerced into `ChoiceField`
            # instead of using their regular typed field.
            field_class = self.serializer_choice_field
            # Some model fields may introduce kwargs that would not be valid
            # for the choice field. We need to strip these out.
            # Eg. models.DecimalField(max_digits=3, decimal_places=1, choices=DECIMAL_CHOICES)
            valid_kwargs = {
                'read_only', 'write_only',
                'required', 'default', 'initial', 'source',
                'label', 'help_text', 'style',
                'error_messages', 'validators', 'allow_null', 'allow_blank',
                'choices'
            }
            field_kwargs["default"] = field_kwargs["model_field"].default  # add this
            for key in list(field_kwargs):
                if key not in valid_kwargs:
                    field_kwargs.pop(key)
        else:
            field_class, field_kwargs = super(ModelSerializer, self).build_standard_field(field_name, model_field)
        return field_class, field_kwargs

swagger
swager2

@MockyBang
Copy link

you can use the extra_kwargs, follow the link https://www.django-rest-framework.org/community/3.0-announcement/#the-extra_kwargs-option. Alternatively, specify the field explicitly on the serializer class.

@john-parton
Copy link
Contributor

john-parton commented May 21, 2021

Potential fix here: #8002

Instead of putting the default kwarg directly in build_standard_field, I added to get_field_kwargs where the bulk of that logic lives.

benesch added a commit to benesch/django-rest-framework that referenced this issue Aug 13, 2021
benesch added a commit to benesch/django-rest-framework that referenced this issue Aug 13, 2021
@stale
Copy link

stale bot commented Apr 29, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Apr 29, 2022
@auvipy auvipy removed the stale label Dec 24, 2022
rnshaikh pushed a commit to rnshaikh/django-rest-framework that referenced this issue Jun 27, 2023
@auvipy auvipy added this to the 3.15 milestone Jul 2, 2023
@auvipy auvipy added the Bug label Jul 31, 2023
auvipy added a commit that referenced this issue Aug 7, 2023
* Propagate 'default' from model_field to serializer field

Fix #7469.

Co-authored-by: Nikhil Benesch <[email protected]>

* updated field default on serializer according to openapi generation and added that to options action response

* added notes regarding default value propagation from model to serializer field

* updated note

* Update docs/api-guide/fields.md

* Update docs/api-guide/fields.md

* Update docs/api-guide/fields.md

* Update docs/api-guide/fields.md

* Update docs/api-guide/fields.md

* Update docs/api-guide/fields.md

---------

Co-authored-by: John Parton <[email protected]>
Co-authored-by: Nikhil Benesch <[email protected]>
Co-authored-by: Rizwan Shaikh <[email protected]>
Co-authored-by: Asif Saif Uddin <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment