인프런 커뮤니티 질문&답변

kwonjiwoo님의 프로필 이미지
kwonjiwoo

작성한 질문수

Vue.js - Django 연동 웹 프로그래밍 (실전편)

axios-prev-next 기능 확인

질문입니다 !!

작성

·

180

0

안녕하세요 강사님, 저는 강사님 코드에서 조금씩 수정하여 서버를 띄워보았는데, PostDetail 보여주는 부분에서 계속 오류가 생겨서요,

TypeError: Object of type User is not JSON serializable [21/Oct/2023 21:14:51] "GET /api/post/2/ HTTP/1.1" 500 120254

이렇게 오류가 뜨는데 왜 이럴까요? ㅠㅠ

이전/다음 포스팅 보여주기 전에 포스팅 하나의 상세페이지 띄워주는 것까지는 정상적으로 확인이 됐었습니다.

api/views.py

# Create your views here.
class ApiPostLV(BaseListView):
    model = Post
    
    def get_queryset(self):
        queryset = super().get_queryset()
        return queryset.order_by('-create_dt')

    def render_to_response(self, context, **response_kwargs):

        qs = context['object_list']
      
        postList = [obj_to_post(obj) for obj in qs]
        return JsonResponse(data=postList, safe=False, status=200)
    

class ApiPostDV(BaseDetailView):
    model = Post

    def render_to_response(self, context, **response_kwargs):
        obj = context['object']
        post = obj_to_post(obj)
        post['prev'], post['next'] = prev_next_post(obj)
        return JsonResponse(data=post, safe=True, status=200)

api/views_util.py

def obj_to_post(obj):
    post = dict(vars(obj))
    if obj.create_dt:
        post['create_dt'] = obj.create_dt.strftime('%Y-%m-%d %H:%M')
    else:
        post['create_dt'] = ''

    if obj.modify_dt:
        post['modify_dt'] = obj.modify_dt.strftime('%Y-%m-%d %H:%M')
    else:
        post['modify_dt'] = ''

    if obj.tags:
        post['tags'] = [tag.name for tag in obj.tags.all()]
    else:
        post['tags'] = []

    if obj.owner:
        post['owner'] = obj.owner.username
    else:
        post['owner'] = 'Anonymous'
    
    del post['_state']

    return post

def prev_next_post(obj):
    try:
        prevObj = obj.get_prev()
        prevDict = {'id' : prevObj.id, 'title' : prevObj.title, 'description' : prevObj.description, 'create_dt' : prevObj.create_dt, 'owner' : prevObj.owner}
    except obj.DoesNotExist as e:
        prevDict = {}
    
    try:
        nextObj = obj.get_next()
        nextDict = {'id' : nextObj.id, 'title' : nextObj.title, 'description' : nextObj.description, 'create_dt' : nextObj.create_dt, 'owner' : nextObj.owner}
    except obj.DoesNotExist as e:
        nextDict = {}

    return prevDict, nextDict

 

blog/models.py

class Post(models.Model):
    title = models.CharField(verbose_name='TITLE', max_length=50)
    # verbose_name : 칼럼에 대한 별칭
    description = models.CharField('DISCRIPTION', max_length=100, blank=True, help_text='simple description text.')
    content = models.TextField('CONTENT')
    create_dt = models.DateTimeField('CREATE DATE', auto_now_add=True)
    modify_dt = models.DateTimeField('MODIFY DATE', auto_now=True)
    tags = TaggableManager(blank=True)
    owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, verbose_name='OWNER', blank=True, null=True)

    def __str__(self):
        return self.title
    
    def get_absolute_url(self):
        return reverse('blog:post_detail', args=(self.id,))
    
    def get_prev(self):
        return self.get_previous_by_create_dt()
    
    def get_next(self):
        return self.get_next_by_create_dt()
    

 

PostDetail.vue

<template>
  <v-container class="white">
      <v-row align="center" justify="center">
<!--  align 속성은 위아래, justify 속성은 좌우 위치 조정  -->
        <v-col cols="12" lg="10">
<!--           <v-card class="pa-2" outlined tile> -->
            <h1>{{ post.title }}</h1>
            <div>
              <h3>{{ post.description }}</h3>
            </div>
            <div>
              <p style="margin: 5px 0;">작성일자 : {{ post.create_dt }}&nbsp;&nbsp; 최종수정 : {{ post.modify_dt }}</p>
              <p style="margin: 5px 0;">written by {{ post.owner }}</p>
            </div>
          <v-divider></v-divider>
<!--           </v-card> -->
        </v-col>
      </v-row>
      <v-row align="start" justify="center">
        <v-col cols="12" lg="10">
