Skip to content
mkdirlife edited this page Apr 16, 2024 · 16 revisions

Utils

Utils 앱은 Safe Eye 프로젝트에서 공통적으로 사용되는 기능들을 제공하는 앱입니다.
이 앱은 다른 앱에서 사용할 수 있는 태그(Tag)와 상태(Status) 기능을 제공하고, 이를 다른 모델에 추가할 수 있도록 TagMixinStatusMixin이 있고, 사용자 정의 404 오류 처리와 권한 제어를 위한 Mixin과 권한 클래스가 있습니다.

Models

Tag 모델과 Status 모델

Tag 모델과 Status 모델은 GenericForeignKey를 사용하여 다양한 모델에 TagStatus 를 추가할 수 있습니다.

예시 코드

from django.contrib.contenttypes.models import ContentType
from .models import Status

# 상태 생성
status = Status.objects.create(
    available=True,
    content_type=ContentType.objects.get_for_model(Alarm),
    object_id=alarm.id
)

Status 모델 사용법을 간단한 예시로 넣어봤습니다. Tag 모델도 사용법은 비슷합니다. Status 모델은 여러 다른 모델에 상태를 추가할 수 있게 하려고 만들었습니다. available 필드가 있어서 사용 가능 여부를 나타낼 수 있습니다.

TagMixinStatusMixin

TagMixinStatusMixin은 모델에 태그와 상태 기능을 추가하기 위한 추상 모델입니다. 모델에서 이 Mixin을 상속받으면 TagStatus 를 연결할 수 있습니다. TagStatus 모델을 그대로 사용할 수도 있지만 이렇게 Mixin을 만든 것은 좀 더 다양한 모델에 사용될 수도 있어서 만들었습니다. TagStatus를 여러 모델에서 사용해야 하고, 모델 간의 관계를 낮추고, 부담을 줄인다는 면에서는 Mixin 을 사용하는 것이 좋을 수 있습니다.
(대규모 프로젝트에서 모델 간의 관계가 많이 추가된다면 쿼리 성능 저하가 발생할 수 있습니다.)
프로젝트가 크지 않고 TagStatus 사용하는 모델이 적다면 Mixin 없이 TagStatus 모델을 사용하는 것이 더 좋을 수 있습니다.

예시 코드

from django.db import models
from .models import TagMixin, StatusMixin

class Alarm(TagMixin, StatusMixin, models.Model):
    # Alarm 모델 필드 정의
    ...
)

위의 코드처럼 모델에서 TagMixinStatusMixin을 상속받아 사용하면, Alarm 모델에 태그와 상태 기능을 쉽게 추가할 수 있고, 알람 데이터에 태그와 상태를 분류하고 관리할 수 있습니다.

Views

TagViewSetStatusViewSet

TagViewSetStatusViewSet은 각각 Tag 모델과 Status 모델에 대한 CRUD 작업을 수행합니다.

# alarm/views.py
from rest_framework import viewsets
from .models import Tag, Status
from .serializers import TagSerializer, StatusSerializer
from .mixins import IsAuthorOrReadOnly
from .views import CustomPageNumberPagination

class TagViewSet(viewsets.ModelViewSet):
    queryset = Tag.objects.all()
    serializer_class = TagSerializer
    permission_classes = [IsAuthorOrReadOnly]
    pagination_class = CustomPageNumberPagination
    filterset_fields = ['tag_type', 'tag_content']

class StatusViewSet(viewsets.ModelViewSet):
    queryset = Status.objects.all()
    serializer_class = StatusSerializer
    permission_classes = [IsAuthorOrReadOnly]
    pagination_class = CustomPageNumberPagination
    filterset_fields = ['available']

TagViewSetStatusViewSetDjango REST FrameworkModelViewSet을 상속받아 구현되고, Tag 모델과 Status 모델에 대한 CRUD 작업을 처리할 수 있습니다. urls.py 에서 ViewSet을 라우터에 등록하면 API 엔드포인트가 생성됩니다. API 엔드포인트를 통해 TagStatus 모델에 대한 CRUD 작업을 수행할 수 있고, HTTP 요청을 보낼 수 있습니다. 이를 통해 필요한 데이터를 효과적으로 조회하고 관리할 수 있습니다.

API

*TagViewSet

GET /tags/ Tag 객체의 목록을 조회합니다.
POST /tags/ 새로운 Tag 객체를 생성합니다.
GET /tags/{id}/ 특정 Tag 객체의 상세 정보를 조회합니다.
PUT /tags/{id}/ 특정 Tag 객체를 수정합니다.
PATCH /tags/{id}/ 특정 Tag 객체를 부분적으로 수정합니다.
DELETE /tags/{id}/ 특정 Tag 객체를 삭제합니다.
GET /tags/?tag_type={tag_type} 특정 tag_type에 해당하는 Tag 객체만 조회합니다.
GET /tags/?tag_content={tag_content} 특정 tag_content에 해당하는 Tag 객체만 조회합니다.
GET /tags/?page={page_number}&page_size={page_size} 지정된 페이지 번호와 페이지 크기로 Tag 객체를 조회합니다.

필터링
GET /tags/?tag_type=category tag_type이 'category'인 Tag 객체만 조회합니다.
GET /statuses/?available=true available이 true인 Status 객체만 조회합니다.
GET /tags/?page=1&page_size=10 Tag 객체의 첫 번째 페이지를 조회하고, 페이지당 10개의 객체를 반환합니다.

*StatusViewSet

