📢 공지사항
home
3️⃣

3주차 (21-30)

Accountapp implementation

21강. CreateView를 통한 회원가입 구현

학습 목표 : 장고에서 제공하는 CreateView를 통해 Account의 Create, 즉 회원 가입을 구현해 본다.
1) pragmatic/accountApp/views.py
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render from django.urls import reverse, reverse_lazy from accountApp.models import HelloWorld from django.views.generic import CreateView def hello_world(request): # class-Based View로 AccountCreateView를 추가한다. class AccountCreateView(CreateView): model = User form_class = UserCreationForm success_url = reverse_lazy('accountApp:hello_world') # 계정 만들기 성공 했으면, 어느 경로로 연결할 것인가? template_name = 'accountApp/create.html' # 어느 html 파일을 통해서 볼지?
Python
복사
model = User : 장고 기본 제공 model
form_class = UserCreationForm : 장고 기본 제공 form
success_url = reverse_lazy(' ') : 계정 생성 성공 시, 어느 경로로 연결 될 건지? (※ defreverse 사용, classreverse_lazy 사용)
template_name = ' ' : 어느 html 파일을 통해서 볼 건지?
2) pragmatic/accountApp/urls.py
from django.urls import path from accountApp.views import hello_world, AccountCreateView app_name = "accountApp" urlpatterns = [ path('hello_world/', hello_world, name='hello_world'), # create 경로를 추가한다. path('create/', AccountCreateView.as_view(), name='create'), ]
Python
복사
3) pragmatic/accountApp/templates/accountApp/create.html (create.html 생성)
{% extends 'base.html' %} {% block content %} <div style="text-align: center"> <form action="{% url 'accountApp:create' %}" method="post"> <!-- post 사용 시, 잊지 말 것! --> {% csrf_token %} <!-- views.py에서 지정한 class form --> {{ form }} <input type="submit" class="btn btn-primary"> </form> </div> {% endblock %}
HTML
복사

22강. Login / Logout 구현

학습 목표 : 장고에서 제공되는 LoginView, LogoutView를 기반으로 로그인 및 로그아웃 기능을 구현한다.
1) pragmatic/accountApp/urls.py
from django.urls import path from accountApp.views import hello_world, AccountCreateView from django.contrib.auth.views import LoginView, LogoutView app_name = "accountApp" urlpatterns = [ path('hello_world/', hello_world, name='hello_world'), # login과 logout 경로를 추가한다. path('login/', LoginView.as_view(template_name='accountApp/login.html'), name='login'), path('logout/', LogoutView.as_view(), name='logout'), path('create/', AccountCreateView.as_view(), name='create'), ]
Python
복사
2) pragmatic/accountApp/templates/accountApp/login.html (login.html 생성)
{% extends 'base.html' %} {% block content %} <div style="text-align: center"> <div> <h4>Login</h4> </div> <div> <form action="" method="post"> {% csrf_token %} {{ form }} <input type="submit" class="btn btn-primary"> </form> </div> </div> {% endblock %}
HTML
복사
3) pragmatic/pragmatic/templates/header.html
<div class="pragmatic_header"> <div> <h1 class="pragmatic_logo">Pragmatic</h1> </div> <div> <span>nav1</span> <span>nav2</span> <span>nav3</span> {% if not user.is_authenticated %} <!--유저가 로그인 되어 있지 않을 경우--> <a href="{% url 'accountApp:login' %}?next={{ request.path }}"> <span>login</span> </a> {% else %} <!--유저가 로그인 되어 있을 경우--> <a href="{% url 'accountApp:logout' %}?next={{ request.path }}"> <span>logout</span> </a> {%endif %} </div> </div>
HTML
복사
4) pragmatic/pragmatic/settings.py
from pathlib import Path import environ import os from django.urls import reverse_lazy # 맨 하단에 Redirect 경로를 추가한다. LOGIN_REDIRECT_URL = reverse_lazy('accountApp:hello_world') LOGOUT_REDIRECT_URL = reverse_lazy('accountApp:login')
Python
복사

