: 외래 키를 사용하여 참조하는 object를 역으로 찾을 수 있다.
: 정참조와 같은 방식으로 사용가능
# models.py
class User(AbstractBaseUser):
...
class UserProfile(models.Model):
user = models.OneToOneField(to=User)
hobby = models.ManyToManyField("Hobby", verbose_name="취미")
...
# view.py
def get(self, request):
user = request.user
user_profile = user.userprofile # 역참조
user2 = user_profile.user # 정참조, user == user2
: _set을 붙여 사용가능
# models.py
class UserProfile(models.Model):
user = models.OneToOneField(to=User)
hobby = models.ManyToManyField("Hobby", verbose_name="취미")
...
class Hobby(models.Model):
...
# views.py
def get(self, request):
user = request.user
hobbys = user.userprofile.hobby.all() # 정참조
for hobby in hobbys:
# exclde : 매칭 된 쿼리만 제외, filter와 반대
# annotate : 필드 이름을 변경해주기 위해 사용, 이외에도 원하는 필드를 추가하는 등 다양하게 활용 가능
# values / values_list : 지정한 필드만 리턴 할 수 있음. values는 dict로 return, values_list는 tuple로 ruturn
# F() : 객체에 해당되는 쿼리를 생성함
hobby_members = hobby.userprofile_set.exclude(user=user).annotate(username=F('user__username')).values_list('username', flat=True) # 역참조
hobby_members = list(hobby_members)
print(f"hobby : {hobby.name} / hobby members : {hobby_members}")
# result print
"""
hobby : 산책 / hobby members : ['user1']
hobby : 음악감상 / hobby members : ['user1', 'user2']
hobby : 스쿠버다이빙 / hobby members : ['user2']
hobby : 여행 / hobby members : ['user2']
"""
: django의 object, queryset 인스턴스 등 복잡한 테이터들을 json같은 다른 콘텐츠 유형으로 쉽게 변환 할 수 있다.
Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into JSON, XML or other content types.
https://www.django-rest-framework.org/api-guide/serializers/
# serializer.py (사용할 앱 디렉토리 안에 생성)
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
# serializer에 사용될 model, field지정
model = User
# 모든 필드를 사용하고 싶을 경우 fields = "__all__"로 사용
fields = ["username", "password", "fullname", "email"]
# views.py
from rest_framework.response import Response
from rest_framework import status
from user.serializers import UserSerializer
def get(self, request):
user = request.user
# serializer에 queryset을 인자로 줄 경우 many=True 옵션을 사용해야 한다.
serialized_user_data = UserSerializer(user).data
return Response(serialized_user_data, status=status.HTTP_200_OK)
# return data
"""
{
"username": "user",
"password": "pbkdf2_sha256$320000$u5YnmKo9luab9csqWpzRsa$pKfqHnBiF5Rgdo1Mj9nxNOdhpAl9AhPVXFPXkbPz7Mg=",
"fullname": "user's name",
"email": "user@email.com"
}
"""
: 외래 키 관계에 있는 테이블이 있을 경우, 해당 테이블의 serializer를 생성해 함께 사용할 수 있다.
# serializer.py
from .models import User, UserProfile
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = "__all__"
class UserSerializer(serializers.ModelSerializer):
userprofile = UserProfileSerializer()
class Meta:
# serializer에 사용될 model, field지정
model = User
# 모든 필드를 사용하고 싶을 경우 fields = "__all__"로 사용
fields = ["username", "fullname", "email", "userprofile"]
# view.py
class UserView(APIView):
permission_classes = [permissions.AllowAny]
def get(self, request):
all_users = User.objects.all()
print(type(UserSerializer(all_users, many=True).data))
return Response(UserSerializer(all_users, many=True).data)
# response reusult
[
{
"username": "admin",
"fullname": "",
"email": "",
"userprofile": {
"id": 1,
"intro": "admin's profile",
"age": 29,
"interest": "게임",
"user": 1
}
},
{
"username": "dongwoo",
"fullname": "김동우",
"email": "esdx@daum.net",
"userprofile": {
"id": 2,
"intro": "dongwoo's profile",
"age": 29,
"interest": "movie",
"user": 2
}
}
]
: 원하는 필드를 추가할 수 있다.
# models.py
class Hobby(models.Model):
hobby = models.CharField(max_length=10)
def __str__(self):
return f"{self.hobby}"
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
intro = models.TextField()
age = models.IntegerField()
hobby = models.ManyToManyField(Hobby)
def __str__(self):
return f"{self.user.username}'s profile"
# serializer.py
class HobbySerializer(serializers.ModelSerializer):
same_hobby_people = serializers.SerializerMethodField()
# obj : hobby 객체
def get_same_hobby_people(self, obj):
people = obj.userprofile_set.all()
name_list = [ person.user.username for person in people ]
return name_list
class Meta:
model = Hobby
fields = ['hobby', 'same_hobby_people']
class UserProfileSerializer(serializers.ModelSerializer):
hobby = HobbySerializer(many=True)
class Meta:
model = UserProfile
fields = ['age', 'hobby']
class UserSerializer(serializers.ModelSerializer):
userprofile = UserProfileSerializer()
class Meta:
# serializer에 사용될 model, field지정
model = User
# 모든 필드를 사용하고 싶을 경우 fields = "__all__"로 사용
fields = ["username", "fullname", "email", "userprofile"]
# response result
[
{
"username": "admin",
"fullname": "",
"email": "",
"userprofile": {
"age": 29,
"hobby": [
{
"hobby": "게임",
"same_hobby_people": [
"dongwoo",
"admin"
]
},
{
"hobby": "코딩",
"same_hobby_people": [
"dongwoo",
"admin",
"soojin"
]
}
]
}
},
{
"username": "dongwoo",
"fullname": "김동우",
"email": "esdx@daum.net",
"userprofile": {
"age": 29,
"hobby": [
{
"hobby": "크로스핏",
"same_hobby_people": [
"dongwoo"
]
},
{
"hobby": "게임",
"same_hobby_people": [
"dongwoo",
"admin"
]
},
{
"hobby": "코딩",
"same_hobby_people": [
"dongwoo",
"admin",
"soojin"
]
}
]
}
},
{
"username": "soojin",
"fullname": "수진",
"email": "esdx@naver.com",
"userprofile": {
"age": 29,
"hobby": [
{
"hobby": "코딩",
"same_hobby_people": [
"dongwoo",
"admin",
"soojin"
]
}
]
}
}
]
: views.py의 접근 권한을 설정할 수 있다.
permissions.AllowAny
: 모든 사용자를 대상으로 접근 허용permissions.IsAuthenticated
: 로그인 된 사용자를 대상으로 접근 허용# permissions.py
from rest_framework.permissions import BasePermission
from datetime import timedelta
from django.utils import timezone
class RegistedMoreThanAWeekUser(BasePermission):
"""
가입일 기준 1주일 이상 지난 사용자만 접근 가능
"""
message = '가입 후 1주일 이상 지난 사용자만 사용하실 수 있습니다.'
def has_permission(self, request, view):
return bool(request.user and request.user.join_date < (timezone.now() - timedelta(days=7)))
# views.py
from .permissions import RegistedMoreThanAWeekUser
# 유저 뷰 기능
class UserView(APIView):
permission_classes = [RegistedMoreThanAWeekUser]
def get(self, request):
all_users = User.objects.all()
return Response(UserSerializer(all_users, many=True).data)
# result
{
"detail": "가입 후 1주일 이상 지난 사용자만 사용하실 수 있습니다."
}