GET /status/ Status 객체의 목록을 조회합니다. 페이지네이션과 필터링을 지원합니다.
POST /status/ 새로운 Status 객체를 생성합니다.
GET /status/{id}/ 특정 Status 객체의 상세 정보를 조회합니다.
PUT /status/{id}/ 특정 Status 객체를 수정합니다.
PATCH /status/{id}/ 특정 Status 객체를 부분적으로 수정합니다.
DELETE /status/{id}/ 특정 Status 객체를 삭제합니다.
GET /status/?available={available} 특정 available 값에 해당하는 Status 객체만 조회합니다.
GET /status/?content_type={content_type_id} 특정 content_type의 ID에 해당하는 Status 객체만 조회합니다.
GET /status/?object_id={object_id} 특정 object_id에 해당하는 Status 객체만 조회합니다.
GET /status/?page={page_number}&page_size={page_size} 지정된 페이지 번호와 페이지 크기로 Status 객체를 조회합니다.

필터링
GET /status/?available=true available이 true인 Status 객체만 조회합니다.
GET /status/?content_type=3 content_type의 ID가 3인 Status 객체만 조회합니다.
GET /status/?object_id=42 object_id가 42인 Status 객체만 조회합니다.

Uses

Custom404Mixin

Custom404Mixin을 사용하여 404 에러 처리를 커스터마이징할 수 있습니다.

예시 코드

# notice/views.py
from utils.mixins import Custom404Mixin

class NoticeViewSet(Custom404Mixin, viewsets.ModelViewSet):
    queryset = Notice.objects.order_by("-created_at")
    serializer_class = NoticeSerializer
    pagination_class = CustomPageNumberPagination
    filter_fields = ["id", "title"]
    custom_404_message = "해당 공지사항을 찾을 수 없습니다."

NoticeViewSet에서 Custom404Mixin을 사용하여 404 에러 처리를 커스터마이징할 수 있습니다.
custom_404_message 속성을 통해 사용자 정의 에러 메시지를 설정할 수 있습니다.

serializer 사용

예시 코드

# alarm/serializers.py
class AlarmSerializer(serializers.ModelSerializer):
    tags = TagSerializer(many=True, required=False)
    status = StatusSerializer(many=True, required=False)
    log_format = serializers.ReadOnlyField(source="to_log_format")

    class Meta:
        model = Alarm
        fields = [
            "id",
            "admin",
            "camera_id",
            "alarm_type",
            "alarm_content",
            "risk",
            "custom_message",
            "created_at",
            "updated_at",
            "tags",
            "status",
            "log_format",
        ]

AlarmSerializer에서 TagSerializerStatusSerializer를 사용하여 태그와 상태 정보를 직렬화할 수 있고, 알람 데이터와 함께 관련된 태그와 상태 정보를 API 응답에 포함시킬 수도 있습니다.

IsAuthorOrReadOnly

IsAuthorOrReadOnly 클래스는 Django REST framework의 사용자 정의 권한 클래스입니다.

예시코드

class AlarmViewSet(Custom404Mixin, viewsets.ModelViewSet):
    queryset = Alarm.objects.order_by("-created_at")
    serializer_class = AlarmSerializer
    permission_classes = [IsAuthorOrReadOnly]
    pagination_class = CustomPageNumberPagination
    filter_backends = [DjangoFilterBackend, filters.SearchFilter]
    filterset_fields = ["camera_id", "alarm_type__code", "risk__level"]
    search_fields = ["alarm_content", "custom_message"]
    custom_404_message = "해당 알람을 찾을 수 없습니다."

permission_classes = [IsAuthorOrReadOnly] 처럼 사용하면 됩니다.

  1. 요청의 HTTP 메서드가 안전한 메서드(GET, HEAD, OPTIONS)인 경우, 모든 사용자에게 권한을 허용합니다.
  2. 요청의 HTTP 메서드가 안전하지 않은 메서드(POST, PUT, PATCH, DELETE)인 경우에는 인증된 사용자만 권한을 허용합니다.
  3. 인증된 사용자의 역할이 admin 또는 superuser인 경우, 해당 객체의 소유자(작성자)와 일치하는 경우에만 권한을 허용합니다.
  4. 인증된 사용자의 역할이 admin 또는 superuser가 아닌 경우, 권한을 거부합니다.

CustomPageNumberPagination

CustomPageNumberPagination은 페이지 크기를 조정할 수 있는 사용자 정의 페이지네이션 클래스입니다. 뷰에서 이 페이지네이션 클래스를 사용하면 클라이언트에서 페이지 크기를 지정할 수 있습니다.

예시코드

class AlarmViewSet(Custom404Mixin, viewsets.ModelViewSet):
    queryset = Alarm.objects.order_by("-created_at")
    serializer_class = AlarmSerializer
    permission_classes = [IsAuthorOrReadOnly]
    pagination_class = CustomPageNumberPagination
    filter_backends = [DjangoFilterBackend, filters.SearchFilter]
    filterset_fields = ["camera_id", "alarm_type__code", "risk__level"]
    search_fields = ["alarm_content", "custom_message"]
    custom_404_message = "해당 알람을 찾을 수 없습니다."

pagination_class = CustomPageNumberPagination 이렇게 사용하면 됩니다. pagination_class 속성은 뷰셋에서 사용할 페이지네이션 클래스를 지정합니다. CustomPageNumberPagination은 페이지 크기를 조정할 수 있는 사용자 정의 페이지네이션 클래스입니다.

위의 예시 코드들을 참고해서 utils 앱의 모델과 클래스를 사용할 수 있습니다. 여러 모델에 태그와 상태 기능을 추가하고, 권한 제어와 페이지네이션, 필터링 등의 기능을 활용할 수 있습니다.

Clone this wiki locally