23강. Bootstrap을 이용한 Form 디자인 정리

학습 목표 : django-bootstrap4 라이브러리를 이용하여 form을 부트스트랩 스타일로 꾸며보고, 지금까지 만든 사이트의 디자인을 정리한다.
1) pragmatic/pragmatic/settings.py
우선, 터미널에서 pip install django-bootstrap4 입력하여 설치한다.
그 다음 settings.py에서 내용을 추가한다.
from pathlib import Path import environ import os from django.urls import reverse_lazy # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'accountApp', # 추가한다. 'bootstrap4', ]
Python
복사
2) pragmatic/accountApp/templates/accountApp/login.html
{% extends 'base.html' %} {% load bootstrap4 %} {% block content %} <!-- (문단의 스타일을 추가적으로 변경함) --> <div style="text-align: center; max-width: 500px; margin: 4rem auto"> <div> <h4>Login</h4> </div> <div> <form action="" method="post"> {% csrf_token %} <!-- 기존 {{ form }} 대신 bootstrap_form으로 변경한다.--> {% bootstrap_form form %} <input type="submit" class="btn btn-dark rounded-pill col-6 mt-3"> </form> </div> </div> {% endblock %}
HTML
복사
3) pragmatic/accountApp/templates/accountApp/create.html
{% extends 'base.html' %} <!-- 추가한다. --> {% load bootstrap4 %} {% block content %} <!-- 변경한다. --> <div style="text-align: center; max-width: 500px; margin: 4rem auto"> <div class="mb-4"> <h4>SignUp</h4> </div> <form action="{% url 'accountApp:create' %}" method="post"> {% csrf_token %} {% bootstrap_form form %} <input type="submit" class="btn btn-dark rounded-pill col-6 mt-3"> </form> </div> {% endblock %}
HTML
복사
4) pragmatic/templates/head.html (폰트를 전체적으로 변경하고 싶을 때)
우선, pragmatic/static 하단에 ‘fonts’라는 새 디렉토리를 생성한 후, 다운 받은 글꼴 파일을 삽입한다.
그 다음 head.html 파일에서 <style> 태그를 통해 내용을 추가한다.
{% load static %} <head> <meta charset="UTF-8"> <title>Pragmatic</title> <!-- 폰트 정보를 추가한다. --> <style> @font-face { font-family: 'NanumPen'; src: local('NanumPen'), url("{% static 'fonts/NanumPen.ttf' %}") format("opentype"); } </style> </head>
HTML
복사

24강. DetailView를 이용한 개인 페이지 구현

학습 목표 : DetailView를 이용하여 개인 페이지를 만들어 본다.
ReadView = DetailView (장고에서 사용)
1) pragmatic/pragmatic/views.py
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render from django.urls import reverse, reverse_lazy # Create your views here. from accountApp.models import HelloWorld from django.views.generic import CreateView, DetailView def hello_world(request): class AccountCreateView(CreateView): # AccountDetailView 클래스를 추가한다. class AccountDetailView(DetailView): model = User context_object_name = 'target_user' template_name = 'accountApp/detail.html'
Python
복사
2) pragmatic/accountApp/templates/accountApp/detail.html (detail.html 생성)
{% extends 'base.html' %} {% block content %} <div> <div style="text-align: center; max-width: 500px; margin: 4rem auto;"> <p> {{ target_user.date_joined }} </p> <h2 style="font-family: 'NanumPen'"> {{ target_user.username }} </h2> </div> </div> {% endblock %}
HTML
복사
3) pragmatic/accountApp/urls.py
from django.contrib.auth.views import LoginView, LogoutView from django.urls import path from accountApp.views import hello_world, AccountCreateView, AccountDetailView app_name = "accountApp" urlpatterns = [ path('hello_world/', hello_world, name='hello_world'), path('login/', LoginView.as_view(template_name='accountApp/login.html'), name='login'), path('logout/', LogoutView.as_view(), name='logout'), path('create/', AccountCreateView.as_view(), name='create'), # detail 경로를 추가한다. path('detail/<int:pk>', AccountDetailView.as_view(), name='detail'), ]
Python
복사
4) pragmatic/templates/header.html
<div class="pragmatic_header"> <div> <h1 class="pragmatic_logo">Pragmatic</h1> </div> <div> <span>nav1</span> <span>nav2</span> <span>nav3</span> {% if not user.is_authenticated %} <!-- 유저가 로그인 되어 있지 않을 경우 --> {% else %} <!-- 유저가 로그인 되어 있을 경우 --> <!-- detail.html로 연결될 MyPage 바를 추가한다. --> <a href="{% url 'accountApp:detail' pk=user.pk %}"> <span>MyPage</span> </a> <a href="{% url 'accountApp:logout' %}?next={{ request.path }}"> <span>logout</span> </a> {%endif %} </div> </div>
HTML
복사

