Django ORM에서는 select_related()를 사용하여 INNER JOIN을 실행할 수 있음.
Django ORM에서는 prefetch_related()를 사용하여 LEFT JOIN을 실행할 수 있음.
참조 : 하나의 모델에서 다른 모델을 직접 가리키는 관계
역참조 : 모델의 반대방향에서 가져오는 것
구분 | 설명 | 예제 |
---|---|---|
참조(Reference) | ForeignKey로 연결된 객체를 직접 가져오는 것 | book.author |
역참조(Reverse Reference) | ForeignKey를 반대로 접근하는 것 | author.book_set.all() (or author.books.all() with related_name ) |
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
# author 를 같이 불러올수 잇음
book = Book.objects.create(title="Harry Potter", author=author)
author = Author.objects.get(name="J.K. Rowling")
# 역참조를 통해 해당 작가가 쓴 모든 책을 가져오기
books = author.book_set.all() # book_set 자동 생성
for book in books:
print(book.title)
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name="books") # 역참조 이름 지정
author = Author.objects.get(name="J.K. Rowling")
# 역참조 (이제 book_set 대신 books 사용 가능)
books = author.books.all()
for book in books:
print(book.title) # "Harry Potter"
# 기본 쿼리 (N+1 문제 발생)
books = Book.objects.all()
for book in books:
print(book.author.name) # 각 book마다 author 정보를 가져오면서 추가적인 쿼리 발생
# select_related() 사용 → INNER JOIN을 통해 한 번의 쿼리로 가져옴
books = Book.objects.select_related('author').all()
for book in books:
print(book.author.name)
# 기본 쿼리 (N+1 문제 발생)
courses = Course.objects.all()
for course in courses:
print(course.students.all()) # 각 course마다 students를 가져오기 위해 추가적인 쿼리 발생
# prefetch_related() 사용 → Django가 두 개의 쿼리를 실행한 후 ORM에서 매칭
courses = Course.objects.prefetch_related('students').all()
for course in courses:
print(course.students.all()) # Django가 메모리에서 데이터를 미리 로드하여 추가적인 쿼리 없이 가져옴
curl -sSL https://install.python-poetry.org | python3 -
mkdir my_django_project && cd my_django_project
poetry init # 프로젝트 초기화
poetry add django # Django 설치
python3 -m venv 가상환경명
source 가상환경명/bin/activate
django-admin startproject config .
.
(점) 을 붙이면 현재 디렉토리에 프로젝트가 생성됨
python manage.py startapp 앱명
INSTALLED_APPS
에 추가 (settings.py)INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp', # 추가된 앱
]
settings.py
에서 TEMPLATES
설정TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'], # templates 폴더 지정
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
프로젝트 루트에
templates/
폴더를 생성하고, 템플릿 파일을 해당 폴더에 저장
settings.py
에서 STATICFILES_DIRS
설정STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / 'static']
프로젝트 루트에
static/
폴더를 생성하고, 정적 파일을 해당 폴더에 저장
settings.py
에서 MEDIA_URL
및 MEDIA_ROOT
설정MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
프로젝트 루트에
media/
폴더를 생성하고, 업로드 파일을 저장
models.py
에서 모델 정의from django.db import models
class User(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField(unique=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
텍스트
파일
숫자
날짜, 시간
연결
기타
class Payment(mdoels.Mdoel):
payment_response = models.JSONField(default = {},[])
python manage.py makemigrations
python manage.py migrate
python manage.py showmigrations : 현재 migrations 항목 도출
post
[X] 0001_initial
[X] 0002_alter_postimage_post_comment_tag
sessions
[X] 0001_initial
python manage.py migrate post 0001 : 2번을 취소하고 싶을때 입력시 X가 취소되는것을 showmigrations를 통해 확인 가능
post
[X] 0001_initial
[ ] 0002_alter_postimage_post_comment_tag
{{ 변수 }}
: 변수를 출력{% if 조건 %} ... {% endif %}
: 조건문{% for item in 리스트 %} ... {% endfor %}
: 반복문{% block content %}
<h1>메인 콘텐츠</h1>
{% endblock %}
{% extends 'base.html' %}
{% block content %}
<p>이 페이지는 base.html을 상속받습니다.</p>
{% endblock %}
{% load static %}
{% load custom_tag %}
<!-- custom_tag에서 설정해 놓은 함수 가져오기 -->
{% add_like_class request.user post.likes.all %}
render
사용from django.shortcuts import render
def home(request):
return render(request, 'home.html')
redirect
사용from django.shortcuts import redirect
def go_to_home(request):
return redirect('home')
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
]
include()
함수를 사용하면 앱 내부의 URL을 프로젝트의 메인 URL과 연결할 수 있음.프로젝트의 urls.py
(최상위 URL 설정)
from django.urls import path, include
urlpatterns = [
path('myapp/', include('myapp.urls')), # myapp의 URL을 포함
]
앱 내부의 myapp/urls.py
(개별 앱의 URL 설정)
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'), # 'myapp/'로 들어오면 index 뷰 실행
path('detail/', views.detail, name='detail'), # 'myapp/detail/'로 들어오면 detail 뷰 실행
]
http://localhost:8000/myapp/
요청 → config/urls.py
에서 myapp.urls
로 연결myapp/urls.py
에서 빈 경로 ''
가 views.index
에 매칭되어 해당 뷰 실행http://localhost:8000/myapp/detail/
요청 시, views.detail
이 실행됨
include()
를 사용하면myapp/urls.py
내부에서 URL을 자유롭게 관리할 수 있으므로, 프로젝트 구조를 깔끔하게 유지할 수 있음.
path()
: 개별 URL 패턴을 정의할 때 사용include()
: 앱별로 URL을 분리하여 관리할 때 사용Django의 forms.Form
또는 forms.ModelForm
을 사용하여 웹 애플리케이션의 입력 양식을 쉽게 관리할 수 있습니다.
Django의 forms.Form
을 사용하여 입력 폼을 정의할 수 있습니다.
from django import forms
class SampleForm(forms.Form):
name = forms.CharField(label="이름", max_length=100)
age = forms.IntegerField(label="나이")
Django에서는 다양한 위젯을 제공하여 폼 필드의 입력 방식을 커스텀할 수 있습니다.
class CustomForm(forms.Form):
email = forms.EmailField(widget=forms.EmailInput(attrs={'class': 'form-control'}))
password = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': '비밀번호 입력'}))
UserCreationForm
(회원가입 폼)Django의 UserCreationForm
을 상속하여 사용자 생성 폼을 만들 수 있습니다.
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = User
fields = ("username", "email", "password1", "password2")
AuthenticationForm
(로그인 폼)Django 기본 제공 로그인 폼을 사용할 수 있습니다.
from django.contrib.auth.forms import AuthenticationForm
class CustomAuthenticationForm(AuthenticationForm):
pass
is_valid()
폼 데이터를 검증할 때 사용되며, 유효하지 않으면 form.errors
를 통해 오류를 확인할 수 있습니다.
form = SampleForm(request.POST)
if form.is_valid():
print(form.cleaned_data)
else:
print(form.errors)
Django의 ORM(Object Relational Mapping)은 데이터베이스 조작을 Python 코드로 수행할 수 있도록 해줍니다.
SQL 없이 Python 코드로 데이터베이스를 조작하는 기술을 의미합니다.
objects.all()
)from myapp.models import User
users = User.objects.all()
filter()
)users = User.objects.filter(age__gte=18) # 18세 이상 사용자 조회
get()
)user = User.objects.get(username="admin")
order_by()
)users = User.objects.order_by('-created_at') # 최신순 정렬
create()
)User.objects.create(username="new_user", email="user@example.com")
delete()
)user = User.objects.get(username="delete_me")
user.delete()
update()
)User.objects.filter(username="update_me").update(email="new@example.com")
get_object_or_404()
사용from django.shortcuts import get_object_or_404
user = get_object_or_404(User, username="admin")
Django에서 제공하는 인증 및 권한 관리 시스템을 이해하고 활용할 수 있습니다.
Django 기본 User
모델을 확장하거나 직접 정의할 수 있습니다.
Django의 User
모델은 django.contrib.auth.models
에서 제공됩니다.
from django.contrib.auth.models import User
# 모든 사용자 조회
users = User.objects.all()
Django에서는 AbstractUser
또는 AbstractBaseUser
를 확장하여 커스텀 사용자 모델을 만들 수 있습니다.
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
nickname = models.CharField(max_length=50, unique=True)
AbstractUser
: Django의 기본 User
모델을 확장하여 쉽게 사용자 모델을 커스텀할 수 있음AbstractBaseUser
: 사용자 모델을 처음부터 직접 정의할 때 사용사용자 권한을 확장할 때 사용되며, 그룹 및 개별 사용자 권한을 추가할 수 있습니다.
사용자 생성 로직을 커스텀할 때 BaseUserManager
를 활용할 수 있습니다.
from django.contrib.auth.models import BaseUserManager
class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError("The Email field must be set")
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
authenticate()
(사용자 인증)사용자가 입력한 아이디와 비밀번호가 올바른지 확인하는 함수
from django.contrib.auth import authenticate
user = authenticate(username="admin", password="password")
if user is not None:
print("인증 성공")
else:
print("인증 실패")
login()
(사용자 로그인)사용자를 로그인 상태로 만듭니다.
from django.contrib.auth import login
def user_login(request):
user = authenticate(username="admin", password="password")
if user is not None:
login(request, user)
return HttpResponse("로그인 성공")
return HttpResponse("로그인 실패")
logout()
(사용자 로그아웃)현재 로그인된 사용자를 로그아웃 처리합니다.
from django.contrib.auth import logout
def user_logout(request):
logout(request)
return HttpResponse("로그아웃 성공")
@login_required
(로그인 필요)로그인이 필요한 뷰에 데코레이터를 추가할 수 있습니다.
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
return HttpResponse("로그인한 사용자만 접근 가능")
Django의 클래스 기반 뷰(Class-Based View, CBV)를 이해하고 활용할 수 있습니다.
클래스를 기반으로 한 Django 뷰 시스템으로, 코드 재사용성이 높아지고 유지보수가 편리합니다.
Django의 View
클래스를 상속받아 GET/POST 요청을 처리할 수 있습니다.
from django.http import HttpResponse
from django.views import View
class MyView(View):
def get(self, request):
return HttpResponse("Hello, world!")
Django는 CRUD(Create, Read, Update, Delete) 작업을 쉽게 수행할 수 있도록 제네릭 뷰(Generic Views)를 제공합니다.
CreateView
(객체 생성)새로운 객체를 생성하는 뷰
from django.views.generic import CreateView
from myapp.models import Post
from django.urls import reverse_lazy
class PostCreateView(CreateView):
model = Post
fields = ["title", "content"]
success_url = reverse_lazy("post_list") # 성공 후 이동할 URL
form_valid(form)
: 폼이 유효할 때 호출 (객체를 저장한 후 리디렉트)form_invalid(form)
: 폼이 유효하지 않을 때 호출get_form_class()
: 사용할 폼 클래스를 반환get_form_kwargs()
: 폼에 전달할 인자를 정의get_success_url()
: 성공 후 리디렉트할 URL을 반환form
: 생성할 객체의 폼(form)object
: 생성된 객체ListView
(객체 목록 조회)객체 리스트를 보여주는 뷰
from django.views.generic import ListView
class PostListView(ListView):
model = Post
template_name = "post_list.html"
get_queryset()
: 기본적으로 model.objects.all()
반환 (조회할 데이터셋을 설정 가능)get_context_data(**kwargs)
: 템플릿에서 사용할 컨텍스트 데이터를 추가할 때 사용object_list
: 모델의 모든 객체 리스트 (예: Post.objects.all()
)is_paginated
: 페이지네이션이 적용되었는지 여부 (True
또는 False
)paginator
: 페이지네이션 객체DetailView
(객체 상세 조회)단일 객체의 상세 정보를 보여주는 뷰
from django.views.generic import DetailView
class PostDetailView(DetailView):
model = Post
get_object()
: 기본적으로 model.objects.get(pk=값)
을 실행하여 객체를 가져옴get_context_data(**kwargs)
: 템플릿에서 사용할 컨텍스트 데이터를 추가할 때 사용object
: 조회된 단일 객체 (예: Post.objects.get(pk=값)
)get_object()
: 기본적으로 model.objects.get(pk=값)
을 실행하여 객체를 가져옴get_context_data(**kwargs)
: 템플릿에서 사용할 컨텍스트 데이터를 추가할 때 사용object
: 조회된 단일 객체 (예: Post.objects.get(pk=값)
)user
가져오기 (현재 로그인한 사용자)current_user = request.user
print(current_user.username)
data
가져오기 (POST 요청 데이터)username = request.POST.get("username")
def my_view(request, user_id):
print(user_id) # URL에서 user_id 값 가져오기
search_query = request.GET.get("q") # ?q=검색어
HttpResponseRedirect
(리다이렉트)from django.http import HttpResponseRedirect
return HttpResponseRedirect("/home/")
HttpResponse
(간단한 응답)from django.http import HttpResponse
return HttpResponse("Hello, world!")
status code
(HTTP 응답 코드 설정)return HttpResponse("Forbidden", status=403)
Django에서 이메일을 보내는 방법
send_mail
from django.core.mail import send_mail
send_mail(
"Subject",
"Message",
"from@example.com",
["to@example.com"],
fail_silently=False,
)
django.core.signing
Django의 django.core.signing
모듈은 데이터를 서명하고 검증하는 기능을 제공합니다.
이 모듈을 사용하면 데이터를 변조되지 않도록 보호할 수 있습니다.
django.core.signing
사용법from django.core import signing
data = "secure_data"
signed_data = signing.sign(data)
print(signed_data) # 서명된 데이터 출력
original_data = signing.unsign(signed_data)
print(original_data) # 'secure_data' 출력
TimestampSigner
시간 제한 서명 생성
from django.core.signing import TimestampSigner
signer = TimestampSigner()
value = signer.sign("my_value")
original = signer.unsign(value, max_age=3600) # 1시간 유효
Django의 ImageField
는 이미지 파일을 저장하고 관리할 수 있도록 해주는 모델 필드입니다.
ImageField
는 Django 모델에서 이미지 파일을 저장하는 데 사용됩니다.Pillow
라이브러리가 필요합니다.from django.db import models
class Profile(models.Model):
avatar = models.ImageField(upload_to='avatars/')
ImageField
를 사용할 때 필요pip install pillow
pip install django-cleanup
MEDIA_ROOT
와 MEDIA_URL
MEDIA_ROOT
: 업로드된 파일이 저장되는 디렉터리MEDIA_URL
: 업로드된 파일에 접근할 수 있는 URLimport os
from django.conf import settings
MEDIA_ROOT = os.path.join(settings.BASE_DIR, 'media')
MEDIA_URL = '/media/'
pip install django-summernote
INSTALLED_APPS = [
'django_summernote',
]
# urls.py
from django.urls import path, include
urlpatterns = [
path('summernote/', include('django_summernote.urls')),
]
from django.db import models
from django_summernote.fields import SummernoteTextField
class Post(models.Model):
content = SummernoteTextField()
shell_plus
) graph_models
)pip install django-extensions
INSTALLED_APPS = [
'django_extensions',
]
shell_plus
사용법python manage.py shell_plus
아래 절차에 따라 네이버 소셜 로그인을 구현합니다.
client_id
와 redirect_uri
를 확인access_token
요청access_token
으로 사용자 정보 조회NAVER_CLIENT_ID = "네이버 클라이언트 ID"
NAVER_CLIENT_SECRET = "네이버 클라이언트 시크릿"
NAVER_CALLBACK_URL = "http://localhost:8000/oauth/naver/callback/"
import requests
from django.conf import settings
def get_naver_access_token(code, state):
params = {
'grant_type': 'authorization_code',
'client_id': settings.NAVER_CLIENT_ID,
'client_secret': settings.NAVER_CLIENT_SECRET,
'code': code,
'state': state,
}
response = requests.get("https://nid.naver.com/oauth2.0/token", params=params)
return response.json().get('access_token')
def get_naver_profile(access_token):
headers = {
'Authorization': f'Bearer {access_token}'
}
response = requests.get("https://openapi.naver.com/v1/nid/me", headers=headers)
return response.json().get('response')
from django.contrib.auth.models import User # ❌ 이렇게 직접 가져오면 안 됨
object_list = User.objects.filter(nickname__icontains=q)
이렇게 가져오면 커스타미이징한 User를 가져오지 않는다
from django.contrib.auth import get_user_model
User = get_user_model()
object_list = User.objects.filter(nickname__icontains=q) # ✅ nickname 필드가 존재하는 커스텀 User 모델을 자동으로 가져옴
-> 우클릭 refactor -> Convert to Python Package ->
__init__
이름 변경 및 ,__init__
생성 ->__init__
파일에from .파일명 import *
작성