mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-05-10 19:03:42 +03:00
Merge b4ce3e5d84
into 985dd732e0
This commit is contained in:
commit
7118691f6d
|
@ -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.
|
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
|
## 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.
|
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 == '*':
|
if source == '*':
|
||||||
source = field_name
|
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.
|
# Determine the serializer field class and keyword arguments.
|
||||||
field_class, field_kwargs = self.build_field(
|
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`
|
# Include any kwargs defined in `Meta.extra_kwargs`
|
||||||
|
|
|
@ -12,6 +12,7 @@ import re
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from django.contrib.auth.models import User
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.core.serializers.json import DjangoJSONEncoder
|
from django.core.serializers.json import DjangoJSONEncoder
|
||||||
from django.core.validators import (
|
from django.core.validators import (
|
||||||
|
@ -726,6 +727,42 @@ class TestRelationalFieldMappings(TestCase):
|
||||||
""")
|
""")
|
||||||
self.assertEqual(repr(TestSerializer()), expected)
|
self.assertEqual(repr(TestSerializer()), expected)
|
||||||
|
|
||||||
|
def test_source_with_attributes(self):
|
||||||
|
class UserProfile(models.Model):
|
||||||
|
age = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(100)])
|
||||||
|
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',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expected = dedent("""
|
||||||
|
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=150, required=False, source='user.first_name')
|
||||||
|
last_name = CharField(allow_blank=True, max_length=150, required=False, source='user.last_name')
|
||||||
|
age = IntegerField(max_value=100, min_value=1)
|
||||||
|
birthdate = DateField()
|
||||||
|
""")
|
||||||
|
self.assertEqual(repr(UserProfileSerializer()), expected)
|
||||||
|
|
||||||
|
|
||||||
class DisplayValueTargetModel(models.Model):
|
class DisplayValueTargetModel(models.Model):
|
||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user