25강. UpdateView를 이용한 비밀번호 변경 구현

학습 목표 : UpdateView를 이용한 비밀번호 변경 구현을 진행한다.
1) pragmatic/accountApp/views.py
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render from django.urls import reverse, reverse_lazy from accountApp.models import HelloWorld from django.views.generic import CreateView, DetailView, UpdateView from accountApp.forms import AccountUpdateForm def hello_world(request): class AccountCreateView(CreateView): class AccountDetailView(DetailView): # AccountCreatView 클래스를 토대로 AccountUpdateView를 추가한다. class AccountUpdateView(UpdateView): model = User context_object_name = 'target_user' form_class = AccountUpdateForm # Form을 바꿔줌 success_url = reverse_lazy('accountApp:hello_world') template_name = 'accountApp/update.html'
Python
복사
2) pragmatic/accountApp/urls.py
from django.contrib.auth.views import LoginView, LogoutView from django.urls import path from accountApp.views import hello_world, AccountCreateView, AccountDetailView, AccountUpdateView app_name = "accountApp" urlpatterns = [ path('hello_world/', hello_world, name='hello_world'), path('login/', LoginView.as_view(template_name='accountApp/login.html'), name='login'), path('logout/', LogoutView.as_view(), name='logout'), path('create/', AccountCreateView.as_view(), name='create'), path('detail/<int:pk>', AccountDetailView.as_view(), name='detail'), # update 경로를 추가한다. path('update/<int:pk>', AccountUpdateView.as_view(), name='update'), ]
Python
복사
3) pragmatic/accountApp/templates/accountApp/update.html (update.html 생성)
<!-- create.html 내용을 토대로 작성함 --> {% extends 'base.html' %} {% load bootstrap4 %} {% block content %} <div style="text-align: center; max-width: 500px; margin: 4rem auto"> <div class="mb-4"> <h4>Change Info</h4> </div> <form action="{% url 'accountApp:update' pk=target_user.pk %}" method="post"> {% csrf_token %} {% bootstrap_form form %} <input type="submit" class="btn btn-dark rounded-pill col-6 mt-3"> </form> </div> {% endblock %}
HTML
복사
4) pragmatic/accountApp/templates/accountApp/detail.html
{% extends 'base.html' %} {% block content %} <div> <div style="text-align: center; max-width: 500px; margin: 4rem auto;"> <p> {{ target_user.date_joined }} </p> <h2 style="font-family: 'NanumPen'"> {{ target_user.username }} </h2> <!-- 로그인 했을 경우, 변경하고자 하는 유저가 본인일 경우 update 가능 (추가) --> {% if target_user == user %} <a href="{% url 'accountApp:update' pk=user.pk %}"> <p> Change Info </p> </a> {% endif %} </div> </div> {% endblock %}
HTML
복사
5) pragmatic/accountApp/forms.py (forms.py 생성)
# update 시, id 변경을 비활성화 하기 위한 용도 from django.contrib.auth.forms import UserCreationForm class AccountUpdateForm(UserCreationForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields['username'].disabled = True
Python
복사

