Q를 사용하면 쿼리에 and, or를 적용할 수 있다. and는 &, or는 |로 연결한다. Q의 인자로 get이나 filter를 사용할 때 쓰는 조건을 적어준다.
아래는 예시이다. 예시의 hobby__name은 hobby 필드가 Hobby 모델과 ManyToMany 필드로 연결되어 있어 Hobby의 name을 조건으로 하는 것이다.
from django.db.models.query_utils import Q
class UserView(APIView)
def get(self, request):
# 취미 중 산책이 있거나 나이가 19살보다 많고 김씨인 사람만 필터 사람만 필터
query = Q(hobby__name="산책") | Q(age__gt=19, user__name__startswith="김")
user_profile_list = UserProfileModel.objects.filter(query)
serializer 객체에 is_valid() 메소드를 사용하면 유효성 검사가 가능하다. is_valid()의 리턴값은 bool 타입으로 유효하면 True, 유효하지 않으면 False를 반환한다. serializer의 fields가 모두 다, 알맞은 타입으로 들어오면 유효하다 판단한다.
아래는 회원가입을 하는 코드이다. is_valid()가 True인 경우에만 save를 이용해서 데이터베이스에 저장한다.
class UserView(APIView):
def post(self, request):
# serializer의 data 인자에는 model로 지정 된 테이블의 field:value를 dictionary로 넘겨준다.
user_serializer = UserSerializer(data=request.data)
# serializer validator를 통과하지 않을 경우 .is_valid()가 False로 return된다.
if user_serializer.is_valid():
# validator를 통과했을 경우 데이터 저장
user_serializer.save()
return Response({"message": "정상"}, status=status.HTTP_200_OK)
# .errors에는 validator에 실패한 필드와 실패 사유가 담겨져 있다.
return Response(user_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializer 클래스에 extra_kwargs를 사용해서 필드들마다 옵션을 설정할 수 있다. wirte_only, read_only, error_message 등을 설정할 수 있다.
class UserSerializer(serializers.ModelSerializer):
# 외래 키 관계에 있는 필드의 required를 설정하고 싶을 경우 인자로 넘겨줘야 한다.
userprofile = UserProfileSerializer(required=False) # default : True
...
class Meta:
...
# 각 필드에 해당하는 다양한 옵션 지정
extra_kwargs = {
# write_only : 해당 필드를 쓰기 전용으로 만들어 준다.
# 쓰기 전용으로 설정 된 필드는 직렬화 된 데이터에서 보여지지 않는다.
'password': {'write_only': True}, # default : False
'email': {
# error_messages : 에러 메세지를 자유롭게 설정 할 수 있다.
'error_messages': {
# required : 값이 입력되지 않았을 때 보여지는 메세지
'required': '이메일을 입력해주세요.',
# invalid : 값의 포맷이 맞지 않을 때 보여지는 메세지
'invalid': '알맞은 형식의 이메일을 입력해주세요.'
},
# required : validator에서 해당 값의 필요 여부를 판단한다.
'required': False # default : True
},
}
serializer의 인자에 object를 넣어 직렬화 된 데이터를 가져올 수 있다.
user = request.user
return Response(UserSerializer(user).data, status=status.HTTP_200_OK)
object와 마찬가지로 queryset을 인자로 넣어 여러개의 직렬화 된 데이터를 가져올 수 있다.
hobbys = Hobby.objects.all()
return Response(HobbySerializer(hobbys, many=True).data, status=status.HTTP_200_OK)
partial을 True로 설정할 경우 required field에 대한 validation을 수행하지 않는다.
주로 일부 필드를 update 할 때 사용된다.
user_serializer = UserSerializer(data=request.data, partial=True)
raise_exception을 True로 설정할 경우 validation을 통과하지 못했을 때 exception을 발생시킨다.
user_serializer = UserSerializer(data=request.data, raise_exception=True)
create는 위의 validate 예시와 같다. serializer 객체는 유효성 검사를 통과한 경우, 즉 is_valid()의 결과가 True라면 save() 메소드로 오브젝트를 생성할 수 있다.
class UserView(APIView):
def post(self, request):
# serializer의 data 인자에는 model로 지정 된 테이블의 field:value를 dictionary로 넘겨준다.
user_serializer = UserSerializer(data=request.data)
# serializer validator를 통과하지 않을 경우 .is_valid()가 False로 return된다.
if user_serializer.is_valid():
# validator를 통과했을 경우 데이터 저장
user_serializer.save() # 여기가 create 하는 부분!
return Response({"message": "정상"}, status=status.HTTP_200_OK)
# .errors에는 validator에 실패한 필드와 실패 사유가 담겨져 있다.
return Response(user_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
기본적인 사용 방법은 validate, create 하는 것과 다르지 않다. 단 update는 수정을 해야하므로 수정할 객체에 대한 정보를 url로부터 전달받아서 serializer 객체를 생성할 때 첫번째 인자로 넣어주고 data에 수정할 데이터들을 딕셔너리 형태로 넣어준다.
아래 수정 예시는 로그인한 사용자 정보를 수정하는 것이므로 url에서 정보를 받지 않고 request.user를 serializer에 전달하면 돼서 따로 수정할 객체에 대한 정보를 받지는 않았다.
class UserView(APIView):
def put(self, request):
user = request.user
if user.is_anonymous:
return Response({"error": "로그인 후 이용해주세요", status=status.HTTP_400_BAD_REQUEST}
# 기본적인 사용 방법은 validator, creater와 다르지 않다.
# update를 해줄 경우 obj, data(수정할 dict)를 입력한다.
# partial=True로 설정해 주면 일부 필드만 입력해도 에러가 발생하지 않는다.
user_serializer = UserSerializer(user, data=request.data, partial=True)
if user_serializer.is_valid():
# validator를 통과했을 경우 데이터 저장
user_serializer.save()
return Response({"message": "정상"}, status=status.HTTP_200_OK)
return Response(user_serializer.errors, status=status.HTTP_400_BAD_REQUEST)
url로부터 인자를 받아 update 하는 예시는 아래와 같다.
from django.urls import path
from . import views
urlpatterns = [
path('product/', views.ProductView.as_view()),
# 여기가 put 메소드를 실행할 url
# product/ url보다 위에 쓰면 product/가 실행이 안 될 수도 있다.
# 반드시 위에 쓰고 싶다면 반드시 int 형인 것을 명시할 것.
# path('<int:obj_id>/', views.ProductView.as_view()), # product/보다 위에 써도 됨.
path('<obj_id>/', views.ProductView.as_view()),
]
class ProductView(APIView):
# obj_id 매개변수로 넣어주기
def put(self, request, obj_id):
product = Product.objects.get(id=obj_id)
product_serializer = ProductSerializer(product, data=request.data, partial=True)
if product_serializer.is_valid():
# validator를 통과했을 경우 데이터 저장
product_serializer.save()
return Response({"message": "정상"}, status=status.HTTP_200_OK)