정참조
와 역참조
가 있다. 역참조
를 사용해 게시글과 게시글에 달린 댓글의 내용을 불러오는 문항이 있었는데, 제대로 해결하지 못했다. _set
이 붙는 것을 알게 되었다. 이번 문항은 이것을 사용해서 진행해보도록 하겠다. user serializer에 추가로 로그인한 사용자의 게시글 및 댓글 리턴 기능 구현
UserSerializer
에 보낼 게시글 및 댓글에 대한 serializer를 만들어보도록 하겠다. blog/serializers.py
from rest_framework import serializers
from .models import Article as ArticleModel
from .models import Comment as CommentModel
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = CommentModel
fields = ["user", "article", "comment"]
class ArticleSerializer(serializers.ModelSerializer):
comments = CommentSerializer(many=True, source='comment_set')
class Meta:
model = ArticleModel
fields = ["title", "content", "comments"]
위의 코드를 포스트맨에서 실험해보면 아래와 같은 결과가 나온다. 그러나 결과는 별로 이뻐보지이 않는다. 추후에 튜닝을 진행하도록 하겠다.
1번
: 현재 로그인되어 있는 사용자인 admi
가 작성한 게시글의 정보와 이에 해당하는 댓글들이 작성되어 있음2번
: 현재 로그인되어 있는 사용자인 admi
가 작성한 댓글해당 부분은 원래 두 번째 코드와 같이 쓰여야 한다. 하지만 포스트맨에 찍히는 이름을 다르게 적용하고 싶어 첫 번째 코드와 같이 쓴 것이다!
comments = CommentSerializer(many=True, source='comment_set')
comment_set = CommentSerializer(many=True)
위의 코드에서 알 수 있듯이, ForeignKey
나 ManyToManyFeild
와 같이 데이터가 QuerySet
으로 넘어가는 경우에는 반드시 many=True
를 붙여줘야 한다.
하지만 데이터가 object
로 즉 단 하나만 넘어가는 OneToOneField
의 경우에는 쓰지 않는다.
user의 아이디인 username
이 보이도록 수정해 좀 더 이쁘게 만들어보도록 하겠다. 또한 게시글의 카테고리도 추가해보도록 하겠다.
comment
를 단 사용자의 아이디를 보여주기 위해 dir(obj)
를 찍어보았다.user
를 역참조로 가져올 수 있고, 모델을 살펴보면 우리는 User
모델의 username
을 사용할 수 있다는 것을 직감적으로 알아채야 한다. class User(AbstractBaseUser):
# "사용자 계정"은 admin 페이지에서 나오는 메뉴의 이름 / unique=True를 설정해 단 하나의 값만 입력할 수 있도록 함
username = models.CharField("사용자 계정", max_length=50, unique=True)
password = models.CharField("비밀번호", max_length=128)
email = models.EmailField("이메일", max_length=100)
name = models.CharField("이름", max_length=20)
# auto_now_add : 최초 생성 시의 시간을 자동으로 입력해줌.(그 후 업데이트에 대한 시간 기록은 x) 주로 가입일, 최초 생성일 등에 사용함
join_data = models.DateTimeField("가입일자", auto_now_add=True)
related_name
을 설정했다면, source='comment_set'
은 쓸 필요가 없다. 하지만 다음과 같이 쓰게 되면 역참조를 통해서 불러왔다는 것을 직관적으로 알 수 있는 것 같다. from rest_framework import serializers
from .models import Article as ArticleModel
from .models import Comment as CommentModel
from .models import Category as CatogoryModel
class CommentSerializer(serializers.ModelSerializer):
username = serializers.SerializerMethodField()
def get_username(self, obj):
return obj.user.username
class Meta:
model = CommentModel
fields = ["username", "comment"]
class ArticleSerializer(serializers.ModelSerializer):
category = serializers.SerializerMethodField()
comments = CommentSerializer(many=True, source='comment_set')
# 카테고리를 리스트로 받아오기 위해 다음과 같이 작성
def get_category(self, obj):
return [category.name for category in obj.category.all()]
class Meta:
model = ArticleModel
fields = ["title", "content", "comments", "category"]
포스트맨에서 확인해보자.
만약 각 serializer에서 서로를 참조하게 되면 circular import error(순환 참조 에러)
가 일어나게 된다. 어떤 의미냐면 계속 서로를 참조하게 되는 것이다(끝없이). 그러므로 참조를 잘 설계해야 한다.
def post(self, request):
user = request.user
title = request.data.get('title', '')
content = request.data.get('content', '')
categorys = request.data.get('category', [])
if len(title) <= 5:
return Response({"error": "제목은 5자보다 많아야 합니다."})
if len(content) <= 20:
return Response({"error": "게시글은 20자보다 많아야 합니다."})
if not categorys:
return Response({"error": "카테고리가 지정되지 않았습니다."})
article = ArticleModel(author=user, title=title, content=content)
article.save()
article.category.add(*categorys)
return Response({"msg": "게시글 작성 성공!!"})
article.category.add(*categorys)
를 사용해 여러 개의 카테고리를 보여주려 리스트 형식으로 받아온 것을 언패킹해 값을 더해줄 수 있다. HTTP_100_CONTINUE = 100
HTTP_101_SWITCHING_PROTOCOLS = 101
HTTP_200_OK = 200
HTTP_201_CREATED = 201
HTTP_202_ACCEPTED = 202
HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203
HTTP_204_NO_CONTENT = 204
HTTP_205_RESET_CONTENT = 205
HTTP_206_PARTIAL_CONTENT = 206
HTTP_207_MULTI_STATUS = 207
HTTP_208_ALREADY_REPORTED = 208
HTTP_226_IM_USED = 226
HTTP_300_MULTIPLE_CHOICES = 300
HTTP_301_MOVED_PERMANENTLY = 301
HTTP_302_FOUND = 302
HTTP_303_SEE_OTHER = 303
HTTP_304_NOT_MODIFIED = 304
HTTP_305_USE_PROXY = 305
HTTP_306_RESERVED = 306
HTTP_307_TEMPORARY_REDIRECT = 307
HTTP_308_PERMANENT_REDIRECT = 308
HTTP_400_BAD_REQUEST = 400
HTTP_401_UNAUTHORIZED = 401
HTTP_402_PAYMENT_REQUIRED = 402
HTTP_403_FORBIDDEN = 403
HTTP_404_NOT_FOUND = 404
HTTP_405_METHOD_NOT_ALLOWED = 405
HTTP_406_NOT_ACCEPTABLE = 406
HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407
HTTP_408_REQUEST_TIMEOUT = 408
HTTP_409_CONFLICT = 409
HTTP_410_GONE = 410
HTTP_411_LENGTH_REQUIRED = 411
HTTP_412_PRECONDITION_FAILED = 412
HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413
HTTP_414_REQUEST_URI_TOO_LONG = 414
HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416
HTTP_417_EXPECTATION_FAILED = 417
HTTP_418_IM_A_TEAPOT = 418
HTTP_422_UNPROCESSABLE_ENTITY = 422
HTTP_423_LOCKED = 423
HTTP_424_FAILED_DEPENDENCY = 424
HTTP_426_UPGRADE_REQUIRED = 426
HTTP_428_PRECONDITION_REQUIRED = 428
HTTP_429_TOO_MANY_REQUESTS = 429
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451
HTTP_500_INTERNAL_SERVER_ERROR = 500
HTTP_501_NOT_IMPLEMENTED = 501
HTTP_502_BAD_GATEWAY = 502
HTTP_503_SERVICE_UNAVAILABLE = 503
HTTP_504_GATEWAY_TIMEOUT = 504
HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505
HTTP_506_VARIANT_ALSO_NEGOTIATES = 506
HTTP_507_INSUFFICIENT_STORAGE = 507
HTTP_508_LOOP_DETECTED = 508
HTTP_509_BANDWIDTH_LIMIT_EXCEEDED = 509
HTTP_510_NOT_EXTENDED = 510
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511
⌘ + 클릭
해 알아볼 수 있다. from rest_framework.response import Response
from rest_framework import status
def post(self, request):
user = request.user
title = request.data.get('title', '')
content = request.data.get('content', '')
categorys = request.data.get('category', [])
if len(title) <= 5:
return Response({"error": "제목은 5자보다 많아야 합니다."})
if len(content) <= 20:
return Response({"error": "게시글은 20자보다 많아야 합니다."})
if not categorys:
return Response({"error": "카테고리가 지정되지 않았습니다."})
article = ArticleModel(author=user, title=title, content=content)
article.save()
article.category.add(*categorys)
return Response({"msg": "게시글 작성 성공!!"}, status=status.HTTP_200_OK)
from django.contrib import admin
from .models import User as UserModel, UserProfile as UserProfileModel, Hobby as HobbyModel
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
class UserAdmin(BaseUserAdmin):
list_display = ('id', 'username', 'name', 'email')
list_display_links = ('username', )
list_filter = ('username', )
search_fields = ('username', 'email', )
fieldsets = (
("info", {"fields": ("username", "password", "email", "name", "join_data", )}),
("Permissions", {"fields": ("is_admin", "is_active", )}),)
filter_horizontal = []
def get_readonly_fields(self, request, obj=None):
if obj:
return ('username', 'join_data',)
else:
return ('join_data', )
# Register your models here.
admin.site.register(UserModel, UserAdmin)
admin.site.register(UserProfileModel)
admin.site.register(HobbyModel)
이제 서버를 돌리고 어드민 페이지로 들어가보았더니, 아래와 같이 변화가 생겼다.
admi
를 클릭해 들어가보도록 하자.
그리고 빨간 박스를 눌러보자. 빨간 박스가 쳐져있는 부분의 말은 비밀번호를 바꾸려면 여기를 눌러라다. 진짜 사이트와 같이 비밀번호를 바꿀 수 있는 것을 볼 수 있다.
잘못 입력된 비밀번호는 아래와 같이 나온다.
settings.py
에 아래 코드를 붙여넣어주면 된다. # https://docs.djangoproject.com/en/1.11/topics/logging/
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
}
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'level': 'DEBUG',
},
}
}
from rest_framework.permissions import BasePermission
from datetime import timedelta
from django.utils import timezone
from rest_framework.exceptions import APIException
from rest_framework import status
class MyAuthenticateOver3(BasePermission):
message = "가입 후 3일이 지나지 않아 글 작성이 불가능합니다."
def has_permission(self, request, view):
user = request.user
if not user or not user.is_authenticated:
return False
# DateField : 2022-06-18
# DataTimeField : 2022-06-18 10:50:55
# datetime.now().date() 를 통해서 시간까지는 안나오게 설정함
print(f'user join date : {user.join_data}')
print(f'now date : {timezone.now()}')
print(f'a week ago date : {timezone.now() - timedelta(minutes=3)}')
return bool(user.join_data < (timezone.now() - timedelta(minutes=3)))
class GenericAPIException(APIException):
def __init__(self, status_code, detail=None, code=None):
self.status_code=status_code
super().__init__(detail=detail, code=code)
class IsAdminOrIsAuthenticatedReadOnly(BasePermission):
"""
admin 사용자는 모두 가능, 로그인 사용자는 조회만 가능
"""
SAFE_METHODS = ('GET', )
message = '접근 권한이 없습니다.'
def has_permission(self, request, view):
user = request.user
if not user.is_authenticated:
response ={
"detail": "서비스를 이용하기 위해 로그인 해주세요.",
}
raise GenericAPIException(status_code=status.HTTP_401_UNAUTHORIZED, detail=response)
# 유저가 인증되어있고 어드민이라면 전부다 할 수 있다.
if user.is_authenticated and user.is_admin:
return True
# 유저가 인증되어있고, 메서드가 세이프 메서드 안에 있다면 트루(어드민 아닌 사람들)
if user.is_authenticated and request.method in self.SAFE_METHODS:
return True
return False
from django_rest_framework.permissions import MyAuthenticateOver3, IsAdminOrIsAuthenticatedReadOnly
# 사용자 정보
class UserView(APIView):
# permission_classes = [MyAuthenticateOver3]
permission_classes = [IsAdminOrIsAuthenticatedReadOnly]
# 사용자 정보 조회
def get(self, request):
return Response(UserSerializer(request.user).data)
# 회원가입
def post(self, request):
user = request.user
print(user)
print(user.is_admin)
return Response({"msg": "post method!!"})
먼저 포스트맨에 가 확인해보면 성공했다.
이제 터미널창을 통해 결과를 보도록 하겠다.
admi
는 admin 권한을 가지고 있는 것을 알 수 있다.로그아웃을 진행한 후 다시 사용자 조회를 해보았다. 로그인이 필요하다는 메세지를 주는 것을 알 수 있다.
이제 admi 말고 다른 유저로 로그인해 사용자 조회를 진행하도록 하겠다.
사용자 조회에 실패한 것을 알 수 있다. 하지만 우리는 여기서 에러 메세지에 집중해야 한다. 현 사용자는 user5로 어드민 권한이 없다.
여기서 우리가 알 수 있는 점은 사용자의 권한에 따라 에러 메세지를 다르게 설정
할 수 있는 것이다.
1번
: 로그인에 성공해 인증은 되어 있지만 admin 권한이 없는 user2번
: 로그인을 하지 않아 인증도 되어 있지 않은 비인가된 사용자현재 우리는 POST
에 대해서 실험을 해본 것이다. 그렇다면 SAFE_METHOD
에 들어있는 GET
메서드로 실험을 한다면 어떻게 될 것인지 알아보도록 하겠다.
이를 통해 우리가 부여한 권한에 따라 사용자들이 이용할 수 있는 서비스를 제한시킬 수 있는 permission을 적용할 수 있다는 것을 알 수 있었다.
user/admin.py
class UserAdmin(BaseUserAdmin):
list_display = ('id', 'username', 'name', 'email')
list_display_links = ('username', )
list_filter = ('username', )
search_fields = ('username', 'email', )
fieldsets = (
("info", {"fields": ("username", "password", "email", "name", "join_data", )}),
("Permissions", {"fields": ("is_admin", "is_active", )}),)
filter_horizontal = []
def get_readonly_fields(self, request, obj=None):
if obj:
return ('username', 'join_data',)
else:
return ('join_data', )
def get_readonly_fields(self, request, obj=None):
if obj:
return ('username', 'join_data',)
else:
return ('join_data', )
auto_now_add=True
로 인해 자동으로 생성되며 이것은 readonly_fields
의 필수값이다. 하지만 사용자의 아이디는 회원가입을 하면서 입력해야 된다. 따라서 username은 아래의 경우 빠져있다.StackedInline
은 역참조
관계에서만 활용할 수 있다. User와 UserProfile은 역참조를 할 수 있는 OneToOne 관계이다. from django.contrib import admin
from .models import User as UserModel, UserProfile as UserProfileModel, Hobby as HobbyModel
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
cfrom django.contrib import admin
from .models import User as UserModel, UserProfile as UserProfileModel, Hobby as HobbyModel
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
# Stackedinline
class UserProfileInline(admin.StackedInline):
model = UserProfileModel
# 헷갈릴 수 있어 일단 사용 안함
# def formfield_for_manytomany(self, db_field, request, **kwargs):
# if db_field.name == 'hobby':
# kwargs['queryset'] = HobbyModel.objects.filter(id__lte=7)
# return super().formfield_for_foreignkey(db_field, request, **kwargs)
class UserAdmin(BaseUserAdmin):
list_display = ('id', 'username', 'name', 'email')
list_display_links = ('username', )
list_filter = ('username', )
search_fields = ('username', 'email', )
fieldsets = (
("info", {"fields": ("username", "password", "email", "name", "join_data", )}),
("Permissions", {"fields": ("is_admin", "is_active", )}),)
filter_horizontal = []
def get_readonly_fields(self, request, obj=None):
if obj:
return ('username', 'join_data',)
else:
return ('join_data', )
# 여기에 인라인을 지정해준다.
inlines = (
UserProfileInline,
)
StackedInline
과 완전히 똑같지만 다른 점은 UserProfile의 내용이 세로로 나오냐 가로로 나오냐이다. TabulrInline
은 가로로 나오는 것을 볼 수 있다. # TabularInline
class UserProfileInline(admin.TabularInline):
model = UserProfileModel
# 헷갈릴 수 있어 일단 사용 안함
# def formfield_for_manytomany(self, db_field, request, **kwargs):
# if db_field.name == 'hobby':
# kwargs['queryset'] = HobbyModel.objects.filter(id__lte=7)
# return super().formfield_for_foreignkey(db_field, request, **kwargs)
class UserAdmin(BaseUserAdmin):
list_display = ('id', 'username', 'name', 'email')
list_display_links = ('username', )
list_filter = ('username', )
search_fields = ('username', 'email', )
fieldsets = (
("info", {"fields": ("username", "password", "email", "name", "join_data", )}),
("Permissions", {"fields": ("is_admin", "is_active", )}),)
filter_horizontal = []
def get_readonly_fields(self, request, obj=None):
if obj:
return ('username', 'join_data',)
else:
return ('join_data', )
# 여기에 인라인을 지정해준다.
inlines = (
UserProfileInline,
)
class UserProfileInline(admin.StackedInline):
model = UserProfileModel
filter_horizontal = ["hobby"]
class UserAdmin(BaseUserAdmin):
list_display = ('id', 'username', 'name', 'email')
list_display_links = ('username', )
list_filter = ('username', )
search_fields = ('username', 'email', )
fieldsets = (
("info", {"fields": ("username", "password", "email", "name", "join_data", )}),
("Permissions", {"fields": ("is_admin", "is_active", )}),)
filter_horizontal = []
def get_readonly_fields(self, request, obj=None):
if obj:
return ('username', 'join_data',)
else:
return ('join_data', )
# 여기에 인라인을 지정해준다.
inlines = (
UserProfileInline,
)
def has_add_permission(self, request, obj=None): # 추가 권한
print(request.user)
return False
def has_delete_permission(self, request, obj=None): # 삭제 권한
print(request.user)
return False
def has_change_permission(self, request, obj=None): # 수정 권한
print(request.user)
return False
로그인해 있는 사용자를 찍어보았다. 권한을 모두 False로 수정해 아예 모든 사용자가 추가, 삭제 및 수정을 할 수 있는 것을 볼 수 있다.
현재는 모두 False로 적용되어 있어 모든 페이지에서 할 수 있던 추가, 삭제, 수정이 모두 막힌 것을 볼 수 있다.
get
#### 상단 생략 ####
class ArticleView(APIView):
permission_classes = [MyAuthenticateOver3]
def get(self, request):
user = request.user
articles = ArticleModel.objects.get(author=user)
print(articles)
return Response({})
#### 하단 생략 ####
filter
#### 상단 생략 ####
class ArticleView(APIView):
permission_classes = [MyAuthenticateOver3]
def get(self, request):
user = request.user
articles = ArticleModel.objects.filter(author=user)
print(articles)
return Response({})
#### 하단 생략 ####
filter
의 경우, 여러 개의 object가 포함되어 있는 QuerySet으로 결과값을 반환해준다.exclude
#### 상단 생략 ####
class ArticleView(APIView):
permission_classes = [MyAuthenticateOver3]
def get(self, request):
user = request.user
articles = ArticleModel.objects.exclude(author=user)
print(articles)
return Response({})
#### 하단 생략 ####
같은 hobby를 가진 사용자
를 출력할 때 현재 로그인되어 있는 사용자의 username로 같이 나오게 된다. 이는 불필요한 부분이라 생각해 제외해보도록 하겠다. user/views.py
#### 상단 생략 ####
class UserView(APIView):
# permission_classes = [MyAuthenticateOver3]
permission_classes = [IsAdminOrIsAuthenticatedReadOnly]
# 사용자 정보 조회
def get(self, request):
# 다수의 사용자의 값을 불러올 때 사용!
# all_user = UserModel.objects.all()
# return Response(UserSerializer(all_user, many=True).data)
user_serializer = UserSerializer(request.user, context={"request": request}).data
return Response(user_serializer)
#### 하단 생략 ####
class UserSerializer(serializers.ModelSerializer):
user_detail = UserProfileSerializer(source="userprofile") # object (OneToOne 관계)
articles = ArticleSerializer(many=True, source="article_set")
comments = CommentSerializer(many=True, source="comment_set")
login_name = serializers.SerializerMethodField()
def get_login_name(self, obj):
return self.context["request"].user.name
class Meta:
# 내가 serializer에서 어떤 모델을 쓰겠다는 것을 선언하는 것!(중요)
model = UserModel
fields = ["username", "email", "name", "join_data", "user_detail", "articles", "comments", "login_name"]
HobbySerializer에서 진행
하도록 한다. 왜냐하면 HobbySerialzer에서도 해당 context 값을 받아서 사용할 수 있기 때문에 굳이 다른 곳에서 받아다 두 번 사용할 필요가 없기 때문이다. user/serializers.py
class HobbySerializer(serializers.ModelSerializer):
same_hobby_user = serializers.SerializerMethodField()
def get_same_hobby_user(self, obj):
user_list = []
user = self.context["request"].user
for user_profile in obj.userprofile_set.exclude(user=user):
user_list.append(user_profile.user.username)
return user_list
# 위의 for문을 리스트 컴프리헨션을 통해 줄일 수 있음!
# return [user_profile.user.username for user_profile in obj.userprofile_set.all()]
class Meta:
model = HobbyModel
fields = ["name", "same_hobby_user"]
#### 상단 생략 ####
class ArticleView(APIView):
permission_classes = [MyAuthenticateOver3]
def get(self, request):
user = request.user
articles = ArticleModel.objects.filter(author__name__contains=user)
print(articles)
return Response({})
#### 하단 생략 ####
#### 상단 생략 ####
class ArticleView(APIView):
permission_classes = [MyAuthenticateOver3]
def get(self, request):
user = request.user
articles = ArticleModel.objects.filter(author__name__startswith='u')
print(articles)
return Response({})
#### 하단 생략 ####
#### 상단 생략 ####
class ArticleView(APIView):
permission_classes = [MyAuthenticateOver3]
def get(self, request):
user = request.user
articles = ArticleModel.objects.filter(author__name__endswith='1')
print(articles)
return Response({})
#### 하단 생략 ####
크거나 / 작거나 / 크거나같거나 / 작거나같은
object를 찾는 것이다.유효기간
을 측정할 때 많이 쓰인다. gt
class UserView(APIView):
# permission_classes = [MyAuthenticateOver3]
permission_classes = [IsAdminOrIsAuthenticatedReadOnly]
# 사용자 정보 조회
def get(self, request):
users = UserProfileModel.objects.filter(age__gt=20)
print(users)
return Response({})
lt
class UserView(APIView):
# permission_classes = [MyAuthenticateOver3]
permission_classes = [IsAdminOrIsAuthenticatedReadOnly]
# 사용자 정보 조회
def get(self, request):
users = UserProfileModel.objects.filter(age__lt=20)
print(users)
return Response({})
gte
class UserView(APIView):
# permission_classes = [MyAuthenticateOver3]
permission_classes = [IsAdminOrIsAuthenticatedReadOnly]
# 사용자 정보 조회
def get(self, request):
users = UserProfileModel.objects.filter(age__gte=20)
print(users)
return Response({})
lte
class UserView(APIView):
# permission_classes = [MyAuthenticateOver3]
permission_classes = [IsAdminOrIsAuthenticatedReadOnly]
# 사용자 정보 조회
def get(self, request):
users = UserProfileModel.objects.filter(age__lte=20)
print(users)
return Response({})
class UserView(APIView):
# permission_classes = [MyAuthenticateOver3]
permission_classes = [IsAdminOrIsAuthenticatedReadOnly]
# 사용자 정보 조회
def get(self, request):
# 다수의 사용자의 값을 불러올 때 사용!
# all_user = UserModel.objects.all()
# return Response(UserSerializer(all_user, many=True).data)
# return Response(UserSerializer(request.user).data)
users = UserProfileModel.objects.filter(hobby__in=['축구', '농구'])
print(users)
return Response({})
def get(self, request):
username = request.data.get('username', '')
password = request.data.get('username', '')
email = request.data.get('username', '')
name = request.data.get('username', '')
user = UserModel.objects.create(
username=username,
password=password, # 이건 이렇게 하면 안된다. set_password 사용해야 함! 예시임!
email=email,
name=name
)
def get(self, request):
UserModel.objects.create(**request.data)
pop
을 사용해 password 값만 따로 빼서 처리해보자. def get(self, request):
password = request.data.pop("password")
user = UserModel(**request.data)
user.set_password(password)
user.save()
가입일 순
으로 게시글을 정렬해보도록 하겠다. class ArticleView(APIView):
permission_classes = [MyAuthenticateOver3]
def get(self, request):
user = request.user
articles = ArticleModel.objects.all().order_by("author__join_data")
print(articles)
return Response({})
가입일의 역순
으로 정렬을 해보자. class ArticleView(APIView):
permission_classes = [MyAuthenticateOver3]
def get(self, request):
user = request.user
articles = ArticleModel.objects.all().order_by("-author__join_data")
print(articles)
return Response({})
랜덤 셔플
을 해보도록 하겠다. class ArticleView(APIView):
permission_classes = [MyAuthenticateOver3]
def get(self, request):
user = request.user
articles = ArticleModel.objects.all().order_by("?")
print(articles)
return Response({})
class ArticleView(APIView):
permission_classes = [MyAuthenticateOver3]
def get(self, request):
user = request.user
articles = ArticleModel.objects.all().order_by("?").first()
print(articles)
return Response({})