DRF 공부하기 (2) :: Setting 및 Basic Serializer

phyyou·2020년 10월 14일
0
post-thumbnail

출처


위의 블로그의 내용을 복붙함.

Setting 및 Basic Serializer

아래 사례는 Udemy의 "The complete Guide to Django Restframework and Vue JS" 강의 중 Section3의 : Django REST Framework - Level One의 내용을 요약정리한 것입니다.

1. DRF 위한 사전 세팅

장고 DRF 실습을 위해 가상환경을 만들고, 아래 프로그램들을 사전에 설치합니다.

1) 설치 프로그램

pip install requests
pip install django
pip install pillow
pip install djangorestframework

pip list     # 설치된 프로그램 확인

2) Project 생성

  • 프로젝트명 : newsapi
  • 생성한 앱 : news

2. News API Serializers 작성

1) news/models.py 작성

class Article(models.Model):
    #author = models.ForeignKey(Journalist, on_delete=models.CASCADE, related_name="articles")
    author = models.CharField(max_length=120)
    title = models.CharField(max_length=120)
    description = models.CharField(max_length=200)
    body = models.TextField()
    location = models.CharField(max_length=120)
    publication_date = models.DateTimeField()
    active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True, null=True)
    updated_at = models.DateTimeField(auto_now=True, null=True)

    def __str__(self):
        return f"{ self.author } { self.title }"

2) 어드민 만들기

  1. 어드민 생성 후 계정/비밀번호 설정
python manage.py createsuperuser
  1. 어드민.py에 아래 내용 작성
from news.models import Article   # 사용할 모델 임포트
admin.site.register(Article)      # 어드민에 해당 모델 등록
  1. 어드민에서 Article 객체 만들기

3) news/api/serializers.py 작성

from rest_framework import serializers
from news.models import Article

class ArticleSerializer(serializers.Serializer):
    id = serializers.IntegerField(read_only=True)
    author = serializers.CharField()
    title = serializers.CharField()
    description = serializers.CharField()
    body = serializers.CharField()
    location = serializers.CharField()
    publication_date = serializers.DateTimeField()
    active = serializers.BooleanField()
    created_at = serializers.DateTimeField(read_only=True)
    updated_at = serializers.DateTimeField(read_only=True)

    def create(self, validated_data):
        print(validated_data)
        return Article.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.author = validated_data.get('author', instance.author)
        instance.title = validated_data.get('title', instance.title)
        instance.description = validated_data.get('description', instance.description)
        instance.body = validated_data.get('body', instance.body)
        instance.location = validated_data.get('location', instance.location)
        instance.publication_date = validated_data.get('publication_data', instance.publication_date)
        instance.active = validated_data.get('active', instance.active)
        instance.save()
        return instance

4) Serializer, Deserializer 이해하기

python manage.py shell 실행해서 아래와 같이 확인해 보기

![img](스크린샷 2020-08-24 오후 10.40.01.png)

2-1) Model Instance -> Serialize하기

# 필요한 모듈 임포트
> from news.models import Article
> from news.api.serializers import ArticleSerializer

# Article 객체, serializer 각각 변수에 담기
> article_instance = Article.objects.first() 
> serializer = ArticleSerializer(article_instance)

# Article 객체 데이터 접근하기
> article_instance
<Article: Jone doe How to be CEO>

> Article.objects.values()
<QuerySet [{'id': 2, 'author': 'Jone doe', 'title': 'How to be CEO', 'description': "it's tough", 'body': 'hahaha', 'location': 'Seoul', 'publication_date': datetime.datetime(2020, 7, 8, 9, 12, 41), 'active': True, 'created_at': datetime.datetime(2020, 7, 8, 9, 12, 43, 445883, tzinfo=<UTC>), 'updated_at': datetime.datetime(2020, 7, 8, 9, 12, 43, 445907, tzinfo=<UTC>)}]>

> article_instance.author
'Jone doe'

# serializer 데이터 접근하기 (Serializer는 파이썬 딕셔너리 타입)

> serializer.data
{id': 2, 'author': 'Jone doe', 'title': 'How to be CEO', 'description': "it's tough", 'body': 'hahaha', 'location': 'Seoul', 'publication_date': '2020-07-08T09:12:41Z', 'active': True, 'created_at': '2020-07-08T09:12:43.445883Z', 'updated_at': '2020-07-08T09:12:43.445907Z'}

> serializer.data['author']
’Jone doe'

# 타입 비교
> type(article_instance)
<class 'news.models.Article'>
> type(serializer.data)
<class 'rest_framework.utils.serializer_helpers.ReturnDict'>

2-2) Data를 Deserialize하기

