Django DRF Generics for CRUD

Haks.ยท2025๋…„ 2์›” 7์ผ
0

How to use

๋ชฉ๋ก ๋ณด๊ธฐ
21/32

Generic View

์ œ๋„ˆ๋ฆญ ๋ทฐ(Generic Views)๋Š” Django REST Framework์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ์ ์ธ CRUD(Create, Retrieve, Update, Delete) ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ทฐ๋ฅผ ์†์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ์ด๋“ค์€ APIView๋ฅผ ์ƒ์†๋ฐ›์•„ ํŠน์ • ์ž‘์—…์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š” ๋ทฐ ํด๋ž˜์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ œ๋„ˆ๋ฆญ ๋ทฐ์˜ ์žฅ์ 

  • ๊ฐ„ํŽธํ•จ: CRUD ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ทฐ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ผ๊ด€์„ฑ: ์ฝ”๋“œ๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ณ  ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์žฌ์‚ฌ์šฉ์„ฑ: ๊ณตํ†ต ๊ธฐ๋Šฅ์„ ์†์‰ฝ๊ฒŒ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ ์‹ค์Šต

  1. ListAPIView
from django.db.models import Q
from rest_framework.generics import ListAPIView, RetrieveAPIView
from rest_framework.permissions import IsAuthenticatedOrReadOnly

from blog.models import Blog
from blog.serializers import BlogSerializer

class BlogListAPIView(ListAPIView):
    queryset = Blog.objects.all()
    serializer_class = BlogSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]
    
    def get_queryset(self):
    	queryset=super().get_queryset()
        # ํ•จ์ˆ˜๋ฅผ ์ด๋ ‡๊ฒŒ ์„ ์–ธํ•ด์„œ ๋„ฃ์–ด์•ผ datetime.now๊ฐ€ ๊ทธ ๋ฐœ์ƒ์‹œ๊ฐ„์— ์„ ์–ธ๋œ๋‹ค. ํด๋ž˜์Šค๋‚ด์—์„œ ๋งŒ๋“ค๋ฉด ๊ทธํด๋ž˜์Šค๊ฐ€ ์ฒ˜์Œ์— ์„ ์–ธ ๋ฌ์„๋•Œ ์˜์‹œ๊ฐ„์œผ๋กœ ์ƒ์„ฑ๋จ
        return queryset.filter(
        	Q(published_at__isnull=True) |
            Q(published_at__gte=timezone.now())
        ).order_by('-created_at').select_related('author')

# blog/urls/generics_urls.py
from django.urls import path, include
from blog.views import generics_views

app_name ='generics_api'
# blog/urls/api_urls.py
urlpatterns = [
    path('blog', generics_views.BlogListAPIView.as_view(), name='blog_list'),
]
  1. DetailView, RetrieveAPIView ListView์™€ ๋™์ผ
class BlogRetrieveAPIView(BlogQuerySetMixin, RetrieveAPIView):
    model = Blog
        queryset = Blog.objects.all()
        serializer_class = BlogSerializer
        permission_classes = [IsAuthenticatedOrReadOnly]
    
        def get_queryset(self): 
            queryset = super().get_queryset()
            return queryset.filter(
                Q(published_at__isnull=True) |
                Q(published_at__gte=timezone.now())
            ).order_by('-created_at').select_related('author')
    
    # blog/urls/generics_urls.py
    from django.urls import path, include
    from blog.views import generics_views
    
    app_name ='generics_api'
    # blog/urls/api_urls.py
    urlpatterns = [
        path('blog/<int:pk>', generics_views.BlogRetrieveAPIView.as_view(), name='blog_detail'),
    ]
  1. ์ƒ์†์‹œ์ผœ ์ œ์ž‘ํ•ด๋ณด์ž
class BlogQuerySetMixin:
    serializer_class = BlogSerializer
    queryset = Blog.objects.all()
    permission_classes = [IsAuthenticatedOrReadOnly]
    def get_queryset(self):
        return self.queryset.filter(
            Q(published_at__isnull=True) |
            Q(published_at__gte=timezone.now())
        ).order_by('-created_at').select_related('author')
class BlogListAPIView(BlogQuerySetMixin, ListAPIView):
    pass

