728x90
๐กDRF๋?
- Django ๊ธฐ๋ฐ REST API ์๋ฒ ๊ตฌ์ถ์ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
Django์ ๋ค๋ฅด๊ฒ ํ๋ก ํธ์๋๋ฅผ ๊ฐ๋ฐํ์ง ์๊ธฐ ๋๋ฌธ์ Model๊ณผ View ๊ทธ๋ฆฌ๊ณ Serializer๊ฐ ๋ฉ๋๋ค. DRF์ ๊ตฌ์กฐ์ ๋ํด์ ์ง์นญํ๋ ํจํด์ ์์ต๋๋ค. ๋ฐฑ์๋์ ์ฉ๋๋ก ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ Template์ ์ฌ์ฉํ์ง ์์ต๋๋ค. ๋์ , JSONํ์ผ์ ํ์์ผ๋ก ํ๋ก ํธ์๋์ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ต๋๋ค.
- Django์์ ์ฐจ์ด์
- DRF ๋ก์ง
๐ง๐ปDRF ๋ชจ๋ ์ค๋ช
DRF ๋ชจ๋ ์ค๋ช
models.py
- ๋ชจ๋ธ ์ ์
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ์ ์ถ์ํํ ๊ฐ๋
- Django ORM์ ํตํด ํ์ด์ฌ ๋ฌธ๋ฒ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์์
- Django์์ ๋ฐ์ดํฐ๋ JSON์ด๋ ์ ์ฌํ ํฌ๋งท์ด ์๋, ํ์ด์ฌ ๊ฐ์ฒด์ ํํ๋ก ์ ์ฅ๋จ
- class Product(models.Model): """ ์ ํ ์ ๋ณด ๋ชจ๋ธ """ name = models.CharField(max_length=255) image = ImageField(upload_to='photos') price = models.IntegerField() quantity = models.IntegerField(default=0) description = models.TextField() pub_date = models.DateTimeField(auto_now_add = True) def __str__(self): return '{} {}'.format(self.name, self.pub_date)
views.py
- request๋ฅผ ๋ฐ์ ๋น์ฆ๋์ค ๋ก์ง์ ์ฒ๋ฆฌํ ๋ค response๋ฅผ ๋ฐํ
- ๋ชจ๋ธ ๋ฐ์ดํฐ ๋ถ๋ฌ์ค๊ธฐ / ์์ฑ / validation์ serializer๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- ๊ตฌํB. ๋น์ฆ๋์ค ๋ก์ง์ด ๋ณต์กํด์ง๋ฉด, ๋ณ๋ ํ์ผ์ ์์ฑํ์ฌ ๊ตฌํํฉ๋๋ค.
- view์ ๋ชจ๋ ์ฝ๋๋ฅผ ์ ์ผ๋ฉด ํด๋น API์ ๊ธฐ๋ฅ์ ์ดํดํ๊ธฐ ์ด๋ ต์ต๋๋ค.
- ํ์ ํจ์๋ค์ ๋ณ๋๋ก unitํ ์คํธ ํด์ผํ๊ธฐ ๋๋ฌธ์ ๋ณ๋ ํ์ผ ๋ฐ ํจ์๋ก ๊ตฌํ
- A. ๊ฐ๋จํ ๋น์ฆ๋์ค ๋ก์ง์ view์์ ๊ตฌํํฉ๋๋ค.
# A ์์
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer(data=request.data)
def post(self, request):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid(raise_exception=False):
serializer.save()
user = serializer.get_object()
# ๊ฐ๋จํ ๋ก์ง๋ค.
send_push_notification(user, '00 ์๋น์ค์ ์ค์ ๊ฑธ ํ์ํฉ๋๋ค')
return Response(serializer.data, 200)
return Response('error', 400)
# B ์์
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer(data=request.data)
def post(self, request):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid(raise_exception=False):
serializer.save()
user = serializer.get_object()
# ๋ณต์กํ ๋ก์ง๋ค
# ex) ์ด๋๋ฏผ ์ ์ ๋ฉด, 00 ๋ก์ง/ ์ผ๋ฐ์ ์ ๋ฉด 00 ๋ก์ง / ์ผ๋ฐ์ ์ ์ค ์ฑ์ผ๋ก ๊ฐ์
ํ๋ฉด Push ์๋ฆผ, ์น์ผ๋ก ๊ฐ์
ํ๋ฉด SMS ๋ฑ๋ฑ
if user.has_role('SYSYEM_ADMIN'):
# do_something_here
elif ...:
# do_something_here
elif ...:
# do_something_here
elif ...:
# do_something_here
# do_something_here
return Response(serializer.data, 200)
return Response('error', 400)
# B ๋ณต์กํ ๋ก์ง๋ค์ ๋ณ๋๋ก ๊ตฌํํ ์์
from user.service import UserService
# ๋๋
from user.utils import userUtils
class UserViewSet(viewsets.ModelViewSet):
serializer_class = UserSerializer(data=request.data)
def post(self, request):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid(raise_exception=False):
serializer.save()
user = serializer.get_object()
service = UserService(user)
service.check_and_set_default_role()
service.send_notification_by_role()
return Response(serializer.data, 200)
return Response('error', 400)
# ์์ UserService ๋๋ UserUtils ์์
class UserService:
user = None
DEFAULT_ROLE = "NORMAL_USER"
def __init__(self, user):
self.user = user
def check_and_set_default_role(self):
# if self.roles == [] ๋กค์ด ์์ผ๋ฉด ๋ํดํธ ๋กค์ ๋ฃ์ด์ค๋ค.
...
def send_notification_by_role(self):
# ex) ์ด๋๋ฏผ ์ ์ ๋ฉด, 00 ๋ก์ง/ ์ผ๋ฐ์ ์ ๋ฉด 00 ๋ก์ง / ์ผ๋ฐ์ ์ ์ค ์ฑ์ผ๋ก ๊ฐ์
ํ๋ฉด Push ์๋ฆผ, ์น์ผ๋ก ๊ฐ์
ํ๋ฉด SMS ๋ฑ๋ฑ
# ...
# ํ์ผ๋ก๋, ๋กค ๊ตฌ๋ถํ๋๊ฑด ์ฌ๊ธฐ์ ํ๊ฒ ์ง๋ง ๋ฉ์ธ์ง ๋ณด๋ด๋ ๊ธฐ๋ฅ์ MessageService ์์ ๊ฐ์ ธ๋ค ์๋๋ค.
if ...:
MessageService.send_push_notification(user, 'ํ์ํฉ๋๋ค!')
elif ...:
MessageService.send_SMS(user, 'ํ์ํฉ๋๋ค!')
serializers.py
- ์ง๋ ฌํ/์ญ์ง๋ ฌํ ์ญํ ์ํ
- ๋ชจ๋ธ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ์ ์ถ์ํํ ๊ฐ๋ ์ด๋ฉฐ, ํ์ด์ฌ์ ๊ฐ์ฒด ํ์์ผ๋ก ์ ์ฅ์ด ๋ฉ๋๋ค.
- ์ฐ๋ฆฌ๋ ํ๋ก ํธ์๋์ JSON ํ์์ผ๋ก ์ ๋ณด๋ฅผ ์ฃผ๊ณ ๋ฐ๋๋ฐ ์ง๋ ฌํ ๊ณผ์ ์ ์๋ตํ๊ณ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๊ฒ ๋๋ค๋ฉด ํ์ด์ฌ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด์ฃผ๊ฒ๋๊ณ ํด๋ผ์ด์ธํธ๋ ์ด๋ฅผ ์ฝ์ง ๋ชปํฉ๋๋ค.
- ํ์ด์ฌ ๋ฐ์ดํฐ ๊ฐ์ฒด๋ฅผ ๋ฌธ์์ด๋ก ๋ณํํ๋ ์์ ์ ์ง๋ ฌํ(Serialize)๋ผ๊ณ ํฉ๋๋ค.
- ๋ฐ๋๋ก ํด๋ผ์ด์ธํธ ์ธก์์ ๋ณด๋ด์ฃผ๋ ๋ฐ์ดํฐ ์ญ์ ํ์ด์ฌ ๊ฐ์ฒด๋ก ๋ณํํด์ผํ๋๋ฐ ์ด๋ฅผ ์ญ์ง๋ ฌํ(Deserialize)๋ผ๊ณ ํฉ๋๋ค.DRF ๋ด์์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋ Django์ ๋ชจ๋ธ์ ํตํด ์ ์ฅํฉ๋๋ค.
- ์ผ๋ฐ์ ์ธ serializer ์ฌ์ฉ๋ฒ
- validation
- ์ ์ฒด validation
- ํ๋ validation - ๊ฐ ํ๋๋ณ๋ก validation์ ์งํํฉ๋๋ค.
- validation ๊ณผ์ ์์ ๋ฐ์ดํฐ๋ฅผ ์ ์ ํ๊ธฐ๋ ํฉ๋๋ค.
- fields
- ํ์ํ ํ๋๋ง ์ง์ ํ๋ ๊ฒฝ์ฐ๋ฅผ ๋งํฉ๋๋ค.
- Field ํจ์๋ค
- ReadOnlyField - ํ์ํ ๋ฐ์ดํฐ ์ฐพ๊ธฐ(Join)
- SerializerMethodField - ํ์ํ ๋ฐ์ดํฐ ๋ง๋ค๊ธฐ
- ๋ฑ๋ฑ
- validation
class UserSerializer(serializers.ModelSerializer):
is_system_admin = serializers.SerializerMethodField()
company_name = serializers.ReadOnlyField(source='company.name', read_only=True)
# ์์ฒ๋ผ ์ ์ํ๋ฉด , user.company.name ์ company_name ์ ๋ด์์ค๋ค.
class Meta:
model = User
# 2. fields,
# tip, List API ์ฒ๋ผ ๋ง์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ ๋์๋ ๋ฌด์กฐ๊ฑด '__all__' ํ๊ธฐ๋ณด๋ค ๋ฑ ์ฌ์ฉํ๋ ํ๋๋ง ์ฐ๋๊ฒ์ข์.
# SELECT * ๋ณด๋ค SELECT first_name, .. ์ด ํจ์จ์ ์ด๊ธฐ์. ๋ฐ์ดํฐ ํฌ๊ธฐ๋ ๊ทธ๋ ๊ณ .
fields = [
"last_name",
"first_name",
"full_name", # Model ์ชฝ @property๋ ์ด๋ ๊ฒ ๋ฐ๋ก ์ฌ์ฉ ๊ฐ๋ฅ!
"is_system_admin",
"company_name"
]
# SerializerMethodField ๋ ํ๋๋ช
์์ get_ ๋ถ์ฌ์ ํจ์๋ฅผ ๊ตฌํ, ์ํ๋ ๊ฐ์ ๋ง๋ค ์ ์์.
def get_is_system_admin(self, obj):
return obj.has_role('SYSTEM_USER') # ์ฌ๊ธฐ์๋ Model function์ ์ผ์ง๋ง, ์ํ๋๋๋ก ์ฌ์ฉ ๊ฐ๋ฅ.
# 1-a. ์ ์ฒด
def validate(self, data):
if data['fisrt_name'] == data['last_name']:
raise serializers.ValidationError("fisrt_name ๊ณผ last_name ์ด ๊ฐ์ต๋๋ค. ๊ฐ ํ์ธํ์ธ์.")
# 1-c, ๋ง์ฝ full_name ์ด ๋ชจ๋ธ ํ๋์๋ค๋ฉด, ์ฌ๊ธฐ์ ๋ง๋ค์ด๋ ๋ฉ๋๋ค.(์ด๊ฑด ์ ์์ธ์ง๋ ๋ชจ๋ฅด๊ฒ ์ง๋ง, ๊ฐ๋ ์ฌ์ฉ)
if not data.get('full_name'):
data['full_name'] = data['last_name'] + data['first_name']
return data
# 1-b. ํ๋๋ณ
# ํ๋๋ช
์์ validate_ ๋ถ์ด๋ฉด ์๋์ผ๋ก ๋์, ์๋๋ first_name ์ฒดํฌํ๋ ๋ก์ง.
def validate_fist_name(self, value):
if len(value) < 10:
raise serializers.ValidationError("first_name should be less than 10 characters")
# 1-c, ๋ง์ฝ first_name์ ๊ณต๋ฐฑ์ ์ ์ธํ๋ ๊ท์น์ด๋ผ๋ฉด, ์ฌ๊ธฐ์ ์ฒ๋ฆฌํด๋ ๋ฉ๋๋ค(์ด๊ฑด ์ ์์ธ์ง๋ ๋ชจ๋ฅด๊ฒ ์ง๋ง, ๊ฐ๋ ์ฌ์ฉ)
value = value.replace(" ", "")
return value
urls.py
- ํ๋ก์ ํธ์ ์ฑ์ url ์ฃผ์๋ฅผ ๋ฑ๋กํ๋ ํ์ผ
- as_views๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์ router๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค.
# as_view ์ฌ์ฉ
from snippets.views import SnippetViewSet, UserViewSet, api_root
from rest_framework import renderers
snippet_list = SnippetViewSet.as_view({
'get': 'list',
'post': 'create'
})
snippet_detail = SnippetViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
})
snippet_highlight = SnippetViewSet.as_view({
'get': 'highlight'
}, renderer_classes=[renderers.StaticHTMLRenderer])
user_list = UserViewSet.as_view({
'get': 'list'
})
user_detail = UserViewSet.as_view({
'get': 'retrieve'
})
# format_suffix_patterns์ด ํ์๋ ์๋๋๋ค. ์ ๊ฑฐํ๊ณ ๋ฆฌ์คํธ ํ์์ผ๋ก๋ง ๋๊ฒจ๋ ์ข์ต๋๋ค.
urlpatterns = format_suffix_patterns([
path('', api_root),
path('snippets/', snippet_list, name='snippet-list'),
path('snippets/<int:pk>/', snippet_detail, name='snippet-detail'),
path('snippets/<int:pk>/highlight/', snippet_highlight, name='snippet-highlight'),
path('users/', user_list, name='user-list'),
path('users/<int:pk>/', user_detail, name='user-detail')
])
# router ์ฌ์ฉ
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views
# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet,basename="snippet")
router.register(r'users', views.UserViewSet,basename="user")
# The API URLs are now determined automatically by the router.
urlpatterns = [
path('', include(router.urls)),
]
๊ฐ๋ฐ ์์
- models → serializers → views → urls ์์๋๋ก ๊ฐ๋ฐํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ ๋๋ค.
- ์๋ ๊ทธ๋ฆผ์ DRF์์ ์ฌ์ฉํ๋ ๋ชจ๋์ ๋์ดํ ๊ฒ์ ๋๋ค.
DRF ์ฌํ๊ฐ๋
1. User ๋ชจ๋ธ ์ปค์คํฐ๋ง์ด์ง
- User ๋ชจ๋ธ์ ์ปค์คํฐ๋ง์ด์ง ํ๋ ์ด์
- ํ์ฅ - ์ ๊ณต๋๋ ๊ธฐ๋ฅ ์ธ์ ๊ธฐ๋ฅ์ ๋ค๋ฃจ๊ธฐ ์ํด์
- ๋ณ๊ฒฝ - ์ ๊ณต๋๋ ๊ธฐ๋ฅ์ ๋ด๊ฐ ํ์ํ ๊ธฐ๋ฅ์ผ๋ก ๋ณ๊ฒฝํ๊ธฐ ์ํด์
- ์์ ์ค๋ช ํ ๋ด์ฉ๋๋ก User ๋ชจ๋ธ์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ๋ค์ํฉ๋๋ค. ๋ก๊ทธ์ธ ํ๊ธฐ ์ํ ์๋จ์ผ๋ก id๋ฅผ ์ฌ์ฉํ๋ ๊ณณ์ด ์๊ณ , ์ด๋ฉ์ผ์ ์ฌ์ฉํ๋ ๊ณณ์ด ์๋ฏ์ด ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๋ฐฉํฅ์ผ๋ก ๊ฐ๋ฐ์ ์งํํ๊ธฐ ์ํด์ ๋ชจ๋ธ ์ปค์คํฐ๋ง์ด์ง์ ์งํํฉ๋๋ค.
- ์ฝ๋๋ ์ ๊ณต๋์ง ์์ต๋๋ค. ์ค์ค๋ก ๋ชจ๋ธ์ ์ปค์คํฐ๋ง์ด์งํด์ ๊ณผ์ ๋ฅผ ํ์ด๋ณด์๊ธฐ ๋ฐ๋๋๋ค.
# permissions.py
class IsOwnerOrReadOnly(BasePermission):
"""
์์ฑ์ ์ธ ์ฝ๊ธฐ ๊ถํ๋ง ๋ถ์ฌ
JWT ํ ํฐ์ decode, obj์ user์ ํด๋น user๊ฐ ์ผ์นํ๋์ง ํ์ธ
ERR03
"""
message = "[Access Denied: ERR03] ๊ฒ์๊ธ ์์ , ์ญ์ ๊ถํ์ด ์์ต๋๋ค."
def has_object_permission(self, request, view, obj):
if request.method in SAFE_METHODS:
return True
else:
token = request.headers.get('Authorization').split(" ")[1]
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=settings.ALGORITHM)
token_user = payload.get('user_id')
return obj.user.id == token_user
2. Permission, Test, Statistic, Logging
- ๊ถํ(Permission) - Github
- ์ฐ๋ฆฌ๋ ์ฑ์ ๋ง๋ค ๋ ๊ถํ์ ์ ์ดํด์ผํฉ๋๋ค.
- DRF์์๋ ๊ถํ์ ๊ดํ ์ฌ๋ฌ ํด๋์ค๊ฐ ์์ต๋๋ค.
- BasePermission์ ์์๋ฐ์ ๊ถํ ์ค์ ์ ์ปค์คํฐ๋ง์ด์งํ ์ ์์ต๋๋ค.
- ์๋์๋ jwt๋ฅผ HTTP ์์ฒญ ํค๋์ Authorization์ผ๋ก ๋ฃ์์ ๋, Owner๋ง ์ฝ์ ์ ์๋๋กํ๋ ์ปค์คํ ์ฝ๋์ ๋๋ค.
- ํ
์คํธ(Test)
- TDD(Test Driven Development) - ํ ์คํธ ์ฃผ๋ ํ ๊ฐ๋ฐ์ด๋ผ๋ ๋ป์ผ๋ก ๊ฐ๋ฐ์ ์์ด ๊ทธ ์งํ์ ๋ด๋นํ๋ ์ฃผ์ฒด๋ฅผ ํ ์คํธ์ ๋๊ณ ์์ต๋๋ค.
- ํ ์คํธ์ ์ข ๋ฅ๋ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์์ผ๋, ๋ด์ฉ์ด ๋ฐฉ๋ํ์ฌ “์ํํธ์จ์ด ๊ฐ๋ฐ ๋ฐฉ๋ฒ๋ก ”์ด๋ผ๋ ์ฃผ์ ๋ก ์ง์ ๊ฒ์ํ์ฌ ๋ณด์๊ธฐ ๋ฐ๋๋๋ค.
- ์๋์ ํ ์คํธ๋ django ํจํค์ง๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ์ ๋๋ค. ์ถ๊ฐ์ ์ผ๋ก DRF์ ํ ์คํธ ๊ธฐ๋ฅ์ ์ฌ์ฉํด๋ณด๊ณ ์ถ์ผ์๋ค๋ฉด DRF Testing์ ํ์ธํด์ฃผ์๊ธธ ๋ฐ๋๋๋ค.
- TDD ํ๋ก์ธ์ค
- ๊ตฌํํ๋ ค๋ ๊ธฐ๋ฅ์ ๋ํ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๋ค.
- ํ ์คํธ๋ฅผ ์คํ์ํค๊ณ , ๊ธฐ๋ฅ์ด ์์ผ๋ ์คํจํ๋ค.
- ํ ์คํธ๋ฅผ ํต๊ณผํ ์ ์๋ ์ต์ํ์ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ค.
- ํ ์คํธ๋ฅผ ์คํ์ํค๊ณ , ํต๊ณผ์ํค๋ฉด ์ฝ๋๋ฅผ ์ ๋ฆฌํ๋ค.
- ๋ชจ๋ ๊ธฐ๋ฅ์ ๊ตฌํํ ๋๊น์ง ์ด๋ฅผ ๋ฐ๋ณตํ๋ค.
- ์์
- ๋ชจ๋ธ์ ๊ดํ ํ ์คํธ์ ๋๋ค. ์์ฑ์ด ๋๋๋ฉด ์๋ ๋ช ๋ น์ด๋ฅผ ํตํด ํ ์คํธ๋ฅผ ์งํํฉ๋๋ค.
- ์๋ฌด๊ฒ๋ ์๊ธฐ ๋๋ฌธ์ ํต๊ณผํ์ง ๋ชปํ ๊ฒ์ ๋๋ค. ์ด์ ํ ์คํธ๋ฅผ ํต๊ณผํ ์ ์๋ ๋ชจ๋ธ์ ์์ฑํฉ๋๋ค.
from django.db import models class Book(models.Model): title = models.CharField(max_length=128) author = models.CharField(max_length=128)
- migration์ ์งํํฉ๋๋ค.
$ python manage.py makemigrations $ python manage.py migrate $ python manage.py test
- view ํ ์คํธ๋ฅผ ์งํํ๋๋ก ํฉ๋๋ค. ํ ์คํธ์ฝ๋๋ฅผ ๋จผ์ ์์ฑํ๋๋ก ํฉ๋๋ค.
# tests.py from django.test import TestCase from .models import Book from rest_framework.test import APIClient from rest_framework import status class ModelTest(TestCase): def setUp(self): self.book_title = "My Book" self.book_author = "Hyeonsoo" self.book = Book(title=self.book_title, author=self.book_author) def test_model_can_create_a_bucketlist(self): old_count = Book.objects.count() self.book.save() new_count = Book.objects.count() self.assertNotEqual(old_count, new_count) class ViewTest(TestCase): def setUp(self): self.client = APIClient() self.book_data = {'title': 'My Book 2', 'author': 'Hyeonsoo'} self.response = self.client.post('/api/books/', self.book_data, format="json") def test_api_can_create_a_book(self): print(self.response.content) self.assertEqual(self.response.status_code, status.HTTP_201_CREATED)
- ์ญ์๋ ์๋ฌด๊ฒ๋ ์์ฑ๋์ด ์์ง ์์์ ํต๊ณผํ ์ ์์ ๊ฒ์ ๋๋ค. ์ด์ ๋๋จธ์ง ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค.
# serializers.py from rest_framework import serializers from .models import Book class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = ('id', 'title', 'author')
# views.py from rest_framework import generics from .serializers import BookSerializer from .models import Book class CreateView(generics.CreateAPIView): queryset = Book.objects.all() serializer_class = BookSerializer def perform_create(self, serializer): serializer.save()
# urls.py from django.urls import path from .views import CreateView urlpatterns = [ path('books/', CreateView.as_view()), ]
- ํต๊ณ(Statistic)
- ์ฐ๋ฆฌ๋ ORM์ ์ฌ์ฉํ์ฌ Database์ ์ฐ๋ํ๊ณ ๋ฐ์ดํฐ๋ฅผ ์์ฑ, ์์ , ์กฐํ, ์ญ์ ํฉ๋๋ค.
- DB์ ์ ์ฅ๋ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ์ด์ฌ์์ ์ฟผ๋ฆฌ๋ฌธ์ ์์ฑํ์ฌ ๋ฐ์ดํฐ์ ํต๊ณ๋ฅผ ์ถ๋ ฅํ ์ ์์ต๋๋ค.
- ์์
# views.py class UserGenderStatisticsView(APIView): """ ์ ์ ์ ๋จ๋ ์๋ฅผ ํ์ธํฉ๋๋ค. """ def get(self, request): male_cnt = User.objects.filter(gender="Male").count() female_cnt = User.objects.filter(gender="Female").count() return Response({"male_count": male_cnt, "female_count": female_cnt}, status=status.HTTP_200_OK) class NoticeBoardGenderStatisticsView(APIView): """ ๊ณต์ง์ฌํญ ๊ฒ์ํ์์ ๋จ๋ ์ ๋ถํฌ๋ฅผ ํ์ธํฉ๋๋ค. """ def get(self, request): male_cnt = NoticeBoard.objects.filter(user__gender="Male").count() female_cnt = NoticeBoard.objects.filter(user__gender="Female").count() return Response({"male_count": male_cnt, "female_count": female_cnt}, status=status.HTTP_200_OK)
- ๋ก๊ทธ(Logging)
- ๋ก๊ทธ ๋ฐ์ดํฐ๋ ๊ธฐ๋ก์ ์๋ฏธ๋ฅผ ๊ฐ์ง๋๋ค. IT์ธํ๋ผ์์ ๋ฐ์ํ๋ ๋ชจ๋ ์ํฉ์ ๋ฐ์ดํฐ๋ผ๊ณ ํ ์ ์์ต๋๋ค.
- ์ฌ๊ณ ๋ ์ฅ์ ๊ฐ ๋ฐ์ ์, ์์ธ์ ํ์ ํ๊ณ ๋์ฒํ ์ ์๋ ๊ทผ๊ฑฐ๋ฅผ ์ ๊ณตํ๊ธฐ ๋๋ฌธ์ ์ค์ํ๋ค๊ณ ํ ์ ์์ต๋๋ค.
- ๋ํ ๊ธฐ๋ก๋ ๊ณ ๊ฐ์ ๋ก๊ทธ๋ฐ์ดํฐ๋ฅผ ํ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ๊ฑฐ๋ ML ๋ชจ๋ธ์ ํ์ฉํ ์๋ ์์ต๋๋ค.
- ๊ด๋ จ ๋ชจ๋
- drf-tracking
- # views.py from rest_framework import generics from rest_framework.response import Response from rest_framework_tracking.mixins import LoggingMixin class SampleView(LoggingMixin): def get(self, request): return Response('with logging')
- django-request-logging
# loggings.py import logging logger = logging.getLogger(__name__) def some_view(request): ... if some_risky_state: logger.warning('Platform is running at risk')
- Logging in JSON formatter ๋ ํผ๋ฐ์ค
- Logging ์ต์ข
๋ชฉ์ ์ ํํ
- JSON ํ์
3. ๊ถํ ์ค์ ๋ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
- JWT Signin(๋๋ Login) ๊ธฐ๋ฅ์ ํตํด ๋ถ์ฌ๋ฐ์ ACCESS_KEY๋ฅผ HTTP ํค๋์ Authorization์ด๋ผ๋ KEY ๊ฐ์ ์ถ๊ฐํ ํ VALUE์๋ Bearer {ํค๊ฐ} ์ ํํ๋ก ๋ฃ์ด์ฃผ์๋ฉด ๋ฉ๋๋ค.
- ์ฌ๊ธฐ์ {}๋ฅผ ์ ๊ฑฐํ ํํ๋ก ํค๊ฐ๋ง ์ ๋ ฅํด์ฃผ์๋ฉด ๋ฉ๋๋ค.
DRF ์ค์น ๋ฐ ์ด๊ธฐ ์ค์
1. DRF ํจ์นํค๋ฅผ ์ค์นํฉ๋๋ค.
$ pip install djangorestframework
2. INSTALLED APP์ ์ถ๊ฐํด์ค๋๋ค.
# settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework', # ์ฑ์ ๋ฑ๋กํฉ๋๋ค.
]
# DRF setting - ์์์
๋๋ค.
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
],
'DEFAULT_PARSER_CLASSES': [
'rest_framework.parsers.JSONParser',
]
}
TIME_ZONE = 'Asia/Seoul'
- REST_FRAMEWORK ๋ผ๋ ํ๊ฒฝ๋ณ์ ์์์ ๋ค์ํ ์ค์ ์ ํ ์ ์์ต๋๋ค.
728x90
๋ฐ์ํ
'python > Django' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
DoesNotExist vs MultipleObjectsReturned - ORM ์์ธ์ฒ๋ฆฌ (0) | 2025.05.08 |
---|---|
OperationalError ํด๊ฒฐ ๋ฐฉ๋ฒ โ DB ์ปค๋ฅ์ ๋๊น (MySQL) (0) | 2025.05.08 |
transaction.atomic() ํธ๋์ญ์ ์ฒ๋ฆฌํ๊ธฐ (0) | 2025.04.30 |
ValidationError โ API/Form ๊ฒ์ฆ (0) | 2025.04.28 |
IntegrityError โ ๋๋ ์ ์ฅ ์ค ์ถฉ๋ ํด๊ฒฐ (0) | 2025.04.28 |