26강. DeleteView 기반 회원 탈퇴 구현

학습 목표 : DeleteView 기반 회원 탈퇴 구현을 진행한다.
1) pragmatic/accountApp/views.py
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render from django.urls import reverse, reverse_lazy from accountApp.models import HelloWorld from django.views.generic import CreateView, DetailView, UpdateView, DeleteView from accountApp.forms import AccountUpdateForm def hello_world(request): class AccountCreateView(CreateView): class AccountDetailView(DetailView): class AccountUpdateView(UpdateView): # AccountDeleteView를 추가한다. class AccountDeleteView(DeleteView): model = User context_object_name = 'target_user' success_url = reverse_lazy('accountApp:login') template_name = 'accountApp/delete.html'
Python
복사
2) pragmatic/accountApp/urls.py
from django.contrib.auth.views import LoginView, LogoutView from django.urls import path from accountApp.views import hello_world, AccountCreateView, AccountDetailView from accountApp.views import AccountUpdateView, AccountDeleteView app_name = "accountApp" urlpatterns = [ path('hello_world/', hello_world, name='hello_world'), path('login/', LoginView.as_view(template_name='accountApp/login.html'), name='login'), path('logout/', LogoutView.as_view(), name='logout'), path('create/', AccountCreateView.as_view(), name='create'), path('detail/<int:pk>', AccountDetailView.as_view(), name='detail'), path('update/<int:pk>', AccountUpdateView.as_view(), name='update'), # delete 경로를 추가한다. path('delete/<int:pk>', AccountDeleteView.as_view(), name='delete'), ]
Python
복사
3) pragmatic/accountApp/templates/accountApp/delete.html (delete.html 생성)
{% extends 'base.html' %} {% block content %} <div style="text-align: center; max-width: 500px; margin: 4rem auto"> <div class="mb-4"> <h4>Quit</h4> </div> <form action="{% url 'accountApp:delete' pk=target_user.pk %}" method="post"> {% csrf_token %} <input type="submit" class="btn btn-danger rounded-pill col-6 mt-3"> </form> </div> {% endblock %}
HTML
복사
4) pragmatic/accountApp/templates/accountApp/detail.html
{% extends 'base.html' %} {% block content %} <div> <div style="text-align: center; max-width: 500px; margin: 4rem auto;"> <p> {{ target_user.date_joined }} </p> <h2 style="font-family: 'NanumPen'"> {{ target_user.username }} </h2> {% if target_user == user %} <a href="{% url 'accountApp:update' pk=user.pk %}"> <p> Change Info </p> </a> <!-- Quit이 가능한 경우를 추가해 준다. --> <a href="{% url 'accountApp:delete' pk=user.pk %}"> <p> Quit </p> </a> {% endif %} </div> </div> {% endblock %}
HTML
복사
5) pragmatic/templates/header.html
<div class="pragmatic_header"> <div> <h1 class="pragmatic_logo">Pragmatic</h1> </div> <div> <span>nav1</span> <span>nav2</span> <span>nav3</span> {% if not user.is_authenticated %} <!-- 유저가 로그인 되어 있지 않을 경우 --> <a href="{% url 'accountApp:login' %}?next={{ request.path }}"> <span>login</span> </a> <a href="{% url 'accountApp:create' %}"> <span>SignUp</span> </a> {% else %} <!-- 유저가 로그인 되어 있을 경우 --> <a href="{% url 'accountApp:detail' pk=user.pk %}"> <span>MyPage</span> </a> <a href="{% url 'accountApp:logout' %}?next={{ request.path }}"> <span>logout</span> </a> {%endif %} </div> </div>
HTML
복사

