- 세션과 쿠키를 이용한 Django 인증 시스템 2023.12.06
- Django의 사용자 인증 및 관리를 위한 유틸리티 함수 2023.11.26
- DRF) serializer에서 validation 메소드 만들기 2023.10.01
- Python의 변수와 참조 2023.09.21
- deque 모듈 2023.08.30
- Django 소유자 여부 확인(DRF) 2023.08.28
- 세션과 쿠키의 작동 방식:
- Django에서 로그인 시, 사용자의 세션 정보는 서버의 데이터베이스에 저장됩니다. 이 세션에는 랜덤으로 생성된 세션 ID가 포함되어 있습니다.
- 서버는 이 세션 ID를 쿠키에 담아 브라우저로 보냅니다. 브라우저는 이 쿠키를 저장하고, 이후 동일한 도메인으로 요청을 보낼 때마다 이 쿠키를 함께 전송합니다.
- 도메인 기반 쿠키:
- 쿠키는 도메인을 기준으로 작동합니다. 특정 도메인에서 생성된 쿠키는 해당 도메인에 대한 요청 시에만 브라우저에 의해 전송됩니다. 이는 보안과 관련된 중요한 특징입니다.
- CORS 설정:
- 프론트엔드(예: React)와 백엔드(Django)가 다른 도메인 또는 포트에서 실행될 때, 백엔드에 대한 AJAX 요청을 위해
CORS_ALLOWED_ORIGINS설정이 필요합니다. 이 설정은 백엔드가 어떤 오리진에서 오는 요청을 허용할지 지정합니다.
- 프론트엔드(예: React)와 백엔드(Django)가 다른 도메인 또는 포트에서 실행될 때, 백엔드에 대한 AJAX 요청을 위해
- Axios와 쿠키 전송:
- JavaScript 또는 Axios를 사용하여 요청을 보낼 때,
withCredentials: true설정을 추가해야 합니다. 이 설정은 AJAX 요청에 쿠키를 포함시키기 위해 필요합니다.
- JavaScript 또는 Axios를 사용하여 요청을 보낼 때,
- 백엔드 설정:
- Django 백엔드에서
CORS_ALLOW_CREDENTIALS = True를 설정해야만, AJAX 요청에 포함된 쿠키를 받아들일 준비가 됩니다.
- Django 백엔드에서
Django와 React에서 세션과 쿠키를 사용한 인증을 구현하기 위한 기본적인 설정 예시를 제공하겠습니다.
Django 설정
django-cors-headers 설치 이후
settings.py에서 CORS 설정
# settings.p
INSTALLED_APPS = [
# ... 기타 설치된 앱들 ...
'corsheaders', # corsheaders 앱 추가
# ... 기타 설치된 앱들 ...
]
MIDDLEWARE = [
# ... 기타 미들웨어 ...
'corsheaders.middleware.CorsMiddleware', # CORS 미들웨어 추가, 꼭 아래의 미들웨어 보다는 먼저 작성
'django.middleware.common.CommonMiddleware',
# ... 기타 미들웨어 ...
]
# 모든 오리진을 허용하거나 특정 오리진만 허용
CORS_ALLOW_ALL_ORIGINS = True
# 또는
# CORS_ALLOWED_ORIGINS = [
# "http://localhost:3000", # React 앱의 URL
# ]
# AJAX 요청에 쿠키를 포함하기 위해
CORS_ALLOW_CREDENTIALS = True
React 설정 (Axios 사용 예시)
Axios 인스턴스 생성
// Axios 설정
import axios from 'axios';
const instance = axios.create({
baseURL: "http://127.0.0.1:8000/api/v1", // Django 서버 주소
withCredentials: true, // 쿠키를 포함시키기 위해
});
export default instance;
CSRF
Django에서 CSRF(Cross-Site Request Forgery) 토큰은 중요한 보안 기능 중 하나입니다. CSRF 토큰은 사용자의 세션을 보호하기 위해 사용되며, 사이트 간 요청 위조 공격을 방지하는 데 도움이 됩니다. Django의 CSRF 보호 기능을 사용하려면 다음과 같은 설정이 필요합니다.
Django CSRF 설정
settings.py에서 CSRF 설정
# settings.py
CSRF_TRUSTED_ORIGINS = ["http://127.0.0.1:3000"] # front 도메인 주소
템플릿에서 CSRF 토큰 사용
<form method="post">
{% csrf_token %}
<!-- 폼 필드 -->
</form>
AJAX 요청에 CSRF 토큰 포함
Django에서는 AJAX 요청에도 CSRF 토큰을 포함해야 합니다. 이를 위해 React 애플리케이션에서 요청을 보낼 때, CSRF 토큰을 요청 헤더에 포함해야 합니다.
React 설정 (Axios 사용 예시)
Axios 인스턴스에 CSRF 토큰 추가
// Axios 설정
import axios from 'axios';
const getCsrfToken = () => {
return document.cookie.split('; ').find(row => row.startsWith('csrftoken=')).split('=')[1];
};
const instance = axios.create({
baseURL: "http://127.0.0.1:8000/api/v1", // Django 서버 주소
withCredentials: true, // 쿠키를 포함시키기 위해
headers: {
'X-CSRFToken': getCsrfToken(), // CSRF 토큰 추가
}
});
export default instance;
위의 코드는 React 앱에서 Django 서버로 보내는 모든 요청에 CSRF 토큰을 포함시키는 방법을 보여줍니다. getCsrfToken 함수는 브라우저의 쿠키에서 CSRF 토큰을 추출하고, Axios 인스턴스는 이 토큰을 요청 헤더에 추가하여 서버에 전송합니다. 이 방법으로 Django 서버의 CSRF 보호 기능을 충족시킬 수 있습니다.
'Python > Django' 카테고리의 다른 글
| Django의 사용자 인증 및 관리를 위한 유틸리티 함수 (1) | 2023.11.26 |
|---|---|
| DRF) serializer에서 validation 메소드 만들기 (0) | 2023.10.01 |
| Django 소유자 여부 확인(DRF) (0) | 2023.08.28 |
| Serializer에서 method 사용하기 (0) | 2023.08.27 |
| Django에서의 Transactions (0) | 2023.08.26 |
Django는 사용자 인증 및 관리를 위해 여러 유틸리티 함수를 제공합니다. check_password, set_password, authenticate, login, logout 함수들을 예시로 들 수 있습니다.
1. check_password()
- 용도: 사용자의 비밀번호가 입력된 비밀번호와 일치하는지 확인합니다.
- 예시:
from django.contrib.auth.models import User user = User.objects.get(username='myusername') if user.check_password('mypassword'): print("비밀번호가 일치합니다.") else: print("비밀번호가 일치하지 않습니다.")
2. set_password()
- 용도: 사용자의 비밀번호를 새로 설정합니다.
- 예시:
user = User.objects.get(username='myusername') user.set_password('newpassword') user.save()
3. authenticate()
- 용도: 사용자 이름과 비밀번호가 유효한지 확인하고, 해당하는
User객체를 반환합니다. - 예시:
from django.contrib.auth import authenticate user = authenticate(request, username='myusername', password='mypassword') if user is not None: print("인증에 성공했습니다.") else: print("인증에 실패했습니다.")
4. login()
- 용도: 주어진
HttpRequest객체와User객체를 사용하여 세션을 시작합니다. - 예시:
from django.contrib.auth import login def my_view(request): # 사용자 인증이 이미 이루어진 상황 가정 user = authenticate(request, username='myusername', password='mypassword') if user is not None: login(request, user) # 로그인 후 처리
5. logout()
- 용도: 현재 세션을 종료합니다.
- 예시:
from django.contrib.auth import logout def my_view(request): logout(request) # 로그아웃 후 처리
'Python > Django' 카테고리의 다른 글
| 세션과 쿠키를 이용한 Django 인증 시스템 (0) | 2023.12.06 |
|---|---|
| DRF) serializer에서 validation 메소드 만들기 (0) | 2023.10.01 |
| Django 소유자 여부 확인(DRF) (0) | 2023.08.28 |
| Serializer에서 method 사용하기 (0) | 2023.08.27 |
| Django에서의 Transactions (0) | 2023.08.26 |
Django Rest Framework에서 serializer에서 각 필드에 대한 validation 로직을 추가할 수 있습니다. 검증을 위한 메서드 명은 validate_필드이름 라고 작성하고 검증할 로직을 구현하면 됩니다.
예
간단한 방 정보를 다루는 예시를 통해서 사용법을 설명하겠습니다.
모델
class Room(model.Model):
name = models.CharField(max_length=100)
price = models.PositiveIntegerField()
description = models.TextField()
시리얼라이저
class RoomSerializer(serializers.ModelSerializer):
class Meta:
model = Room
fields = ["name", "price", "description"]
def validate_name(self, value):
if len(value) < 3:
raise serializers.ValidationError("방 이름은 최소 3글자 이상이어야 합니다.")
return value
def validate_price(self, value):
if value < 0:
raise serializers.ValidationError("가격은 음수일 수 없습니다.")
return value
이 예시에서는 Room 모델을 정의하고, 이를 시리얼라이저로 변환하는 RoomSerializer를 만들었습니다. RoomSerializer는 Room 모델과 연결되어 있습니다.
RoomSerializer 내부에서 validate_name 메소드와 validate_price 메소드를 정의했습니다.
validate_name메소드는name필드의 값을 검증합니다. 만약 이름이 3글자 미만이면serializers.ValidationError을 발생시켜 에러를 일으킵니다.validate_price메소드는price필드의 값을 검증합니다. 만약 가격이 음수라면 마찬가지로 에러를 발생시킵니다.
이런 식으로 각 필드에 대한 검증 로직을 추가할 수 있습니다. 이제 이 시리얼라이저를 사용하면, 입력된 데이터가 검증되고 필요한 처리가 이루어집니다.
serializer = RoomSerializer(data=data)
if serializer.is_valid():
# 유효한 경우, 데이터를 저장하거나 다른 처리를 할 수 있습니다.
room = serializer.save()
else:
# 유효하지 않은 경우, 에러 메시지를 확인할 수 있습니다.
errors = serializer.errors
이렇게 하면 시리얼라이저를 통해 데이터를 검증하고 처리할 수 있습니다.
'Python > Django' 카테고리의 다른 글
| 세션과 쿠키를 이용한 Django 인증 시스템 (0) | 2023.12.06 |
|---|---|
| Django의 사용자 인증 및 관리를 위한 유틸리티 함수 (1) | 2023.11.26 |
| Django 소유자 여부 확인(DRF) (0) | 2023.08.28 |
| Serializer에서 method 사용하기 (0) | 2023.08.27 |
| Django에서의 Transactions (0) | 2023.08.26 |
변수는 일반적으로 데이터를 저장할 수 있는 메모리 공간을 의미합니다.
다만, 파이썬에서의 변수는 C, 자바 같은 컴파일 언어에서의 변수와는 차이가 있습니다.
자바의 변수
자바를 예로 들면 자바는 변수를 선언하면서 선언된 자료형 만큼의 메모리를 확보합니다. 더 정확하게 말하면 원시 타입(Primitive Type)에 해당하는 변수(int, double, boolean 등)를 선언하면 선언된 타입만큼의 크기의 영역을 Stack 메모리에 선언합니다. 그리고 객체와 메서드 같은 참조형 타입(Reference type)은 Heap 메모리에 실질적인 데이터가 저장되고 그 데이터의 주소값이 stack 메모리에 저장되는 형태입니다.
파이썬의 변수
하지만 파이썬의 변수는 다릅니다.
파이썬에서 변수는 타입에 의해 선언되는 게 아닌 객체와 연관되어 있습니다.
왜냐하면 변수에 선언되는 데이터는 모두 객체이기 때문입니다.
만약 a = 10 이라는 python 구문이 있다면, 파이썬은 우선 10을 나타내는 객체를 생성합니다. 이후 변수 a를 생성하고 변수 a와 객체 10을 연결합니다.
즉, a와 객체 10은 다른 위치에 저장되고 이 둘은 참조에 의해 연결됩니다.
변수명 참조 주소 메모리 주소 객체 값
| a | 0x1 | ➡️ | 0x1 | 10 |
사실 이 부분을 좀 더 자세히 설명하면 다음과 같습니다.
interning
파이썬에서는 정수와 같은 몇몇 흔한 값들에 대해 미리 객체를 생성하고 재사용합니다. 이를 "interning"이라고 합니다. 특히 작은 정수에 대해 이런 방식이 적용됩니다.
구체적으로, -5부터 256까지의 정수 객체는 파이썬이 시작될 때 미리 생성되어 있습니다. 따라서 a = 10 구문을 실행할 때, 새로운 10 객체를 생성하는 것이 아니라 이미 생성되어 있는 10 객체를 재사용합니다.
따라서, a = 10을 실행하면 다음과 같은 순서로 동작합니다:
- 10 객체가 이미 메모리에 있는지 확인합니다.
- 이미 있으면 그 객체의 참조를 변수 a에 연결합니다.
- 없으면 (예를 들어, 매우 큰 숫자나 5 이하의 숫자에서는) 새로운 객체를 생성하고 그 참조를 변수 a에 연결합니다.
즉, a = 10 구문을 실행하면 a는 이미 존재하는 10 객체를 참조하게 됩니다.
10과 10은 같은 객체
앞에서 말한 interning은 파이썬 구문으로 확인 가능합니다.
파이썬에서 == 는 값이 같은지 확인하고 'is'는 같은 객체를 참조하고 있는지를 확인해 줍니다.
a = 10
b = 10
a == b
#--> True
a is b
#--> True
10은 같은 객체임을 확인할 수 있습니다.
얕은 복사, 깊은 복사
list_1 = [1,2,3]
list_2 = list_1
list_1[0] = 10
list_2
#--> [10,2,3]
list_1과 list_2는 같은 [1,2,3] 객체를 참조합니다.
그리고 list는 가변 객체이기에 값이 변할 수 있습니다.
List_1[0] = 10 이 구문은 list_1이 다른 객체를 참조하도록 하는 구문이 아니라, list_1이 참조하는 객체 자체를 바꾼 것입니다.
그러기에 같은 객체를 참조하는 list_2의 출력값도 바뀌는 것입니다.
표로 표현하면 다음과 같습니다.
변수명 참조 주소 메모리 주소 객체 값
| list_1 | 0x1 | ➡️ | 0x1 | [1,2,3] |
| list_2 | 0x1 | ↗️ |
list_1[0] = 10 구문 실행
변수명 참조 주소 메모리 주소 객체 값
| list_1 | 0x1 | ➡️ | 0x1 | [10,2,3] |
| list_2 | 0x1 | ↗️ |
다른 예시를 더 살펴보면
동적 타입 언어(dynamic typing)
a = 10
a = "ten"
이 경우 a의 타입이 정수타입에서 문자열타입으로 변경된 것이 아니라 변수 a가 객체 10을 참조했다가, 객체 "ten"을 참조하는 것이다.
왜냐하면 파이썬에서의 변수는 동적으로 타입을 갖습니다. 파이썬의 변수는 참조하는 객체의 타입에 따라 동적으로 타입이 바뀔 수 있습니다.
변수는 사실상 특정 객체를 참조하고 있기에 가능한 것입니다. 자바나, c에서는 불가능합니다. 왜냐하면 변수의 타입에 따라 메모리의 크기를 정했기 때문입니다.
객체 메모리 구성
파이썬의 객체는 메모리 상에서 여러 부분으로 구성되어 있습니다. 헤더에는 타입 정보와 다른 메타데이터가 저장되며, 이후에 실제 데이터 값 등이 저장됩니다.
객체는 타입 정보를 헤더에 저장합니다. 그래서 파이썬에서는 변수에 타입을 지정할 필요가 없습니다. 왜냐하면 각 객체가 자신의 타입 정보를 직접 포함하고 있기 때문입니다. 이 특징 덕분에 앞에서 말한 파이썬이 동적 타이핑 언어가 가능한 이유입니다.
객체의 메모리 구성
| 타입 정보 (헤더) (Type Information) |
| 참조 카운트 (Reference Count) |
| 객체의 실제 데이터 값 (Object’s Actual Data Value) |
참조 카운트
참조 카운트는 파이썬의 메모리 관리 메커니즘 중 하나로, 특정 객체에 대한 참조의 수를 나타냅니다.
파이썬에서는 객체의 메모리를 효율적으로 관리하기 위해 참조 카운팅 방식을 사용합니다. 객체가 생성될 때 해당 객체의 참조 카운트는 1로 설정됩니다. 만약 다른 변수나 데이터 구조가 그 객체를 참조하게 되면 참조 카운트가 증가하며, 참조가 사라질 때마다 참조 카운트가 감소합니다.
참조 카운트가 0이 되면, 해당 객체는 더 이상 어떤 변수나 데이터 구조에도 참조되지 않는 것을 의미합니다. 이 시점에서 파이썬의 가비지 컬렉터(garbage collector)는 해당 객체의 메모리를 해제합니다.
예
a = [1, 2, 3] # 리스트 객체 생성, 참조 카운트 = 1
b = a # 리스트 객체에 대한 참조 추가, 참조 카운트 = 2
del a # 리스트 객체에 대한 참조 제거, 참조 카운트 = 1
del b # 리스트 객체에 대한 참조 제거, 참조 카운트 = 0 (이제 객체의 메모리가 해제될 수 있음)
'Python > Python' 카테고리의 다른 글
| deque 모듈 (0) | 2023.08.30 |
|---|---|
| Python - isinstance() (0) | 2023.08.12 |
| Python) 위치 인자, 키워드 인자 (0) | 2023.07.25 |
| @classmethod 와 @staticmethod (0) | 2023.07.20 |
| @property 데코레이터 (0) | 2023.07.01 |
deque 모듈
deque(데크, double-ended queue) 모듈은 양쪽 끝에서 삽입과 삭제가 가능한 자료구조입니다.
즉, 스택과 큐를 모드 지원하는 모듈로 Python의 collections 모듈에서 제공됩니다.
deque를 사용하기 위해서는 리스트와 비슷한 형식으로 데이터를 저장해야 합니다.
기본적인 사용법
Import 방법
from collections import deque
생성
d = deque([1, 2, 3, 4])
삽입 / 삭제
for i in range(5):
deque_list.append(i) # 오른쪽 끝에 삽입
print(deque_list)
# deque([0, 1, 2, 3, 4])
deque_list.pop() # 오른쪽 끝 요소 삭제
print(deque_list)
# deque([0, 1, 2, 3])
for i in range(5):
deque_list.appendleft(i) # 왼쪽 끝에 삽입
print(deque_list)
# deque([4, 3, 2, 1, 0])
deque_list.popleft() # 왼쪽 끝 요소 삭제
print(deque_list)
# deque([3, 2, 1, 0])
조회
d[0] # 첫 번째 요소 조회
d[-1] # 마지막 요소 조회
길이
len(d) # deque의 길이
장점 및 특징
deque 모듈은 리스트에 비해 일반적인 스택과 큐 연산에 더 효율적입니다.
또한 양쪽에서의 삽입, 삭제가 O(1) 시간 복잡도로도 가능합니다. 이로 얻는 장점은 아래 예제에서 확인하겠지만, 리스트에 비해 삽입, 삭제 연산이 매우 빠릅니다.
이러한 장점을 갖는 이유는 deque가 연결 리스트(Linked list)의 특성을 지원하기 때문입니다.
참고로 연결 리스트는 데이터를 저장할 때 요소의 값을 한 쪽으로 연결한 후, 요소의 다음 값의 주소값을 저장하여 데이터를 연결하는 기법입니다.

