Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/api-guide/fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Set to false if this field is not required to be present during deserialization.

Setting this to `False` also allows the object attribute or dictionary key to be omitted from output when serializing the instance. If the key is not present it will simply not be included in the output representation.

Defaults to `True`. If you're using [Model Serializer](https://www.django-rest-framework.org/api-guide/serializers/#modelserializer), the default value will be `False` when you have specified a `default`, or when the corresponding `Model` field has `blank=True` or `null=True` and is not part of a unique constraint at the same time. (Note that without a `default` value, [unique constraints will cause the field to be required](https://www.django-rest-framework.org/api-guide/validators/#optional-fields).)
Defaults to `True`. If you're using [Model Serializer](https://www.django-rest-framework.org/api-guide/serializers/#modelserializer), the default value will be `False` when you have specified a `default`, or when the corresponding `Model` field has a `db_default`, `blank=True` or `null=True` and is not part of a unique constraint at the same time. (Note that without a `default` value, [unique constraints will cause the field to be required](https://www.django-rest-framework.org/api-guide/validators/#optional-fields).)

### `default`

Expand Down
4 changes: 2 additions & 2 deletions rest_framework/utils/field_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def get_field_kwargs(field_name, model_field):
kwargs['read_only'] = True
return kwargs

if model_field.has_default() or model_field.blank or model_field.null:
if model_field.has_default() or model_field.has_db_default() or model_field.blank or model_field.null:
kwargs['required'] = False

if model_field.blank and (isinstance(model_field, (models.CharField, models.TextField))):
Expand Down Expand Up @@ -304,7 +304,7 @@ def get_relation_kwargs(field_name, relation_info):
# No further keyword arguments are valid.
return kwargs

if model_field.has_default() or model_field.blank or model_field.null:
if model_field.has_default() or model_field.has_db_default() or model_field.blank or model_field.null:
kwargs['required'] = False
if model_field.validators:
kwargs['validators'] = model_field.validators
Expand Down
35 changes: 35 additions & 0 deletions tests/test_model_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
MinValueValidator
)
from django.db import models
from django.db.models.functions import Now
from django.db.models.signals import m2m_changed
from django.dispatch import receiver
from django.test import TestCase
Expand Down Expand Up @@ -381,6 +382,24 @@ class Meta:
assert non_editable_choice_field.read_only is True
assert non_editable_choice_field.choices

def test_db_default_field_not_required(self):
class DBDefaultModel(models.Model):
db_default_field = models.IntegerField(db_default=0)
db_default_expression_field = models.DateTimeField(db_default=Now())

class TestSerializer(serializers.ModelSerializer):
class Meta:
model = DBDefaultModel
fields = '__all__'

expected = dedent(r"""
TestSerializer\(\):
id = IntegerField\(label='ID', read_only=True\)
db_default_field = IntegerField\(.*required=False\)
db_default_expression_field = DateTimeField\(required=False\)
""")
assert re.search(expected, repr(TestSerializer())) is not None


class TestDurationFieldMapping(TestCase):
def test_duration_field(self):
Expand Down Expand Up @@ -656,6 +675,22 @@ class Meta:
""")
self.assertEqual(repr(TestSerializer()), expected)

def test_foreign_key_with_db_default(self):
class DBDefaultForeignKeyModel(models.Model):
foreign_key = models.ForeignKey(ForeignKeyTargetModel, on_delete=models.CASCADE, db_default=1)

class TestSerializer(serializers.ModelSerializer):
class Meta:
model = DBDefaultForeignKeyModel
fields = '__all__'

expected = dedent("""
TestSerializer():
id = IntegerField(label='ID', read_only=True)
foreign_key = PrimaryKeyRelatedField(queryset=ForeignKeyTargetModel.objects.all(), required=False)
""")
self.assertEqual(repr(TestSerializer()), expected)

def test_nested_relations(self):
class TestSerializer(serializers.ModelSerializer):
class Meta:
Expand Down
Loading