Authentication

27강. Authentication 인증 시스템 구축

학습 목표 : 요청을 보내는 유저가 로그인을 했는지, 또 접근하는 페이지의 성격에 따라 해당 페이지의 유저 객체와 요청 유저 객체를 비교하고, 필요할 경우 요청을 차단하는 코드를 구축한다.
1) pragmatic/accountApp/views.py
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render from django.urls import reverse, reverse_lazy from accountApp.models import HelloWorld from django.views.generic import CreateView, DetailView, UpdateView, DeleteView from accountApp.forms import AccountUpdateForm from django.http import HttpResponseForbidden def hello_world(request): class AccountCreateView(CreateView): class AccountDetailView(DetailView): class AccountUpdateView(UpdateView): model = User context_object_name = 'target_user' form_class = AccountUpdateForm success_url = reverse_lazy('accountApp:hello_world') template_name = 'accountApp/update.html' # 로그인 되어 있을 때만 Update 가능 + 타 계정으로는 접속 불가능 def get(self, *args, **kwargs): if self.request.user.is_authenticated and self.get_object() == self.request.user: return super().get(*args, **kwargs) else: return HttpResponseForbidden() def post(self, *args, **kwargs): if self.request.user.is_authenticated and self.get_object() == self.request.user: return super().post(*args, **kwargs) else: return HttpResponseForbidden() class AccountDeleteView(DeleteView): model = User context_object_name = 'target_user' success_url = reverse_lazy('accountApp:login') template_name = 'accountApp/delete.html' # 로그인 되어 있을 때만 Delete 가능 + 타 계정으로는 접속 불가능 def get(self, *args, **kwargs): if self.request.user.is_authenticated and self.get_object() == self.request.user: return super().get(*args, **kwargs) else: return HttpResponseForbidden() def post(self, *args, **kwargs): if self.request.user.is_authenticated and self.get_object() == self.request.user: return super().post(*args, **kwargs) else: return HttpResponseForbidden()
Python
복사

28강. Decorator를 이용한 코드 간소화

학습 목표 : 파이썬의 Decorator 패턴을 이용해 자주 쓰이는 코드들을 줄여본다. 장고에서 기본 제공하는 Decorator부터 커스터마이징 한 Decorator로 27강에서 만든 인증시스템 코드 볼륨을 줄인다.
함수의 내부를 변경시키지는 않지만, 함수를 앞 뒤로 꾸며주는 역할을 한다.

Function

1) Decorator 적용 전
... def hello_world(request): if request.user.is_authenticated: if request.method == "POST": temp = request.POST.get('hello_world_input') new_hello_world = HelloWorld() new_hello_world.text = temp new_hello_world.save() hello_world_list = HelloWorld.objects.all() return HttpResponseRedirect(reverse('accountApp:hello_world')) else: hello_world_list = HelloWorld.objects.all() return render(request, 'accountApp/hello_world.html', context={'hello_world_list': hello_world_list}) else: return HttpResponseRedirect(reverse('accountApp:login')) ...
Python
복사
2) Decorator 적용 후 (장고 기본 제공)
from django.contrib.auth.decorators import login_required ... @login_required def hello_world(request): if request.method == "POST": temp = request.POST.get('hello_world_input') new_hello_world = HelloWorld() new_hello_world.text = temp new_hello_world.save() hello_world_list = HelloWorld.objects.all() return HttpResponseRedirect(reverse('accountApp:hello_world')) else: hello_world_list = HelloWorld.objects.all() return render(request, 'accountApp/hello_world.html', context={'hello_world_list': hello_world_list}) ...
Python
복사

Method (class 내부)