> from rest_framework.renderers import JSONRenderer

# serializer.data를 JSON화
> json = JSONRenderer().render(serializer.data)
> json
b'{"id":2,"author":"Jone doe","title":"How to be CEO","description":"it\'s tough","body":"hahaha","location":"Seoul","publication_date":"2020-07-08T09:12:41Z","active":true,"created_at":"2020-07-08T09:12:43.445883Z","updated_at":"2020-07-08T09:12:43.445907Z"}'

# json를 파이썬 딕셔너리화
> import io
> from rest_framework.parsers import JSONParser
> stream = io.BytesIO(json)
> data = JSONParser().parse(stream)
> data
{'id': 2, 'author': 'Jone doe', 'title': 'How to be CEO', 'description': "it's tough", 'body': 'hahaha', 'location': 'Seoul', 'publication_date': '2020-07-08T09:12:41Z', 'active': True, 'created_at': '2020-07-08T09:12:43.445883Z', 'updated_at': '2020-07-08T09:12:43.445907Z'}

# 타입 비교
> type(json)
<class 'bytes'>
> type(stream)
<class '_io.BytesIO'>
> type(data)
<class 'dict'>

2-3) Serializer화 하여 데이터 저장하기

> serializer = ArticleSerializer(data=data)

> serializer.is_valid()
True

# serializer로 객체에 데이터 저장하기
> serializer.validated_data
OrderedDict([('author', 'Jone doe'), ('title', 'How to be CEO'), ('description', "it's tough"), ('body', 'hahaha'), ('location', 'Seoul'), ('publication_date', datetime.datetime(2020, 7, 8, 9, 12, 41, tzinfo=<UTC>)), ('active', True)])
> serializer.save()
{'author': 'Jone doe', 'title': 'How to be CEO', 'description': "it's tough", 'body': 'hahaha', 'location': 'Seoul', 'publication_date': datetime.datetime(2020, 7, 8, 9, 12, 41, tzinfo=<UTC>), 'active': True}
<Article: Jone doe How to be CEO>

# 데이터 저장되었는지 확인
> Article.objects.all()
<QuerySet [<Article: Jone doe How to be CEO>, <Article: Jone doe How to be CEO>]





3. Serializers 공식문서 내용 요약

1) Serilizer 사용하기

serializer가 어떤 역할을 수행하는지 잘 익혀 두어야 잘 활용할 수 있다. 따라서 아래 과정에 대해 상세히 알아둘 필요가 있다.

  • Serializing objects : 객체를 가져와서 데이터로 뿌려줌 (GET일 때)
serializer = CommentSerializer(comment)
serializer.data
# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}
  • Deserializing objects : 데이터를 받아서, DB에 저장될 수 있도록 1) 데이터 유효성 검사를 한 뒤, 2) 파이썬 딕셔너리 형태로 변환 (POST, PUT, PATCH일 때)
serializer = CommentSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}
  • Saving instances : deserializing된 objects를 DB에 저장
comment = serializer.save()
# .save() will create a new instance.
serializer = CommentSerializer(data=data)
serializer.save()

# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)
serializer.save()
  1. Passing additional attributes to .save()

saving instance할 때 추가 정보를 전달하고 싶을 때가 있다. 가령, 현재 시간이라거나 현재 사용자 정보 등의 경우 말이다. 이렇게 추가로 정보를 전달하고 싶을 때는 .save()할 때 추가 정보를 전달하면 된다.

serializer.save(owner=request.user)
  1. Overrding .save() directly

Contact form 같은 경우, 객체를 생성할 필요가 없이 단지 이메일이나 혹은 메시지를 보내는 로직만 필요한 경우가 있다. 이 때는 .save()의 오버라이드해서 로직을 수정해 줄 필요가 있다.

class ContactForm(serializers.Serializer):
    email = serializers.EmailField()
    message = serializers.CharField()

    def save(self):
        email = self.validated_data['email']
        message = self.validated_data['message']
        send_email(from=email, message=message)

2) serializers Fields

구체적인 필드 종류는 공식 문서를 참조할 것, 단 주로 사용하는 serializer의 핵심 속성들은 잘 이해하고 있어야 함.

Core Argument

  • read-only (Default=False)
  • write-only (Default=False)
  • required (Default=True)
  • allow_null (Default=False)
  • source (Default는 필드명과 동일한 모델의 필드)
  • validators
  • error_messages
profile
박효영

0개의 댓글