프로젝트를 진행하던 도중 json안에 json을 넣는 등 복잡한 구조의 통신이 필요해졌다.
칵테일 레시피를 보여주는 웹사이트를 제작 중이다.
칵테일 레시피가 데이터 베이스에 저장되는 방식은 이렇다.
1. 칵테일 이름
2. 베이스 (술 이름, 들어가는 양(oz))
3. 서브 (재료 이름, 들어가는 양)
4. 부재료 (재료 이름, 들어가는 양)
5. 조합법
일단은 1,2,3 만 구현해보기로 했는데
결론적으로 다음과 같은 JSON을 보내야 한다.
베이스 재료와 서브 재료는 각각 들어가는 재료 이름과 양을 모두 가지고 있어야해서 하나의 json으로 만들었다.
즉 json 안에 json을 넣어 통신을 해야하는 상황인데 지금까지 배운 serializer의 기본 사용법으로는 구현하는데 한계를 느꼈다.
그러던 도중 발견한 것이 장고의 외래키(ForeignKey)기능이다.
외래키 기능은 장고에서 모델을 만들때 두개 이상의 모델을 연결할 수 있도록 하는 기능이다.
외래키 사용법을 검색했을때 공식 문서에서는 앨범과 앨범 수록곡(track) 모델을 연결하는 것을 예시로 들어주었다.
공식문서
https://www.django-rest-framework.org/api-guide/relations/#api-reference
Serializer relations - Django REST framework
relations.py Data structures, not algorithms, are central to programming. — Rob Pike Relational fields are used to represent model relationships. They can be applied to ForeignKey, ManyToManyField and OneToOneField relationships, as well as to reverse re
www.django-rest-framework.org
번역본?
https://kimdoky.github.io/django/2018/07/13/drf-Serializerrelations/
Django REST Framework - Serializer relations
on July 13, 2018 under django 22 minute read Django REST framework - Serializer relations “Bad programmers worry about the code. Good programmers worry about data structures and their relationships.” “나쁜 프로그래머는 코드에 대해 걱정
kimdoky.github.io
그래서 저 자료를 활용해서 model 클래스와 serializer을 작성해봤다.
베이스 재료들과 서브 재료들이 모여있는 BaseIngredient, SubIngredient 모델 클래스를 만들고
외래키를 이용해 CocktailIngredient 클래스에 연결했다.
#models.py
from django.db import models
class CocktailIngredient(models.Model):
cocktail_name = models.CharField(max_length = 100, primary_key="True")
class BaseIngredient(models.Model):
cocktail_name = models.ForeignKey(CocktailIngredient, related_name="base_ingredients",on_delete=models.CASCADE,db_column="base")
drink_name = models.CharField(max_length=100,default="")
oz = models.FloatField(default=0.0)
# def __str__(self):
# return f'{self.drink_name}: {self.oz} oz'
class SubIngredient(models.Model):
cocktail_name = models.ForeignKey(CocktailIngredient, related_name="sub_ingredients",on_delete=models.CASCADE,db_column="sub")
drink_name = models.CharField(max_length=100,default="")
oz = models.FloatField(default=0.0)
def __str__(self):
return f'{self.drink_name}: {self.oz} oz'
그리고 serializer을 구성하는 방법은 여러가지가 존재하는데
StringRelatedField
slugRelatedField
등등..
아래 예시에선 Nested relationships 방법을 사용하기로 했다.
#serializers.py
from rest_framework import serializers
from .models import BaseIngredient, CocktailIngredient, SubIngredient
class BaseIngredientSerializer(serializers.ModelSerializer):
class Meta:
model = BaseIngredient
fields = ('drink_name','oz')
class SubIngredientSerializer(serializers.ModelSerializer):
class Meta:
model = SubIngredient
fields = ('drink_name','oz')
class CocktailIngredientSerializer(serializers.ModelSerializer):
#base_ingredients = serializers.StringRelatedField(many=True, read_only = True)
#sub_ingredients = serializers.StringRelatedField(many=True, read_only=True)
base_ingredients = BaseIngredientSerializer(many=True)
sub_ingredients = SubIngredientSerializer(many=True)
class Meta:
model = CocktailIngredient
fields = ('cocktail_name','base_ingredients','sub_ingredients')
def create(self, validated_data):
base_data = validated_data.pop('base_ingredients')
sub_data = validated_data.pop('sub_ingredients')
cocktail = CocktailIngredient.objects.create(**validated_data)
for base in base_data:
BaseIngredient.objects.create(cocktail_name=cocktail,**base)
for sub in sub_data:
SubIngredient.objects.create(cocktail_name=cocktail, **sub)
return cocktail
말 그래도 serializer을 중첩해서 사용하는데 이 경우 create 함수를 따로 만들어줘야한다.
사실 예재에 있는거 그대로 따라했는데 create 함수 부분은 아직 완벽히 이해가 안된다.
더 공부 후 추가 예정
'장고는 못말려' 카테고리의 다른 글
사지방에서 웹 백엔드 공부하기 #2 Django REST API 설계 및 구현 (0) | 2023.02.19 |
---|---|
사지방에서 웹 백엔드 공부하기 #1 개발환경 설정 (Goorm IDE) (2) | 2023.02.11 |
REST API 장고로 구현하기 - 3 (연습 프로젝트 구현) (2) | 2022.06.22 |
REST API 장고로 구현하기 - 2 (연습 프로젝트 준비) (2) | 2022.06.22 |
REST API 장고로 구현하기 - 1 (웹 기본지식) (2) | 2022.06.22 |