1) Decorator 적용 전
... class AccountUpdateView(UpdateView): model = User context_object_name = 'target_user' form_class = AccountUpdateForm success_url = reverse_lazy('accountApp:hello_world') template_name = 'accountApp/update.html' def get(self, *args, **kwargs): if self.request.user.is_authenticated and self.get_object() == self.request.user: return super().get(*args, **kwargs) else: return HttpResponseForbidden() def post(self, *args, **kwargs): if self.request.user.is_authenticated and self.get_object() == self.request.user: return super().post(*args, **kwargs) else: return HttpResponseForbidden() class AccountDeleteView(DeleteView): model = User context_object_name = 'target_user' success_url = reverse_lazy('accountApp:login') template_name = 'accountApp/delete.html' def get(self, *args, **kwargs): if self.request.user.is_authenticated and self.get_object() == self.request.user: return super().get(*args, **kwargs) else: return HttpResponseForbidden() def post(self, *args, **kwargs): if self.request.user.is_authenticated and self.get_object() == self.request.user: return super().post(*args, **kwargs) else: return HttpResponseForbidden()
Python
복사
2) Decorator 적용 후 (장고 기본 제공)
@method_decorator(function, ‘적용할 method’)
: 일반 function에 사용하는 decorator를 method에 사용할 수 있도록 변환해주는 decorator
from django.contrib.auth.decorators import login_required from django.utils.decorators import method_decorator ... @method_decorator(login_required, 'get') @method_decorator(login_required, 'post') class AccountUpdateView(UpdateView): model = User context_object_name = 'target_user' form_class = AccountUpdateForm success_url = reverse_lazy('accountApp:hello_world') template_name = 'accountApp/update.html' @method_decorator(login_required, 'get') @method_decorator(login_required, 'post') class AccountDeleteView(DeleteView): model = User context_object_name = 'target_user' success_url = reverse_lazy('accountApp:login') template_name = 'accountApp/delete.html'
Python
복사

직접 만든 Decorator 적용하기

1) pragmatic/accountApp/decorators.py (decorators.py 생성)
from django.contrib.auth.models import User from django.http import HttpResponseForbidden # (get, post 모두) pk를 확인해서, User.objects가 실제 request를 보낸 유저와 같은지 판별 def account_ownership_required(func): def decorated(request, *args, **kwargs): # 요청을 받으면서 pk(primary key)로 'pk' 값을 가지고 있는 유저가 user가 된다. user = User.objects.get(pk=kwargs['pk']) # user를 확인해서, 다른 경우 Forbidden 된다. if not user == request.user: return HttpResponseForbidden() return func(request, *args, **kwargs) return decorated
Python
복사
2) Decorator 적용 후 1 (직접 만든 Decorator 적용)
from django.contrib.auth.decorators import login_required from django.utils.decorators import method_decorator from accountApp.decorators import account_ownership_required ... @method_decorator(login_required, 'get') @method_decorator(login_required, 'post') @method_decorator(account_ownership_required, 'get') @method_decorator(account_ownership_required, 'post') class AccountUpdateView(UpdateView): model = User context_object_name = 'target_user' form_class = AccountUpdateForm success_url = reverse_lazy('accountApp:hello_world') template_name = 'accountApp/update.html' @method_decorator(login_required, 'get') @method_decorator(login_required, 'post') @method_decorator(account_ownership_required, 'get') @method_decorator(account_ownership_required, 'post') class AccountDeleteView(DeleteView): model = User context_object_name = 'target_user' success_url = reverse_lazy('accountApp:login') template_name = 'accountApp/delete.html'
Python
복사
3) Decorator 적용 후 2 (직접 만든 Decorator 적용, 코드 간소화)
from django.contrib.auth.decorators import login_required from django.utils.decorators import method_decorator from accountApp.decorators import account_ownership_required # 배열로 만든다. (method_decorator에 넣으면, 배열 내에 있는 decorator들을 다 확인함) has_ownership = [account_ownership_required, login_required()] ... @method_decorator(has_ownership, 'get') @method_decorator(has_ownership, 'post') class AccountUpdateView(UpdateView): model = User context_object_name = 'target_user' form_class = AccountUpdateForm success_url = reverse_lazy('accountApp:hello_world') template_name = 'accountApp/update.html' @method_decorator(has_ownership, 'get') @method_decorator(has_ownership, 'post') class AccountDeleteView(DeleteView): model = User context_object_name = 'target_user' success_url = reverse_lazy('accountApp:login') template_name = 'accountApp/delete.html'
Python
복사

