mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-04-15 06:32:11 +03:00
Merge 2fc08b2971
into 3ba8ef967e
This commit is contained in:
commit
7d1da75656
|
@ -580,6 +580,22 @@ This option is a dictionary, mapping field names to a dictionary of keyword argu
|
|||
|
||||
Please keep in mind that, if the field has already been explicitly declared on the serializer class, then the `extra_kwargs` option will be ignored.
|
||||
|
||||
It is also possible to create new serializer fields from any related model fields using the `extra_kwargs` option. For example:
|
||||
|
||||
class UserProfile(models.Model):
|
||||
birthdate = models.DateField()
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
|
||||
class UserProfileSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = UserProfile
|
||||
fields = ['date_of_birth', 'first_name', 'last_name']
|
||||
extra_kwargs = {
|
||||
'date_of_birth': {'source': 'birthdate'},
|
||||
'first_name': {'source': 'user.first_name'},
|
||||
'last_name': {'source': 'user.last_name'}
|
||||
}
|
||||
|
||||
## Relational fields
|
||||
|
||||
When serializing model instances, there are a number of different ways you might choose to represent relationships. The default representation for `ModelSerializer` is to use the primary keys of the related instances.
|
||||
|
|
|
@ -1101,9 +1101,36 @@ class ModelSerializer(Serializer):
|
|||
if source == '*':
|
||||
source = field_name
|
||||
|
||||
# Get the right model and info for source with attributes
|
||||
source_attrs = source.split('.')
|
||||
source_info = info
|
||||
source_model = model
|
||||
|
||||
if len(source_attrs) > 1:
|
||||
attr_info = info
|
||||
attr_model = model
|
||||
|
||||
for attr in source_attrs[:-1]:
|
||||
if attr not in attr_info.relations:
|
||||
break
|
||||
|
||||
attr_model = attr_info.relations[attr].related_model
|
||||
attr_info = model_meta.get_field_info(attr_model)
|
||||
else:
|
||||
attr = source_attrs[-1]
|
||||
if (
|
||||
attr in attr_info.fields_and_pk
|
||||
or attr in attr_info.relations
|
||||
or hasattr(attr_model, attr)
|
||||
or attr == self.url_field_name
|
||||
):
|
||||
source = attr
|
||||
source_info = attr_info
|
||||
source_model = attr_model
|
||||
|
||||
# Determine the serializer field class and keyword arguments.
|
||||
field_class, field_kwargs = self.build_field(
|
||||
source, info, model, depth
|
||||
source, source_info, source_model, depth
|
||||
)
|
||||
|
||||
# Include any kwargs defined in `Meta.extra_kwargs`
|
||||
|
|
|
@ -13,6 +13,7 @@ import sys
|
|||
import tempfile
|
||||
|
||||
import pytest
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
from django.core.validators import (
|
||||
|
@ -731,6 +732,46 @@ class TestRelationalFieldMappings(TestCase):
|
|||
""")
|
||||
self.assertEqual(repr(TestSerializer()), expected)
|
||||
|
||||
def test_source_with_attributes(self):
|
||||
class UserProfile(models.Model):
|
||||
age = models.IntegerField()
|
||||
birthdate = models.DateField()
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
|
||||
class UserProfileSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = UserProfile
|
||||
fields = ('username', 'email', 'first_name', 'last_name', 'age', 'birthdate')
|
||||
extra_kwargs = {
|
||||
'username': {
|
||||
'source': 'user.username',
|
||||
},
|
||||
'email': {
|
||||
'source': 'user.email',
|
||||
},
|
||||
'first_name': {
|
||||
'source': 'user.first_name',
|
||||
},
|
||||
'last_name': {
|
||||
'source': 'user.last_name',
|
||||
}
|
||||
}
|
||||
|
||||
# In Django 3.0, the maximum length of first_name is 30, whereas it is 150
|
||||
# in later versions, so we can't hard-code the value in the expected variable.
|
||||
max_length = User.first_name.field.max_length
|
||||
|
||||
expected = dedent(f"""
|
||||
UserProfileSerializer():
|
||||
username = CharField(help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, source='user.username', validators=[<django.contrib.auth.validators.UnicodeUsernameValidator object>, <UniqueValidator(queryset=User.objects.all())>])
|
||||
email = EmailField(allow_blank=True, label='Email address', max_length=254, required=False, source='user.email')
|
||||
first_name = CharField(allow_blank=True, max_length={max_length}, required=False, source='user.first_name')
|
||||
last_name = CharField(allow_blank=True, max_length=150, required=False, source='user.last_name')
|
||||
age = IntegerField()
|
||||
birthdate = DateField()
|
||||
""")
|
||||
self.assertEqual(repr(UserProfileSerializer()), expected)
|
||||
|
||||
|
||||
class DisplayValueTargetModel(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
|
|
Loading…
Reference in New Issue
Block a user