• 티스토리 홈
  • 프로필사진
    조별하
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
조별하
  • 프로필사진
    조별하
    • 분류 전체보기 (124)
      • 1. 공부 (0)
        • 기술 면접 (0)
      • 2. 웹개발 (7)
        • Java (1)
        • IT 정보 (5)
        • Error 모음 (1)
      • 3. 개인관심 (1)
        • 전자 (1)
      • GITHUB (5)
      • IT 기술 면접 (3)
      • COMPUTER (2)
      • TASK (1)
      • LANGUAGES (20)
        • Python (3)
        • Django (6)
        • Java (7)
        • Node (1)
        • Jsp (2)
        • R (1)
      • 데이터과학 (2)
        • 머신러닝 및 딥러닝 (2)
      • DATABASE (5)
        • Oracle (2)
      • ISSUE (10)
        • Django (4)
        • Drf (2)
        • Javascript (1)
        • Git (1)
      • JAVA 교육 (65)
        • Java (3)
        • Jquery (2)
        • Sql (16)
        • Jdbc (1)
        • Db (2)
        • Jsp (9)
        • myWeb (15)
        • Servlet (4)
        • Spring (12)
        • Crawling (0)
        • Hosting (1)
      • 정보처리산업기사 (1)
      • EDUCATION (2)
        • IoT 서비스 (2)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
        등록된 공지가 없습니다.
      # Home
      # 공지사항
      #
      # 태그
      # 검색결과
      # 방명록
      • [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

         

        🍃 참고

        Django

         

        Django

        The web framework for perfectionists with deadlines.

        docs.djangoproject.com

        Serializer relations

         

        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

         

         

        저작자표시 (새창열림)

        'ISSUE > Django' 카테고리의 다른 글

        [ISSUE] ManytoMany 관계를 가진 두 모델 Bulk Create 작업  (1) 2023.05.06
        [ISSUE]decorator를 이용한 중복작업 전처리  (0) 2023.05.05
        [ISSUE] signup AbstractBaseUser class  (0) 2023.05.05
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바