29강. superuser, media 관련 설정

학습 목표 : createsuperuser 명령어를 통한 관리자 계정 생성, 그리고 Media 파일을 다루기 위해 필요한 설정들을 진행한다.
1) superuser(관리자) 계정 생성
jangs@DESKTOP-70KJSMB MINGW64 ~/PycharmProjects/pragmatic_2/pragmatic (master)
$ python manage.py createsuperuser
Username (leave blank to use 'jangs'): username입력
Email address: (생략 가능)
Password: password 입력
Password (again): password 입력
Superuser created successfully.
jangs@DESKTOP-70KJSMB MINGW64 ~/PycharmProjects/pragmatic_2/pragmatic (master) $ python manage.py createsuperuser Username (leave blank to use 'jangs'): jang Email address: Password: Password (again): Error: Blank passwords aren't allowed. Password: Password (again): Superuser created successfully.
2) pragmatic/pragmatic/settings.py
step 1. 하단에 MEDIA_URLMEDIA_ROOT를 추가한다.
... STATIC_URL = 'static/' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') STATICFILES_DIRS = [ BASE_DIR / "static", ] DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' LOGIN_REDIRECT_URL = reverse_lazy('accountApp:hello_world') LOGOUT_REDIRECT_URL = reverse_lazy('accountApp:login') # 실제 미디어 파일에 접근하기 위해, 주소창에서 media ~(이하) 필요하다. MEDIA_URL = '/media/' # 미디어 파일을 서버에 올렸을 때, 어느 경로에 지정될 것인지에 대한 정보 MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Python
복사
step 2. 터미널 창에서 $ pip install pillow 를 입력하여 설치한다.

Profileapp Implementation

30강. Profileapp 시작 그리고 ModelForm

학습 목표 : 새로운 앱 Profileapp을 시작한다. 그리고 모델 기반으로 간편하게 Form을 만들어 주는 ModelForm을 짚고 넘어간다.

Profileapp 시작

account 앱과 profile 객체를 1:1로 매칭 시킨다. (즉, account 하나에 하나의 profile)
Profile Image / Profile Nickname / Profile Message 세 가지로 구성된다.
Delete View와 Detail View는 구현하지 않는다.
1) profileApp 생성
터미널 창에 $ python manage.py startapp profileApp 를 입력한다.
2) pragmatic/pragmatic/settings.py
from pathlib import Path import environ import os from django.urls import reverse_lazy # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'accountApp', 'bootstrap4', # 추가한다. 'profileApp', ]
Python
복사
3) pragmatic/pragmatic/urls.py
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('accounts/', include('accountApp.urls')), # profiles 경로를 추가한다. path('profiles/', include('profileApp.urls')), ]
Python
복사
4) pragmatic/profileAPP/urls.py (urls.py 생성)
app_name = 'profileApp' urlpatterns = [ # 추가로 작성할 것 ]
Python
복사
5) pragmatic/profileAPP/models.py
from django.contrib.auth.models import User from django.db import models class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile') image = models.ImageField(upload_to='profile/', null=True) nickname = models.CharField(max_length=20, unique=True, null=True) message = models.CharField(max_length=100, null=True)
Python
복사
6) pragmatic/profileAPP/forms.py (forms.py 생성)
from django.forms import ModelForm from profileApp.models import Profile class ProfileCreationForm(ModelForm): class Meta: model = Profile fields = ['image', 'nickname', 'message']
Python
복사