class BlogRetrieveAPIView(BlogQuerySetMixin, RetrieveAPIView):
    pass

๐Ÿ“ POST, UPDATE, DESTROY

class BlogQuerySetMixin:
    serializer_class = BlogSerializer
    queryset = Blog.objects.all()
    permission_classes = [IsAuthenticatedOrReadOnly]
    def get_queryset(self):
        
        return self.queryset.filter(
            Q(published_at__isnull=True) |
            Q(published_at__gte=timezone.now())
        ).order_by('-created_at').select_related('author')
class BlogListAPIView(BlogQuerySetMixin, ListCreateAPIView):
    pass

class BlogRetrieveAPIView(BlogQuerySetMixin, RetrieveUpdateDestroyAPIView):
    pass
  1. postman์œผ๋กœ ์ด๋ณด๋ฉด author ์•„ ์—†์–ด์„œ ์•ˆ๋จ
  2. command + ํด๋ฆญํ•ด์„œ -> create ๋˜ ๋“ค์–ด๊ฐ€๋ณด๋ฉด ํ•ด๋‹น ํด๋ž˜์Šค ์‚ดํŽด๋ณด๋ฉด serializer.save(author=request..) ๋ญ ์ด๋Ÿฐ์‹ ์ด๊ฑธ ๋ถˆ๋Ÿฌ์™€์„œ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•ด์ฃผ์ž -> ์ž˜๋จ
class BlogListAPIView(BlogQuerySetMixin, ListCreateAPIView):
    def perform_create(self, serializer):
        serializer.save(author=self.request.user)
  1. ์—…๋ฐ์ดํŠธ๋Š” ์ž‘์„ฑ์ž๋งŒ ๊ฐ€๋Šฅํ•˜๊ฒŒ permission์„ ์—…๋ฐ์ดํŠธ ํ•ด์ฃผ์ž ๋งŒ๋“ค์–ด๋†“์€ ๊ฑธ๋กœ
from permissions import IsAuthorOrReadOnly
class BlogRetrieveAPIView(BlogQuerySetMixin, RetrieveUpdateDestroyAPIView):
    permission_classes = [IsAuthorOrReadOnly]

# utils/permissions.py
from rest_framework import permissions

class IsAuthorOrReadOnly(permissions.BasePermission):
    def has_pers(self, request, view):
        if request.method in permissions.SAFE_METHODS:
            return True
        try:
            obj = view.get_object(request, *view.args, **view.kwargs)
        except TypeError:
            # get_object ๊ฐ€ ๋‹ค๋ฆ„ 
            obj = view.get_object()
        return obj.author == request.user

๐Ÿ“Œ fields์— ๋“œ๊ฐ€๋Š” ๋‹จ์–ด ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•˜๋Š” ๋ฐฉ๋ฒ• SerializerMethodField()

class BlogSerializer(serializers.ModelSerializer):
    author = UserSerializer(many=False, read_only=True)
    # read_only => ํ•ด๋‹นํ•„๋“œ๋ฅผ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๊ฒŒ ํ•ด๋†“๋Š” ๊ฒƒ
    # foreignkey ์—ฐ๊ฒฐ๋œ๊ฒƒ ์—ฐ๊ฒฐํ•˜๋Š”๊ฒƒ serialzer ๋กœ ํ•ด๋†“์€๊ฒƒ ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉ๊ฐ€๋Šฅ
    # ์ด๋ ‡๊ฒŒ ์“ฐ๋ฉด ๊ผญ ๊นŒ๋จน์ง€๋ง๊ณ  views ์—์„œ select_related ๋“ฑ๋กํ•˜๊ธฐ
    # BlogSerializer๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด author๊ฐ€ ์ž๋™์œผ๋กœ ๋ถˆ๋Ÿฌ์™€์ง

    comment_count = serializers.SerializerMethodField()  # ์ด๋ ‡๊ฒŒ ์“ฐ๋ฉด ์ƒํŽ˜์ด์ง€์—์„œ ๋Œ“๊ธ€ ์ˆซ์ž๋ฅผ ํ™•์ธํ• ์ˆ˜์žˆ์Œ
    # SerializerMethodField ๋ฉ”์†Œ๋“œ๋Š” ๋ณ€์ˆ˜ ์•ž์— get_ ์„ ๋ถ™์—ฌ ํ•จ์ˆ˜๋กœ ๋งŒ๋“ค๋ฉด ๋ณ€์ˆ˜๋ฅผ Meta์—์„œ ์‚ฌ์šฉํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ๋ฉ”์†Œ๋“œ์ด๋‹ค
    author_name = serializers.SerializerMethodField()
    def get_comment_count(self, obj):
        return obj.comment_set.count()
    def get_author_name(self, obj):
        return obj.author.username
    # ๋งŒ๋“ ๊ฒƒ ๊ผญ feild์— ๋„ฃ์–ด์•ผ ๋ณด์ž„    
    # author์˜ name ๋งŒ ๋ณด๋ฉด ๋˜์–ด์„œ ์ด์ œ author ๋ฅผ ๋นผ๋„ author๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
    class Meta:
        model = Blog
        fields = ['title', 'content', 'author', 'published_at', 'created_at', 
                  'updated_at', 'comment_count','author_name']

