Django Rest Framework 소스 해결 - 시리얼화
14264 단어 Django
예시 코드는 백엔드에서 작성한 코드와 서열화 과정만 보여 줍니다. 예시 코드는 다음과 같습니다.
파일을 나누는 것이 귀찮아서 모두views를 씁니다.py가 맞았다
import re
from django.db import models
from rest_framework import serializers
from rest_framework.viewsets import ModelViewSet
class UserProfile(models.Model):
"""
"""
username = models.CharField(
max_length=20, default="", verbose_name=" ", help_text=" ")
email = models.EmailField(
max_length=50, verbose_name=" ", help_text=" ")
class UserSerializer(serializers.ModelSerializer):
"""
"""
class Meta:
model = UserProfile
fields = "__all__"
class UserViewSet(ModelViewSet):
"""
:
"""
queryset = UserProfile.objects.all()
serializer_class = UserSerializer
url.py
from django.contrib import admin
from django.urls import path, include
from study.views import UserViewSet
from rest_framework import routers
router = routers.SimpleRouter()
router.register(r"users", UserViewSet, base_name="users")
urlpatterns = [
path('admin/', admin.site.urls),
path(r"api/", include(router.urls))
1. 사용자 목록 보기 Serializer의 서열화 과정
1. 서열화된 대상 가져오기
class ListModelMixin:
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
#
# data ,instance
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
class GenericAPIView(views.APIView):
.......
serializer_class = None
.......
def get_serializer(self, *args, **kwargs):
"""
Return the serializer instance that should be used for validating and
deserializing input, and for serializing output.
"""
#
serializer_class = self.get_serializer_class()
kwargs['context'] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
def get_serializer_class(self):
"""
Return the class to use for the serializer.
Defaults to using `self.serializer_class`.
You may want to override this if you need to provide different
serializations depending on the incoming request.
(Eg. admins get full serialization, others get basic serialization)
"""
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)
# Views serializer_class = UserSerializer
return self.serializer_class
......
이전 단계를 통해 우리는serializer=self를 알게 되었다.get_serializer(queryset, many=True)가 실행하는 UserSerializer 클래스의 실례화
2. Userializer 클래스의 실례화 과정
클래스 실례화 전에 new 방법을 실행합니다. 하나의 클래스의 생성 실례를 제어하는 과정에서 빈 대상을 생성하고, 하위 클래스가 없으면 부모 클래스의 new를 찾으며, new가 실행된 후에야 init 구조 방법을 실행할 수 있습니다.
User Serializer의 부류 Model Serializer에는 new 방법이 없고, Model Serializer의 부류 Serializer에도 new 방법이 없습니다. BaseSerlizer의 new 방법을 위로 찾으세요.
class BaseSerializer(Field):
.......
def __init__(self, instance=None, data=empty, **kwargs):
self.instance = instance
if data is not empty:
self.initial_data = data
self.partial = kwargs.pop('partial', False)
self._context = kwargs.pop('context', {})
kwargs.pop('many', None)
super().__init__(**kwargs)
def __new__(cls, *args, **kwargs):
# We override this method in order to automagically create
# `ListSerializer` classes instead when `many=True` is set.
# many=True, cls.many_init(*args, **kwargs)
if kwargs.pop('many', False):
return cls.many_init(*args, **kwargs)
return super().__new__(cls, *args, **kwargs)
@classmethod
def many_init(cls, *args, **kwargs):
"""
This method implements the creation of a `ListSerializer` parent
class when `many=True` is used. You can customize it if you need to
control which keyword arguments are passed to the parent, and
which are passed to the child.
Note that we're over-cautious in passing most arguments to both parent
and child classes in order to try to cover the general case. If you're
overriding this method you'll probably want something much simpler, eg:
@classmethod
def many_init(cls, *args, **kwargs):
kwargs['child'] = cls()
return CustomListSerializer(*args, **kwargs)
"""
allow_empty = kwargs.pop('allow_empty', None)
child_serializer = cls(*args, **kwargs)
list_kwargs = {
'child': child_serializer,
}
if allow_empty is not None:
list_kwargs['allow_empty'] = allow_empty
list_kwargs.update({
key: value for key, value in kwargs.items()
if key in LIST_SERIALIZER_KWARGS
})
meta = getattr(cls, 'Meta', None)
# ListSerializer
list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer)
return list_serializer_class(*args, **list_kwargs)
# init
3. Userializer 클래스의 인스턴스화 후 return Response(serializer.data) 실행
class ListSerializer(BaseSerializer):
......
@property
def data(self):
# data
ret = super().data
return ReturnList(ret, serializer=self)
class BaseSerializer(Field):
......
@property
def data(self):
if hasattr(self, 'initial_data') and not hasattr(self, '_validated_data'):
msg = (
'When a serializer is passed a `data` keyword argument you '
'must call `.is_valid()` before attempting to access the '
'serialized `.data` representation.
'
'You should either call `.is_valid()` first, '
'or access `.initial_data` instead.'
)
# data is_valid
raise AssertionError(msg)
# _data
if not hasattr(self, '_data'):
# _errors
if self.instance is not None and not getattr(self, '_errors', None):
self._data = self.to_representation(self.instance)
# is_valid to_representation
elif hasattr(self, '_validated_data') and not getattr(self, '_errors', None):
self._data = self.to_representation(self.validated_data)
else:
# get_initial
self._data = self.get_initial()
return self._data
4、우리가 전송한 instance 때문에self를 실행합니다.to_representation 함수에서 instance 실례가 전송되었습니다
class Serializer(BaseSerializer, metaclass=SerializerMetaclass):
.......
def to_representation(self, instance):
"""
Object instance -> Dict of primitive datatypes.
"""
ret = OrderedDict()
#
fields = self._readable_fields
for field in fields:
try:
# field
attribute = field.get_attribute(instance)
except SkipField:
continue
# We skip `to_representation` for `None` values so that fields do
# not have to explicitly deal with that case.
#
# For related fields with `use_pk_only_optimization` we need to
# resolve the pk value.
check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
#
if check_for_none is None:
#
ret[field.field_name] = None
else:
# field to_representation attribute
ret[field.field_name] = field.to_representation(attribute)
return ret
@property
def _readable_fields(self):
#
for field in self.fields.values():
if not field.write_only:
yield field
@cached_property
def fields(self):
"""
A dictionary of {field_name: field_instance}.
"""
# `fields` is evaluated lazily. We do this to ensure that we don't
# have issues importing modules that use ModelSerializers as fields,
# even if Django's app-loading stage has not yet run.
fields = BindingDict(self)
# get_fields
for key, value in self.get_fields().items():
#
fields[key] = value
#
return fields
class ModelSerializer(Serializer):
......
def get_fields(self):
"""
Return the dict of field names -> field instances that should be
used for `self.fields` when instantiating the serializer.
"""
# url_field_name
if self.url_field_name is None:
self.url_field_name = api_settings.URL_FIELD_NAME
# Meta
assert hasattr(self, 'Meta'), (
'Class {serializer_class} missing "Meta" attribute'.format(
serializer_class=self.__class__.__name__
)
)
# Meta model
assert hasattr(self.Meta, 'model'), (
'Class {serializer_class} missing "Meta.model" attribute'.format(
serializer_class=self.__class__.__name__
)
)
#
if model_meta.is_abstract_model(self.Meta.model):
raise ValueError(
'Cannot use ModelSerializer with Abstract Models.'
)
#
declared_fields = copy.deepcopy(self._declared_fields)
# model
model = getattr(self.Meta, 'model')
#
depth = getattr(self.Meta, 'depth', 0)
# 0 10
if depth is not None:
assert depth >= 0, "'depth' may not be negative."
assert depth <= 10, "'depth' may not be greater than 10."
# Retrieve metadata about fields & relationships on the model class.
# model
info = model_meta.get_field_info(model)
# filed
field_names = self.get_field_names(declared_fields, info)
# Determine any extra field arguments and hidden fields that
# should be included
#
extra_kwargs = self.get_extra_kwargs()
extra_kwargs, hidden_fields = self.get_uniqueness_extra_kwargs(
field_names, declared_fields, extra_kwargs
)
# Determine the fields that should be included on the serializer.
fields = OrderedDict()
#
for field_name in field_names:
# If the field is explicitly declared on the class then use that.
#
if field_name in declared_fields:
#
fields[field_name] = declared_fields[field_name]
continue
#
extra_field_kwargs = extra_kwargs.get(field_name, {})
source = extra_field_kwargs.get('source', '*')
if source == '*':
source = field_name
# Determine the serializer field class and keyword arguments.
#
field_class, field_kwargs = self.build_field(
source, info, model, depth
)
# Include any kwargs defined in `Meta.extra_kwargs`
field_kwargs = self.include_extra_kwargs(
field_kwargs, extra_field_kwargs
)
# Create the serializer field.
# field
fields[field_name] = field_class(**field_kwargs)
# Add in any hidden fields.
fields.update(hidden_fields)
return fields
이 때 Model을 통해 서열화된 필드 값으로 변환됩니다. 속성을 가져오는 과정에서 filed입니다.get_attribute 방법은 사실 다음과 같은 방법을 사용했다.
def get_attribute(instance, attrs):
"""
Similar to Python's built in `getattr(instance, attr)`,
but takes a list of nested attributes, instead of a single attribute.
Also accepts either attribute lookup on objects or dictionary lookups.
"""
#
for attr in attrs:
try:
# Mapping
if isinstance(instance, Mapping):
#
instance = instance[attr]
else:
#
instance = getattr(instance, attr)
except ObjectDoesNotExist:
return None
if is_simple_callable(instance):
try:
instance = instance()
except (AttributeError, KeyError) as exc:
# If we raised an Attribute or KeyError here it'd get treated
# as an omitted field in `Field.get_attribute()`. Instead we
# raise a ValueError to ensure the exception is not masked.
raise ValueError('Exception raised in callable attribute "{}"; original exception was: {}'.format(attr, exc))
return instance
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Django 라우팅 계층 URLconf 작용 및 원리 해석URL 구성(URLconf)은 Django가 지원하는 웹 사이트의 디렉토리와 같습니다.그것의 본질은 URL과 이 URL을 호출할 보기 함수 사이의 맵표입니다. 위의 예제에서는 URL의 값을 캡처하고 위치 매개 변수로...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.