- [ISSUE] Tag 포함된 Site 모델의 serialize 처리2023년 05월 06일
- 조별하
- 작성자
- 2023.05.06.:34
[22.11.27]
🍃 구현하고자 하는 화면
1. 이전 개발 단계에서 사이트를 등록하여 해당 사이트에 Tag를 Many-to-Many관계로 등록하는 진행
2. 이제 태그가 등록된 사이트를 최신순으로 4~6개 조회 후 등록된 모든 태그를 조회하여 하단에 Tag button형태로 동적으로 뿌려주는 작업을 진행할 것이다.
3. 위와 같이 진행하기 위해서 Site항목을 조회할 뿐 아니라 Many-to-Many관계로 등록된 태그도 조회를 해야하기 때문에 Serializer 작업을 진행하게 되었다.
- 물론 api 2개를 요청하여 각각 사이트 데이터, 태그 데이터 조회할 수도 있지만 2번을 요청한다는 것 자체가 비효율적이며 drf에 존재하는 serialize를 활용하지 못한다고 판단
1. views.py > TagsAPIView 구현
class TagsAPIView(APIView): """ Site model에 Tag model값이 존재하는 것만 조회 """ def get(self, request): word: str = request.GET['word'] tags = [tag for tag in Tag.objects.all()] list_qs = Site.objects.filter( (Q(tag__in=tags))&( Q(title__contains=word)| Q(host_name__contains=word))).distinct() serializer = SiteSerializer(list_qs, many=True) return Response(serializer.data)
- /api/tags?word= api요청으로 들어오는 view 단 작업 코드이다.
- word는 검색으로 조회 시 요청되는 값이므로 자세한 설명은 생략하겠다.
- 먼저 태그가 등록된 사이트 항목을 조회하기 위해 모든 태그를 조회하여 tags에 할당
- Site모델에 tag가 위에서 할당받은 tags가 포함되며 word로 넘어온 값이 포함한 값이 조회 되게 filter를 작성
- 단, 중복된 값이 조회되지 않게 distinct()를 사용
- serializer를 사용하면 쿼리 셋 및 모델 인스턴스와 같은 복잡한 데이터를 Python 데이터 타입으로 변환한 다음
JSON
,XML 또는
다른 콘텐츠 유형으로 쉽게 렌더링 할 수 있기 때문에 queryset을 SiteSerializer에 넣어 반환받아 리턴 시켰다.
📌 SiteSerializer
lass SiteSerializer(ModelSerializer): CATEGORY_CHOICES = [(1, 'python'), (2, 'django'), (3, 'javascript'), (4, 'orm'), (5, 'mysql'), (6, 'drf'), (7, 'docker'), (8, 'os'), (9, 'aws'), (10, 'html'), (11, 'css'), (12, 'git'), (13, 'linux')] title = serializers.CharField(max_length=100, allow_blank=False, trim_whitespace=True) thumbnail_url = serializers.URLField(max_length=200, min_length=None, allow_blank=False) host_name = serializers.CharField(max_length=30, allow_blank=False, trim_whitespace=True) content = serializers.CharField(max_length=2000, allow_blank=True) category = serializers.ChoiceField(choices=CATEGORY_CHOICES) user = serializers.CharField(max_length=10, allow_blank=False, trim_whitespace=True) favorite = serializers.BooleanField(default=False) video = serializers.BooleanField(default=False) def create(self, validated_data): return Site.objects.create(**validated_data) def update(self, instance, validated_data): instance.category = validated_data.get('category', instance.category) instance.favorite = validated_data.get('favorite', instance.favorite) instance.video = validated_data.get('video', instance.video) instance.save() return instance class Meta: model = Site exclude = ["created_at", "updated_at"]
- 현재 사이트 시리얼라이즈는 위와 같이 Site모델이 가지고 있는 field를 상단에 선언
- create와 update 작업이 이루어질 때 validation작업을 할 수 있게 함수 작성
- 반환되는 값은 created_at와 updated_at를 제외한 모든 값이 조회되게 exclude에
created_at
,updated_at
을 할당해 주었다.
2. 기존 serializer를 이용한 response
✔️
[http://127.0.0.1:8000/api/tags?word=](http://127.0.0.1:8000/api/tags?word=)
api를 호출, 현재 response값
✔️ 현재 response값을 이용해선 사이트를 구현할 수 있지만 태그 값이 존재하지 않아 위의 이미지처럼 하단에 태그를 button형식으로 구현할 수 없다.
✔️ serializer는 한 번만 걸쳐서 tag값이 포함된 site값을 조회하기 위해 models.py와 serializers.py를 수정해 주겠다.📌 serializers.py
✔️ drf 정식 문서를 보여 하나의 시리얼라이즈에서 many-to-many관계를 가진 두 개의 모델 데이터를 모두 조회할 수 있는 방법을 찾아보았다.
✔️ Nested relationships 이라고 하며 서로 두 모델 간 관계가 설정되어 있는 경우 가져올 수 있다.
class SiteSerializer(ModelSerializer): CATEGORY_CHOICES = [(1, 'python'), (2, 'django'), (3, 'javascript'), (4, 'orm'), (5, 'mysql'), (6, 'drf'), (7, 'docker'), (8, 'os'), (9, 'aws'), (10, 'html'), (11, 'css'), (12, 'git'), (13, 'linux')] title = serializers.CharField(max_length=100, allow_blank=False, trim_whitespace=True) thumbnail_url = serializers.URLField(max_length=200, min_length=None, allow_blank=False) host_name = serializers.CharField(max_length=30, allow_blank=False, trim_whitespace=True) content = serializers.CharField(max_length=2000, allow_blank=True) category = serializers.ChoiceField(choices=CATEGORY_CHOICES) user = serializers.CharField(max_length=10, allow_blank=False, trim_whitespace=True) favorite = serializers.BooleanField(default=False) video = serializers.BooleanField(default=False) **tag = TagSerializer(many=True, read_only=True)** def create(self, validated_data): return Site.objects.create(**validated_data) def update(self, instance, validated_data): instance.category = validated_data.get('category', instance.category) instance.favorite = validated_data.get('favorite', instance.favorite) instance.video = validated_data.get('video', instance.video) instance.save() return instance class Meta: model = Site # exclude = ["created_at", "updated_at"] fields = ['title', 'thumbnail_url' , 'host_name', 'content' , 'category', 'user', 'favorite', 'video', **'tag'**]
1. 반환되는 fields에 tag를 포함하여 보낼 수 있게 추가
2. SiteSerializer가 tag를 인식할 수 있게 상단에 tag 필드 설정
3. tag필드를 설정하기 위해 TagSerializer작성
- site에 묶인 모든 tag를 조회하기 위해 many=True, read_only=True속성 추가
class TagSerializer(ModelSerializer): name = serializers.CharField(max_length=20, allow_blank=False, trim_whitespace=True) class Meta: model = Tag fields = ['id', 'name']
1. name 필드 값을 설정
2. 반환되는 field 설정
- 태그 이름은 화면에 바인딩할 때 사용
- id 값은 해당 태그 선택 시 api 호출에 대한 식별자 값으로 보내기 위해 사용
✔️ 이렇게 TagSerializer도 생성을 했고 SiteSerializer를 호출할 때 반환되는 값에 tag가 포함되게 코드작성을 해 주었다.
✔️하지만 결과는 동일하게 tag는 포함되지 않고 response값이 나온 걸 확인할 수 있다.
3. models.py related_name 설정
class Tag(models.Model): """ 웹 항목 태그 목록 모델 """ name = models.CharField(verbose_name='이름', max_length=20) site = models.ManyToManyField(Site, **related_name='tag'**,verbose_name='리스트') def __str__(self): return f"{self.name}" class Meta: verbose_name = '태그' verbose_name_plural = '태그 목록'
✔️ Tag 모델을 탐지할 때 site에서 값을 읽어 낼 수 있도록 related_name을 tag로 설정 후 다시 migrate 하고 진행하여 보겠다.
4. 수정한 serializer를 이용한 response
🍃 참고
'ISSUE > Django' 카테고리의 다른 글
[ISSUE] ManytoMany 관계를 가진 두 모델 Bulk Create 작업 (1) 2023.05.06 [ISSUE]decorator를 이용한 중복작업 전처리 (0) 2023.05.05 [ISSUE] signup AbstractBaseUser class (0) 2023.05.05 다음글이전글이전 글이 없습니다.댓글