๐Ÿ“ Comment ๋ชจ๋ธ, generics CRUD ์ œ์ž‘

# models.py
class Comment(TimestampModel) :
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField('๋ณธ๋ฌธ')

    class Meta:
        verbose_name = '๋Œ“๊ธ€'
        verbose_name_plural ='๋Œ“๊ธ€ ๋ชฉ๋ก'
        ordering = ('-created_at', '-id')

# serializers.py
class CommentSerializer(serializers.ModelSerializer):
    blog = BlogSerializer(many=False, read_only=True)
    author = UserSerializer(many=False, read_only=True)
    class Meta:
        model = Comment
        fields = ['id', 'blog', 'author', 'content', ]

# generics_views.py
class CommentListCreateAPIView(ListCreateAPIView):
    queryset = Comment.objects.all()
    serializer_class = CommentSerializer
    permission_classes = [IsAuthenticatedOrReadOnly]

    def perform_create(self, serializer):
        blog=self.get_blog_object()
        serializer.save(author=self.request.user, blog = blog)

    def get_queryset(self):
        queryset = super().get_queryset()
        blog = self.get_blog_object()
        return queryset.filter(blog=blog)

    def get_blog_object(self):
        return get_object_or_404(Blog, pk=self.kwargs.get('blog_pk'))
# generics_urls.py
path('comment/<int:blog_pk>', generics_views.CommentListCreateAPIView.as_view(), name='comment_list_create'),

# DELETE,UPDATE
# ์ƒ์„ธํŽ˜์ด์ง€๊ฐ€ ์—†๊ธฐ์— ์ด๋ ‡๊ฒŒ ์ƒ์†๋ฐ›๋Š”๊ฒŒ ์ ์ ˆํ•จ
class CommentUpdateDestroyAPIView(UpdateAPIView,  DestroyAPIView):
    queryset = Comment.objects.all()
    serializer_class = CommentBlogSerializer
    permission_classes = [IsAuthorOrReadOnly]
# serializers.py
class CommentBlogSerializer(serializers.ModelSerializer):
    author = UserSerializer(many=False, read_only=True)
    blog = BlogSerializer(many=False, read_only=True)
    class Meta:
        model = Comment
        fields = ['id', 'author', 'content','blog' ]

๐Ÿš€ super().get_queryset()์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ  - ๋” ๊นŠ์ด ์ดํ•ดํ•˜๊ธฐ

๐Ÿ“Œ 1๏ธโƒฃ ๊ธฐ๋ณธ์ ์ธ ๋™์ž‘ ๋ฐฉ์‹ ์ •๋ฆฌ

Django REST Framework(DRF)์˜ ListAPIView๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ get_queryset()์„ ํ˜ธ์ถœํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

class ListAPIView(GenericAPIView, mixins.ListModelMixin):
    def get_queryset(self):
        assert self.queryset is not None, (
            f"{self.__class__.__name__} should either include a `queryset` attribute, "
            "or override the `get_queryset()` method."
        )
        return self.queryset.all()

