www.youtube.com/watch?v=Kc1Q_ayAeQk&list=PL-51WBLyFTg2vW-_6XBoUpE7vpmoR3ztO&index=18
www.youtube.com/watch?v=jYzTKcvO0Pk&list=PL-51WBLyFTg2vW-_6XBoUpE7vpmoR3ztO&index=19
이 포스팅은 다음과 같은 youtube 영상을 따라하면서 배운 내용과 학습 내용을 담은 것이다:
- Dennis Ivy - Introduction to Django Signals | Django Framework (3.0) Crash Course Tutorials (pt 18)
- Dennis Ivy - Creating Customer Profiles with Django Signals | Django Framework (3.0) Crash Course Tutorials (pt 19)
현재 Django Version 3.1.2 를 쓰고 있다. Django는 파이썬을 쓰는 오픈소스 웹 프레임워크이다. 웹사이트 만들때 주로 쓰며, 간단한 것이 큰 특징이다.
※ signals.py 추가하기
Django Documentation에서는 Django Signals를 다음과 같이 정의하고 있다:
"Django includes a “signal dispatcher” which helps allow decoupled applications get notified when actions occur elsewhere in the framework. In a nutshell, signals allow certain senders to notify a set of receivers that some action has taken place. They’re especially useful when many pieces of code may be interested in the same events."
즉 간략하게 설명하면, signal은 sender가 무슨 행동을 취했는지를 receiver가 인식하게끔 해주는 것이다. decorator들과 비슷하게, 비슷한 상황들이 일어난다면 이러한 코드들을 통해 여러 상황에 적용이 가능하게 끔 해준다. 이 signal에는 여러가지가 있는데, 예를 들면 pre_save, post_save, pre_delete, post_delete, m2m_changed, request_started, request_finished 등등이 있다. 자세한 것은 여기에서 찾아볼 수 있다.
이제 accounts/에 signals.py를 추가해준다:
# signals.py
from django.contrib.auth.models import User, Group
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Customer
@receiver(post_save, sender=User)
def customer_profile(sender, instance, created, **kwargs):
if created:
group = Group.objects.get(name='customer')
instance.groups.add(group)
Customer.objects.create(user=instance, name=instance.username, email=instance.email)
우리가 사용할 시그널의 경우는, 사용자가 회원 가입을 했을때, 사용자를 Customer이라는 Group으로 자동 저장시켜주는 것을 하기 위한 것이다.
따라서 User, Group 을 django.contrib.auth.models에서 import를 해준다. 또한, Customer class를 쓸 것이기 때문에 .models에서 Customer를 import 해준다.
또한, django.db.models.signals에서 post_save라는 것을 import 해주는데, 이는 save()가 불러일으켜진 후, post_save의 내용들을 send해주는 것이다.
마지막으로 django.displatch에서 receiver를 import 하는것은 post_save를 decorator 형식으로 써주기 위함이다.
그렇다면 이제 customer_profile 함수를 한번 살펴보자. sender, instance, created, **kwargs는 무조건 통과를 시켜줘야 하는 변수들로 정의가 되어 있다. 또한, if created는 "새로운 기록이 생성되면"이라는 값이 True 일 경우를 의미하는데, 이 "새로운 기록이 생성되면"을 Django는 sender의 model class를 통해 인식한다. 즉, sender=에 있는 model class에 새로운 기록이 생긴다면, 이 함수가 실행되는 것이다. 여기서는 User model에 새로운 기록이 생기면 signal이 send되게 하는 것이므로, sender=User 이다.
다음은 if created: 이후의 코드이다. (views.py에 있는 registerPage 함수에 있는 내용들을 가지고 왔다) group은 'customer'이라는 이름의 Group의 object를 불러와서 저장하고, instance.groups.add(group)을 통해 이 instance에 group을 추가해준다. 여기서 instance는 우리가 실제로 저장하려는 인스턴스를 의미한다. (이 경우는 우리가 새로 생성한 사용자)
마지막으로는 Customer이라는 class 안에 이 사용자를 저장시켜주는 것이다. 여기서도 user=user가 아닌 user=instance로 정의를 해주어 실제로 추가되는 instance를 통과시켜주는 것이다.
여기서 헷갈릴 수 있는 부분은, Group에 instance(=user)을 추가해줬는데, 왜 Customer class에 다시 instance를 추가해줘야 하는 것이다. 이전 포스팅을 보면 기억날 수도 있지만, Group에 instance를 추가해준 것은 특정 사용자만 특정 페이지를 접근 권한이 가지게끔 하기 위한 것이었고, Customer class에 instance를 추가하는 것은 사용자가 Customer class에 추가되어 있어야 주문을 할 수 있기 때문이다.
※ views.py 수정하기
위에 signals.py를 설정해주었기 때문에 이제 views.py를 수정해주어야 한다.
# views.py
...
@unauthenticated_user
def registerPage(request):
form = CreateUserForm()
if request.method == 'POST':
form = CreateUserForm(request.POST)
if form.is_valid():
user = form.save()
return redirect('login')
context = {'form':form}
return render(request, 'accounts/register.html', context)
signals.py에 추가한 부분은 registerPage 함수에서 없애주어야 한다.
※ apps.py / settings.py 수정하기
현재 apps.py는 다음과 같이 되어 있을 것이다:
# apps.py
from django.apps import AppConfig
class AccountsConfig(AppConfig):
name = 'accounts'
이를 다음과 같이 수정한다:
# apps.py
from django.apps import AppConfig
class AccountsConfig(AppConfig):
name = 'accounts'
def ready(self):
import accounts.signals
또한, settings.py 도 현재 다음과 같이 되어 있을 것이다:
# settings.py
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'accounts',
'django_filters',
]
...
이를 다음과 같이 수정한다:
# settings.py
...
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'accounts.apps.AccountsConfig',
'django_filters',
]
...
이렇게 해주지 않는다면 signal이 제대로 전달되지 않는다. 이를 해줌으로써, signal module을 app에 import 해주는 과정이라고 생각하면 된다.
settings.py의 경우, 바꾸지 않고 단순히 app의 __init__.py 에 이렇게 추가할 수 있다:
# __init__.py
default_app_config = "accounts.app.AccountsConfig"
이렇게 하고 settings.py에 있는 INSTALLED_APPS의 'accounts'는 건들지 않아도 정상적으로 작동하게끔 할 수 있다. 하지만 이렇게 하지 않고 settings.py를 수정하는 것이 더 추천하는 방법인 이유는, Django가 그렇게 추천하기 때문이다.
따라서 그냥 settings.py의 INSTALLED_APPS를 수정하는 것이 더 나은 방법이라 생각된다.
이렇게 하면 이제 signals.py를 추가함으로써, 사용자를 customer group에 추가했고, Customer class에도 추가를 할 수 있었다. 그리고 드디어 이제 Youtube Dennis Ivy의 Django Tutorial이 끝났다. 조만간 다른 유튜버의 Django Tutorial로 찾아올 수 있도록 하겠다.