연결 리스트는 다음 요소의 주소값을 저장하므로 데이터를 원형으로 저장할 수 있고, 마지막 요소에 첫 번째 값의 주소를 저장한다면 해당 값을 찾아갈 수 있습니다. 이러한 특징 때문에 가능한 기능 중 하나가 rotate() 함수입니다. rotate(n)은 요소들을 n값 만큼 회전하는 함수입니다. n이 양수이면 오른쪽으로 회전하고, n이 음수이면 왼쪽으로 회전합니다.
from collections import deque
deque_list = deque([2, 4, 6, 8])
print(deque_list)
# deque([2, 4, 6, 8])
deque_list.rotate(1)
print(deque_list)
# deque([8, 2, 4, 6])
deque_list.rotate(-1)
print(deque_list)
# deque([2, 4, 6, 8])
rotate() 함수는 이처럼 각 요소와 인덱스 번호를 하나씩 옮깁니다.
deque모듈의 추가적인 함수들
reversed()
reversed()함수는 기존과 반대로 데이터를 저장할 수 있습니다.
deque_list = deque([1, 2, 3, 4])
reversed_deque = deque(reversed(deque_list))
print(reversed_deque)
# deque([4, 3, 2, 1])
clear()
deque리스트를 모두 지웁니다.
deque_list = deque()
for i in range(4):
deque_list.append(i)
print(deque_list)
# deque([0, 1, 2, 3])
deque_list.clear()
print(deque_list)
# deque([])
extend(), extendleft()
extend()와 extedleft()는 리스트가 통째로 추가됩니다.
deque_list = deque([1, 2, 3])
deque_list.extend([4, 5, 6])
print(deque_list)
# deque([1, 2, 3, 4, 5, 6])
deque_list.extendleft([0, -1, -2])
print(deque_list)
deque([-2, -1, 0, 1, 2, 3, 4, 5, 6])
maxlen
maxlen은 deque의 매개변수로 deque의 사이즈를 고정하는 인자값입니다.
data = [1, 2, 3, 4, 5, 6, 7]
deque_list = deque(data, maxlen=3)
print(deque_list)
# deque([5, 6, 7], maxlen=3)
deque와 list의 성능 테스트 비교
from collections import deque
import time
# insert 성능 비교
# deque
deque_list = deque()
start = time.time() # second단위
for i in range(100000):
deque_list.insert(1, "x")
end = time.time()
print("deque insert 시간: ", end - start)
# deque insert 시간: 0.012130975723266602
# list
list = list()
start = time.time()
for i in range(100000):
list.insert(1, "x")
end = time.time()
print("list insert 시간: ", end - start)
# list insert 시간: 4.031864166259766
# 추출 성능 비교
# deque start = time.time()
for i in range(100000):
deque_list.pop()
end = time.time()
print("deque pop 시간: ", end - start)
# deque pop 시간: 0.0071468353271484375
# list
start = time.time()
for i in range(100000):
list.pop()
end = time.time()
print("list pop 시간: ", end - start)
# list pop 시간: 0.007027149200439453
# 아래 부분을 테스트 하기 위해서는 pop 부분 코드를 주석 처리해야 합니다.
# deque
start = time.time()
for i in range(100000):
deque_list.popleft()
end = time.time()
print("deque pop 시간: ", end - start)
# deque pop 시간: 0.00786733627319336
# list
start = time.time()
for i in range(100000):
list.pop(0)
end = time.time()
print("list pop 시간: ", end - start)
# list pop 시간: 1.268723964691162
이를 통해 deque가 list에 비해 빠르다는 것을 알 수 있습니다.
'Python > Python' 카테고리의 다른 글
| Python의 변수와 참조 (0) | 2023.09.21 |
|---|---|
| Python - isinstance() (0) | 2023.08.12 |
| Python) 위치 인자, 키워드 인자 (0) | 2023.07.25 |
| @classmethod 와 @staticmethod (0) | 2023.07.20 |
| @property 데코레이터 (0) | 2023.07.01 |
Django 소유자 여부 확인(DRF)
Room 모델이 있고, 각 방은 owner가 있습니다.
방 정보를 조회하는 API를 만들려고 하는데, 로그인한 사용자가 각 방의 owner인지 여부를 확인하려고 합니다.
models.py
from django.db import models
from django.contrib.auth.models import User
class Room(models.Model):
name = models.CharField(max_length=100)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
serializers.py
from rest_framewok import serializers
from .models import Room
class RoomSerializer(serializers.ModelSerializer):
is_owner = serializers.SerializerMethodField()
def get_is_owner(self, room):
request = self.context["request"]
return room.owner == request.user
class Meta:
model = Room
fields = ["id", "name", "is_owner"]
views.py
from rest_framework import generics
from .models import Room
from .serializers import RoomSerializer
class RoomList(generics.ListAPIView):
queryset = Room.objects.all()
serializer_class = RoomSerializer
위 코드에서 Room 모델과 그에 맞는 시리얼라이저, APIView를 정의했습니다.
이때 is_owwner필드는 RoomSerializer클래스에 추가된 SerializerMethodField로, 방의 소유자 여부를 나타냅니다.get_is_owner 메서드에서는 self.context를 통해 현재 요청의 정보에 접근하고, 이를 활용하여 방의 소유자와 현재 사용자를 비교하여 is_owner 값을 결정하고 있습니다.
이렇게 context를 활용하여 요청 정보를 활용하는 것은 API의 동작을 더욱 유연하게 커스터마이징하고 필요한 정보를 포함시킬 수 있습니다.
'Python > Django' 카테고리의 다른 글
| Django의 사용자 인증 및 관리를 위한 유틸리티 함수 (1) | 2023.11.26 |
|---|---|
| DRF) serializer에서 validation 메소드 만들기 (0) | 2023.10.01 |
| Serializer에서 method 사용하기 (0) | 2023.08.27 |
| Django에서의 Transactions (0) | 2023.08.26 |
| values_list() (0) | 2023.08.09 |