<!--           <v-card class="pa-2" outlined tile> -->
            <p style="white-space: pre-wrap;">
              {{ post.content }}</p>
            <div>
                        
              <strong>TAGS:</strong>
              <v-chip class="ma-2" outlined v-for="(tag, index) in post.tags" :key="index">{{ tag }}</v-chip>
            </div>
        <v-divider></v-divider>
<!--           </v-card> -->
        </v-col>
      </v-row>
      <v-row align="center" justify="center">
        <v-col cols="12" lg="10">
          <v-card class="pa-2" outlined tile>
          <v-row>
      <!-- 왼쪽에 다음 글 문구 배치 -->
      <v-col align="center" cols="2">
        <p>이전 글</p>
      </v-col>
      <!-- 오른쪽에 다음 글 제목 문구 배치 -->
      <v-col  cols="10">
        <div>
          <h3 v-if="post.prev" @click="fetchPostDetail(post.prev.id)">{{ post.prev.title }}</h3>
          <p v-if="post.prev" @click="fetchPostDetail(post.prev.id)">{{ post.prev.description }}</p>
        </div>
      </v-col>
    </v-row>
  </v-card>
          <v-card class="pa-2" outlined tile>
          <v-row>
      <!-- 왼쪽에 다음 글 문구 배치 -->
      <v-col align="center" cols="2">
        <p>다음 글</p>
      </v-col>
      <!-- 오른쪽에 다음 글 제목 문구 배치 -->
      <v-col  cols="10">
        <div>
          <h3 v-if="post.next" @click="fetchPostDetail(post.next.id)">{{ post.next.title }}</h3>
          <p v-if="post.next" @click="fetchPostDetail(post.next.id)">{{ post.next.description }}</p>
        </div>
      </v-col>
    </v-row>
  </v-card>
        </v-col>
      </v-row>
    </v-container>
</template>

<script>
import axios from "axios";

  export default {
    name: "PostDeatail",

    data: () => ({
      post: {},
    }),

    created() {
      console.log("created()...");
      const postId = 2;
      this.fetchPostDetail(postId);
    },

    methods: {
      fetchPostDetail(postId) {
        console.log("fetchPostDetail()...", postId);
        axios.get(`/api/post/${postId}/`)
        .then(res =>{
          console.log("POST DETAIL GET RES", res);
          this.post = res.data;
        })
        .catch(err => {
          console.log("POST DETAIL GET ERR_RESPONSE", err.response);
          alert(err.response.status + ' ' + err.response.statusText);
        });
      }
    }
  }
</script>
<style scoped>
</style>

 

계속 다시 코드를 짜보았는데도 어디서 오류가 나는 것인지 모르겠어서요 ㅠㅠ.....

감사합니다 .. ㅜㅜ

 

 

답변 2

0

김석훈님의 프로필 이미지
김석훈
지식공유자

prevObj.owner 에는 User 객체가 들어 있습니다. 이 User 객체를 serialize 하는 과정에 에러가 난 것입니다.

해결방법은 User 객체 전체를 보내는 것이 아니라, User 객체의 username 속성만 보내면 됩니다.

  prevDict = {'id' : prevObj.id, ..., 'owner' : prevObj.owner.username}
kwonjiwoo님의 프로필 이미지
kwonjiwoo
질문자

주말에도 답변해주시고 정말 감사합니다 강사님 !! ㅠㅠ

0

김석훈님의 프로필 이미지
김석훈
지식공유자

독자님. 혹시 저의 원래 코드에서는 에러가 발생 않나요?

그렇다면 독자님의 수정한 코드에서, 아래 에러 메세지와 관련 코드가 있는지 확인 바랍니다.

TypeError: Object of type User is not JSON serializable
kwonjiwoo님의 프로필 이미지
kwonjiwoo
질문자

말씀해주신대로 강사님이랑 똑같이 코드 수정 후에 하나씩 바꾸면서 진행 했더니 오류가 난 부분을 찾았습니다 !

prev_next_post() 메서드에서

  prevDict = {'id' : prevObj.id, 'title' : prevObj.title, 'description' : prevObj.description, 'create_dt' : prevObj.create_dt.strftime('%Y-%m-%d %H:%M'), 'owner' : prevObj.owner}

'owner' : prevObj.owner 이 부분에서 오류가 나는 듯 합니다. 이것만 제거하면 잘 되더라구요.

그런데 왜 여기서 저런 에러가 나는 건지 모르겠습니다 ㅜㅜ

kwonjiwoo님의 프로필 이미지
kwonjiwoo

작성한 질문수

질문하기