โœ” ์ฆ‰, ListAPIView๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ self.queryset์„ ์‚ฌ์šฉํ•ด์„œ queryset.all()์„ ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
โœ” ๋งŒ์•ฝ ์šฐ๋ฆฌ๊ฐ€ queryset์„ ์ •์˜ํ•˜์ง€ ์•Š์œผ๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ“Œ 2๏ธโƒฃ queryset์„ ๋‹ค์‹œ ์„ค์ •ํ•˜๋Š” ์ด์œ 

โœ… 1. ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๊ธฐ๋ณธ ๋™์ž‘์„ ์œ ์ง€ํ•˜๋ฉด์„œ ํ™•์žฅํ•˜๊ธฐ ์œ„ํ•ด

๐Ÿ“Œ ์ž˜๋ชป๋œ ๋ฐฉ์‹ (๋ถ€๋ชจ์˜ ๊ธฐ๋Šฅ์„ ๋ฌด์‹œํ•˜๊ณ  ์ง์ ‘ queryset ์„ค์ •)

class BlogListAPIView(ListAPIView):
    serializer_class = BlogSerializer

    def get_queryset(self):
        return Blog.objects.filter(published_at__lte=timezone.now()).order_by("-created_at")

๐Ÿšจ ๋ฌธ์ œ์ 

  • ListAPIView๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ self.queryset์„ ํ™œ์šฉํ•˜๋Š” ๊ตฌ์กฐ์ธ๋ฐ, ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ถ€๋ชจ ํด๋ž˜์Šค(ListAPIView)์˜ queryset์„ ์•„์˜ˆ ๋ฌด์‹œํ•จ.
  • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‹ค๋ฅธ ํด๋ž˜์Šค์—์„œ BlogListAPIView๋ฅผ ์ƒ์†๋ฐ›์•„์„œ ํ™•์žฅํ•  ๋•Œ ๋ถ€๋ชจ์˜ get_queryset()์„ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ.

๐Ÿ“Œ ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ์‹ (๋ถ€๋ชจ์˜ ๊ธฐ๋Šฅ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ํ•„ํ„ฐ๋ง ์ถ”๊ฐ€)

class BlogListAPIView(ListAPIView):
    queryset = Blog.objects.all()  # ๊ธฐ๋ณธ QuerySet ์„ค์ •
    serializer_class = BlogSerializer

    def get_queryset(self):
        queryset = super().get_queryset()  # ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ get_queryset() ์‹คํ–‰
        return queryset.filter(published_at__lte=timezone.now()).order_by("-created_at")

โœ… ์ด ๋ฐฉ์‹์ด ์ข‹์€ ์ด์œ 
1. super().get_queryset()์„ ํ˜ธ์ถœํ•˜๋ฉด ๋ถ€๋ชจ ํด๋ž˜์Šค(ListAPIView)์—์„œ ์„ค์ •ํ•œ QuerySet์„ ๋จผ์ € ๊ฐ€์ ธ์˜จ ํ›„, ์ถ”๊ฐ€์ ์ธ ํ•„ํ„ฐ๋ง์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Œ.
2. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋งŒ์•ฝ ๋‹ค๋ฅธ ๊ณณ์—์„œ queryset์„ ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝํ•ด๋„ get_queryset()์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š์•„๋„ ๋จ.
3. super().get_queryset()์„ ์‚ฌ์šฉํ•˜๋ฉด ์ถ”ํ›„ BlogListAPIView๋ฅผ ์ƒ์†๋ฐ›์•„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ, get_queryset()์˜ ๋™์ž‘์„ ์œ ์ง€ํ•˜๋ฉด์„œ ์ถ”๊ฐ€์ ์ธ ํ•„ํ„ฐ๋ง์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Œ.


๐Ÿ“Œ 3๏ธโƒฃ ์ƒ์†์„ ํ™œ์šฉํ•˜๋Š” ์ด์œ 

โœ… ๋ถ€๋ชจ ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•˜๋ฉด์„œ๋„ ์œ ์—ฐํ•œ ์„ค๊ณ„๋ฅผ ํ•˜๊ธฐ ์œ„ํ•ด

