Admin Page 작업 정리

김의석 ·2025년 1월 24일

Hello! Poko Ver.2

목록 보기
25/28
post-thumbnail

1. Serializser가 필요하지 않는 경우

Serializser

직렬화 기본

Django의 model_to_dict는 기본적으로 모델 객체를 딕셔너리로 변환하는 데 유용하지만, 외래키(ForeignKey)일대일 관계(OneToOneField)와 같은 복잡한 필드 구조를 직렬화하는 데는 한계가 있다. 이 경우, Django REST Framework(DRF)의 Serializer를 사용한다.

API에서 Serializser를 사용하지 않는 경우

WeeklyListView

class WeeklyListView(ListAPIView):
    def get(self, request, *args, **kwargs):
        year = self.request.query_params.get("year", None)
        if year:
            # 선택한 연도의 출석 데이터 필터링
            attendance_dates = (
                Attendance.objects.filter(date__year=year)
                .values_list("date", flat=True)
                .distinct()
            )
        else:
            attendance_dates = Attendance.objects.values_list(
                "date", flat=True
            ).distinct()

        sorted_dates = sorted(attendance_dates)

        return Response(sorted_dates)

이 코드는 Attendance model을 사용하여 객체를 가져오지만 values_list()`로
날짜 데이터의 원시값만 추출하고 이를 정렬하여 반환한다.

  • values_list() : 특정 필드만 가져오기 위해 사용하며, flat=True를 설정하면 단일 필드의 값만 리스트 형태로 반환한다.
  • distinct() : 중복된 데이터를 제거한다.

WeeklyListView의 반환값

['2023-01-01', '2023-01-02']

GroupAttendanceViewSet

class GroupAttendanceViewSet(ModelViewSet):
    queryset = Attendance.objects.all()
    serializer_class = GroupAttendanceSerializer
    permission_classes = [IsAuthenticated]
    authentication_classes = [JWTCookieAuthentication]

    @action(detail=False, methods=["get"], url_path="attendance-by-week")
    def attendance_by_week(self, request):
        # 쿼리 파라미터에서 날짜 가져오기
        week = request.query_params.get("week")

        if not week:
            return Response({"error": "Week parameter is required"}, status=400)

        try:
            # 요청된 날짜를 필터링
            attendance_data = (
                Attendance.objects.filter(date=week)  # 요청된 날짜 필터링
                .values("name__grade")  # 학년 기준 그룹화
                .annotate(
                    attendance_count=Count("id", filter=Q(attendance=True)),  # 출석 수
                    absent_count=Count("id", filter=Q(attendance=False)),  # 결석 수
                )
                .order_by("name__grade")  # 학년 기준 정렬
            )

            return Response(attendance_data)  # 결과 반환

serializer_class옵션은 ModelViewSet기본 CRUD 동작 및 기본 조회 동작에서 사용된다.

attendance_by_week와 같은 @action 데코레이터로 정의된 커스텀 액션은 기본 CRUD 동작과 별도로 정의되므로 해당메서드에서는 serializer_class가 자동으로 사용되지않는다.

attendance_by_week 메서드에서 반환하는 데이터는 집계된 결과로, Attendance 모델의 인스턴스가 아니기때문에 serializer_class가 사용되지않는다.

GroupAttendanceViewSet의 반환값

[
    {"name__grade": "1", "attendance_count": 10, "absent_count": 5},
    {"name__grade": "2", "attendance_count": 8, "absent_count": 3},
]

2. react-apexcharts 사용하기

그래프 serise와 option 설정

react-apexcharts를 생성할 serise와 option 함수를 생성한다.

const series = getGraphSeries(weeklyAttendanceData);
const lineGraphOptions = getLineGraphOptions();
const groupGrades = groupAttendanceData.map((item) => item.name__grade);
const groupSeries = getGroupGraphSeries(groupAttendanceData);
const barGraphOptions = getBarGraphOptionsForGroups(groupGrades);

series : weeklyAttendanceData를 기반으로 라인 그래프에 사용할 시리즈 데이터를 생성한다.
lineGraphOptions : 라인 그래프의 옵션을 생성한다.
groupGrades : groupAttendanceData에서 각 반(grade)의 이름(name__grade)을 추출하여 배열로 만든다.
groupSeries : groupAttendanceData를 기반으로 막대 그래프를 생성한다.
barGraphOptions : 막대 그래프의 옵션을 생성한다.

데이터 호출

weeklyAttendanceData, groupAttendanceData는 두 함수를 통해 생성

// 주간 출석 데이터 가져오기
const fetchData = async () => {
    setLoading(true);
    try {
      const data = await fetchWeeklyAttendanceData(selectedYear);
      setWeeklyAttendanceData(data);
    } catch (error) {
      console.error("Error fetching weekly attendance data:", error);
      message.error("출석 데이터를 가져오는 데 실패했습니다.");
    } finally {
      setLoading(false);
    }
  };

  // 반별 출석 데이터 가져오기
  const fetchGroupData = async () => {
		// 데이터 호출 코드
  };

graphUtils.js

serise와 option 함수는 graphUtils.js를 생성하여 분리하여 관리한다.

/**
 * 그래프 데이터를 생성하는 함수
 * @param {Array} attendanceData - 출석 데이터 배열
 * @returns {Array} series - 그래프 시리즈 데이터
 */
export const getGraphSeries = (attendanceData) => [
  {
    name: "출석",
    data: attendanceData
      .filter((item) => item.type === "출석")
      .map((item) => ({
        x: new Date(item.date).getTime(), // 날짜를 타임스탬프로 변환
        y: item.value,
      })),
  },
  {
    name: "결석",
    data: attendanceData
      .filter((item) => item.type === "결석")
      .map((item) => ({
        x: new Date(item.date).getTime(), // 날짜를 타임스탬프로 변환
        y: item.value,
      })),
  },
];

export const getLineGraphOptions => [
];
export const getGroupGraphSeries => [
];
export const getBarGraphOptionsForGroups => [
];

태그 적용

각 태그에서 serise와 option을 통해 그래프를 생성한다.

<Chart options={lineGraphOptions} series={series} type="line" height={350} />
<Chart options={barGraphOptions} series={groupSeries} type="bar" height={350} />
  
  
profile
널리 이롭게

0개의 댓글