ListAPIView๋ฅผ ์ƒ์†๋ฐ›์œผ๋ฉด ๊ธฐ๋ณธ์ ์ธ ๊ธฐ๋Šฅ(ListModelMixin์˜ ๊ธฐ๋Šฅ ํฌํ•จ)์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ ํ”„๋กœ์ ํŠธ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž์ถฐ ์ฟผ๋ฆฌ์…‹์„ ์ˆ˜์ •ํ•˜๊ณ  ์‹ถ์„ ๋•Œ get_queryset()์„ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ธ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

๐Ÿ“Œ ์ดํ•ด๋ฅผ ๋•๊ธฐ ์œ„ํ•œ ๋น„์œ 
โœ” ListAPIView๋Š” ์ž๋™์ฐจ์˜ ๊ธฐ๋ณธ ๋ชจ๋ธ
โœ” BlogListAPIView๋Š” ๊ธฐ๋ณธ ๋ชจ๋ธ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์˜ต์…˜(์ฟผ๋ฆฌ ํ•„ํ„ฐ๋ง ๋“ฑ)์„ ์ถ”๊ฐ€ํ•œ ์Šคํฌ์ธ ์นด

๐Ÿš— ์ž๋™์ฐจ ๊ธฐ๋ณธ ๋ชจ๋ธ (ListAPIView)

class Car:
    def drive(self):
        print("Driving a car")

๐ŸŽ ์ƒ์†์„ ํ™œ์šฉํ•œ ํ™•์žฅ (BlogListAPIView)

class SportsCar(Car):
    def drive(self):
        print("Super speed mode activated!")
        super().drive()  # โœ… ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๊ธฐ๋ณธ ๋™์ž‘์„ ์œ ์ง€ํ•˜๋ฉด์„œ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€

๐Ÿš€ ๊ฒฐ๊ณผ

my_car = SportsCar()
my_car.drive()

๐Ÿ“Œ ์ถœ๋ ฅ:

Super speed mode activated!
Driving a car

โœ… ์ฆ‰, ๋ถ€๋ชจ์˜ ๊ธฐ๋Šฅ์„ ์œ ์ง€ํ•˜๋ฉด์„œ๋„ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ํ•ต์‹ฌ!


๐Ÿ“Œ 4๏ธโƒฃ ๊ฒฐ๋ก 

์งˆ๋ฌธ์„ค๋ช…
๋ถ€๋ชจ ํด๋ž˜์Šค์— queryset์ด ์žˆ๋Š”๋ฐ ์™œ get_queryset()์—์„œ ๋˜ ์„ค์ •ํ•˜๋Š”๊ฐ€?๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๊ธฐ๋ณธ ๋™์ž‘์„ ์œ ์ง€ํ•˜๋ฉด์„œ ํŠน์ • ํ•„ํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด
๋ถ€๋ชจ์˜ queryset์„ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ ๋˜๋Š”๊ฐ€?๊ฐ€๋Šฅํ•˜์ง€๋งŒ, super().get_queryset()์„ ์‚ฌ์šฉํ•˜๋ฉด ์œ ์ง€๋ณด์ˆ˜์™€ ํ™•์žฅ์„ฑ์ด ๋” ์ข‹์•„์ง
๊ทธ๋Ÿผ queryset์„ ์„ค์ •ํ•˜๊ณ  get_queryset()์„ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜๋ฉด ์™œ super()๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๊ฐ€?๋‹ค๋ฅธ ๊ณณ์—์„œ queryset์ด ๋ณ€๊ฒฝ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ. super().get_queryset()์„ ์‚ฌ์šฉํ•˜๋ฉด ๋™์ ์œผ๋กœ ๋ณ€๊ฒฝ๋œ ๋ถ€๋ชจ์˜ queryset์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Œ

๐Ÿ”ฅ ์ฆ‰, super().get_queryset()์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ถ€๋ชจ์˜ queryset์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•„ํ„ฐ๋ง์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์–ด์„œ ๋” ์œ ์—ฐํ•˜๊ณ  ํ™•์žฅ์„ฑ์ด ๋†’์•„์ง„๋‹ค! ๐Ÿš€

0๊ฐœ์˜ ๋Œ“๊ธ€

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด