-
<DJANGO>[HTTP Requests]Flower in my dev/Django 2017. 5. 7. 17:32
[HTTP Requests]
1. 기본 URLconf
123456789from django.conf.urls import urlfrom . import viewsurlpatterns = [url(r'^articles/2003/$', views.special_case_2003),url(r'^articles/([0-9]{4})/$', views.year_archive),url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),]cs - 처음 '/'는 필요 없다.
- 정규식에 맞는 인자만 허용
2. 기본 URLconf에서 매개변수 추가
123456789from django.conf.urls import urlfrom . import viewsurlpatterns = [url(r'^articles/2003/$', views.special_case_2003),url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$',views.article_detail),]cs - 전달된 인자를 매개변수에 매칭할 수 있다.
- 형식 : (?P<매개변수>정규식)
3. 모든 인자는 파이썬 문자열이다.
12345678910# URLconffrom django.conf.urls import urlfrom . import viewsurlpatterns = [url(r'^blog/$', views.page),url(r'^blog/page(?P<num>[0-9]+)/$', views.page),]# View (in blog/views.py)def page(request, num="1"):# Output the appropriate page of blog entries, according to num. ...cs - num의 타입을 확인할 수 있다. (num="1")
- 정규식으로 숫자를 검증하지만 전달되는 타입은 str이다.
- 같은 url으로 같은 func을 태우는 방법이다.
4. include로 서브url 추가
1234567from django.conf.urls import include, urlurlpatterns = [# ... snip ...url(r'^community/', include('django_website.aggregator.urls')),url(r'^contact/', include('django_website.contact.urls')),# ... snip ...]cs - 외부 urlsconf를 추가할 수 있다.
5. url 분할하여 include
123456789101112from django.conf.urls import include, url from apps.main import views as main_viewsfrom credit import views as credit_viewsextra_patterns = [url(r'^reports/$', credit_views.report),url(r'^reports/(?P<id>[0-9]+)/$', credit_views.report),url(r'^charge/$', credit_views.charge),]urlpatterns = [url(r'^$', main_views.homepage),url(r'^help/', include('apps.help.urls')),url(r'^credit/', include(extra_patterns)),]cs - credit의 하위 url을 extra_patterns(리스트)로 만들어 include 할 수 있다.
- 아래와 같이 연속된 url을 정리 할 수 있다.
12345678910111213141516171819202122from django.conf.urls import url from . import viewsurlpatterns = [url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/history/$', views.history),url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/edit/$', views.edit),url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/discuss/$', views.discuss),url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/permissions/$', views.permissions),]"""같은 URL공통부분 ^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/"""from django.conf.urls import include, url from . import viewsurlpatterns = [url(r'^(?P<page_slug>[\w-]+)-(?P<page_id>\w+)/', include([url(r'^history/$', views.history),url(r'^edit/$', views.edit),url(r'^discuss/$', views.discuss),url(r'^permissions/$', views.permissions),])),]cs 6. include된 url로도 인자 전달이 된다.
1234567891011121314# In settings/urls/main.pyfrom django.conf.urls import include, urlurlpatterns = [url(r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),]# In foo/urls/blog.pyfrom django.conf.urls import urlfrom . import viewsurlpatterns = [url(r'^$', views.blog.index),url(r'^archive/$', views.blog.archive),]cs 7. 유연한 url
12345from django.conf.urls import urlurlpatterns = [url(r'blog/(page-(\d+)/)?$', blog_articles), # badurl(r'comments/(?:page-(?P<page_number>\d+)/)?$', comments), # good]cs - page의 매칭은 이루어지지만 잡아내지 않는다.
- 인자가 없거나 page_number이 넘어간다.
8. 옵션 전달 url
12345from django.conf.urls import urlfrom . import viewsurlpatterns = [url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),]cs - dict 타입으로 값을 전달할 수 있다.
- 실제 받게 되는 값 : (request, year='2017', foo='bar')
9. 옵션을 전달하는 2가지 경우
12345678910111213# main.pyfrom django.conf.urls import include, urlurlpatterns = [url(r'^blog/', include('inner'), {'blogid': 3}),]# inner.pyfrom django.conf.urls import urlfrom mysite import viewsurlpatterns = [url(r'^archive/$', views.archive),url(r'^about/$', views.about),]cs 12345678910111213# main.pyfrom django.conf.urls import include, urlfrom mysite import viewsurlpatterns = [url(r'^blog/', include('inner')),]# inner.pyfrom django.conf.urls import urlurlpatterns = [url(r'^archive/$', views.archive, {'blogid': 3}),url(r'^about/$', views.about, {'blogid': 3}),]cs - 첫번째경우 : include 다음 dict 타입으로 추가
- 두번째경우 : func 다음 dict 타입으로 추가
10. reverse() 사용하기 01
123456from django.conf.urls import urlfrom . import viewsurlpatterns = [ #...url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),#...]cs 1234567<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>{# Or with the year in a template context variable: #}<ul>{% for yearvar in year_list %}<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>{% endfor %}</ul>cs 1234567from django.urls import reversefrom django.http import HttpResponseRedirectdef redirect_to_year(request):# ...year = 2006# ...return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))cs - urlconf에서 name을 설정
- html에서 name에 설정된 값으로 func 호출
- func에서 HttpResponseRedirect(reverse()) 구현
11. reverse() 사용하기 02
12345from django.conf.urls import include, urlurlpatterns = [url(r'^author-polls/', include('polls.urls', namespace='author-polls')),url(r'^publisher-polls/', include('polls.urls', namespace='publisher-polls')),]cs 1234567from django.conf.urls import urlfrom . import viewsapp_name = 'polls'urlpatterns = [url(r'^$', views.IndexView.as_view(), name='index'),url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),...]cs 1234from django.urls import reversefrom django.http import HttpResponseRedirectdef index_page(request):return HttpResponseRedirect(reverse('polls:index', current_app=self.request.resolver_match.namespace))cs - 메인 url에서 namespace를 추가 include 한다.
- html에서 'app이름 : func의 name'으로 호출한다.
12. app_name 명시하는 방법(two ways)
123456789101112131415#urls.pyfrom django.conf.urls import include, urlurlpatterns = [url(r'^polls/', include('polls.urls')),]#polls/urls.pyfrom django.conf.urls import urlfrom . import viewsapp_name = 'polls'urlpatterns = [url(r'^$', views.IndexView.as_view(), name='index'),url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),...]cs 12345678910from django.conf.urls import include, urlfrom . import viewspolls_patterns = ([url(r'^$', views.IndexView.as_view(), name='index'),url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),], 'polls')urlpatterns = [url(r'^polls/', include(polls_patterns)),]cs - 서브 url에서 app_name 선언
- url(리스트)와 app_name을 튜플로 include
13. 간단한 views
123456from django.http import HttpResponseimport datetimedef current_datetime(request):now = datetime.datetime.now()html = "<html><body>It is now %s.</body></html>" % nowreturn HttpResponse(html)cs - HttpResponse를 import하여 전달
14. error 처리 views
1234567from django.http import HttpResponse, HttpResponseNotFounddef my_view(request):# ...if foo:return HttpResponseNotFound('<h1>Page not found</h1>')else:return HttpResponse('<h1>Page was found</h1>')cs 12345678910# 404 errorfrom django.http import Http404from django.shortcuts import renderfrom polls.models import Polldef detail(request, poll_id):try:p = Poll.objects.get(pk=poll_id)except Poll.DoesNotExist:raise Http404("Poll does not exist")return render(request, 'polls/detail.html', {'poll': p})cs 12345# Customizing error viewshandler404 = 'mysite.views.my_custom_page_not_found_view'handler500 = 'mysite.views.my_custom_error_view'handler403 = 'mysite.views.my_custom_permission_denied_view'handler400 = 'mysite.views.my_custom_bad_request_view'cs - HttpResponseNotFound을 import하여 html 메세지 전달
- 해당 error를 import 하여 전달
- 각각의 error를 상황에 맞게 구현하여 전달
15. Http method 확인
12345from django.views.decorators.http import require_http_methods@require_http_methods(["GET", "POST"])def my_view(request):# I can assume now that only GET or POST requests make it this far # ...passcs - require_http_methods 데코레이터를 사용
- require_GET() : GET method
- require_POST() : POST method
- require_safe() : GET or HEAD method
16. 기본 파일 업로드
12345# forms.pyfrom django import formsclass UploadFileForm(forms.Form):title = forms.CharField(max_length=50)file = forms.FileField()cs 1234567891011121314151617181920# views.pyfrom django.http import HttpResponseRedirectfrom django.shortcuts import renderfrom .forms import UploadFileForm# Imaginary function to handle an uploaded file.from somewhere import handle_uploaded_filedef upload_file(request):if request.method == 'POST':form = UploadFileForm(request.POST, request.FILES)if form.is_valid():handle_uploaded_file(request.FILES['file'])return HttpResponseRedirect('/success/url/')else:form = UploadFileForm()return render(request, 'upload.html', {'form': form})def handle_uploaded_file(f):with open('some/file/name.txt', 'wb+') as destination:for chunk in f.chunks():destination.write(chunk)cs - forms.py에서 파일을 받을 FileField()를 구현
- UploadFileForm으로 request.POST와 FILES를 넘기고 반환값을 받는다.
- validation 확인 후 request.FILES에서 파일을 받아서 저장
- 파일저장로직은 상황에 맞게 구현
17. model 사용하여 파일 업로드
12345678910111213from django.http import HttpResponseRedirectfrom django.shortcuts import renderfrom .forms import ModelFormWithFileFielddef upload_file(request):if request.method == 'POST':form = ModelFormWithFileField(request.POST, request.FILES)if form.is_valid():# file is savedform.save()return HttpResponseRedirect('/success/url/')else:form = ModelFormWithFileField()return render(request, 'upload.html', {'form': form})cs 1234567891011121314from django.http import HttpResponseRedirectfrom django.shortcuts import renderfrom .forms import UploadFileFormfrom .models import ModelWithFileFielddef upload_file(request):if request.method == 'POST':form = UploadFileForm(request.POST, request.FILES)if form.is_valid():instance = ModelWithFileField(file_field=request.FILES['file'])instance.save()return HttpResponseRedirect('/success/url/')else:form = UploadFileForm()return render(request, 'upload.html', {'form': form})cs - ModelFormWithFileField으로 request.POST와 FILES를 넘기고 반환값을 저장한다.
- UploadFileForm으로 request.POST와 FILES를 넘기고 반환값을 받는다.
- 반환값을 검사 후 ModelWithFileField에 request.FILES를 넘기고 반환값을 저장한다.
18. 다중 파일 업로드
12345678910111213141516171819202122# forms.pyfrom django import formsclass FileFieldForm(forms.Form):file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))# views.pyfrom django.views.generic.edit import FormViewfrom .forms import FileFieldFormclass FileFieldView(FormView):form_class = FileFieldFormtemplate_name = 'upload.html' # Replace with your template.success_url = '...' # Replace with your URL or reverse().def post(self, request, *args, **kwargs):form_class = self.get_form_class()form = self.get_form(form_class)files = request.FILES.getlist('file_field')if form.is_valid():for f in files:... # Do something with each file.return self.form_valid(form)else:return self.form_invalid(form)cs - forms.py에서 FileField의 속성을 추가/수정
- views.py에서 루프문으로 각각 파일을 저장한다.
19. 미들웨어 기본 구조 및 적용
12345678910def simple_middleware(get_response):# One-time configuration and initialization.def middleware(request):# Code to be executed for each request before# the view (and later middleware) are called.response = get_response(request)# Code to be executed for each request/response after# the view is called.return responsereturn middlewarecs 1234567891011class SimpleMiddleware(object):def __init__(self, get_response):self.get_response = get_response# One-time configuration and initialization.def __call__(self, request):# Code to be executed for each request before# the view (and later middleware) are called.response = self.get_response(request)# Code to be executed for each request/response after# the view is called.return responsecs 123456789MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',]cs 123456789101112131415161718192021222324252627282930313233343536from django.conf import settingsclass FlowerMiddleware(object):def __init__(self, get_response):self.get_response = get_response# One-time configuration and initialization.def __call__(self, request):# Code to be executed for each request before# the view (and later middleware) are called.response = self.get_response(request)# Code to be executed for each request/response after# the view is called.return response### Called during request:def process_request(self, request):passdef process_view(self, request, view_func, view_args, view_kwargs):pass### Called during response:def process_response(self, request, response):...return responsedef process_template_response(self, request, response):# only for template responsespassdef process_exception(self, request, exception):# only if the view raised an exceptionpasscs - process_request(self, request) : Request 처리
- process_view(self, request, view_function, view_args, view_kwargs) : view 처리
- process_response(self, request, response) : Response 처리
- process_template_response(self, response) : Response가 rendor()를 포함하면 처리
- process_exception(self, request, exception) : view에서 발생한 Exception 처리
20. 기본 sessions 사용방법(DB)
- settings.py의 MIDDLEWARE_CLASSES에
'django.contrib.sessions.middleware.SessionMiddleware' 추가
- django-admin startproject로 프로젝트 생성시 Default로 설정되어있다.
- Default 설정은 프로젝트에서 사용하는 Database를 사용하는데, settings.py의 INSTALLED_APPS에 'django_contrib.sessions'를 추가해야 한다.
- manage.py migrate를 실행하여 session 데이터를 저장할 테이블을 생성한다.
21. 다른 방법을 사용하는 session
1) cache
- SESSION_ENGINE에 'django.contrib.sessions.backends.cache'을 설정
(cache가 가득차거나 cache server가 재부팅중에는 저장되지 않는다.)
- SESSION_ENGINE에 'django.contrib.sessions.backends.cached_db'을 설정
2) file
- SESSION_ENGINE에 'django.contrib.sessions.backends.file'을 설정
(SESSION_FILE_PATH를 설정하여야 하는데 Default 파일경로는 tempfile.gettempdir()를 통해 얻어진다. 보통 /tmp)
3) cookie
- SESSION_ENGINE에 'django.contrib.sessions.backends.signed_cookies'을 설정
(SECRET_KEY에 저장이 되며 보안이 취약할 경우 PickleSerializer를 사용하여야한다.)
4) view (SessionMiddleware가 구동중일때)
- HttpRequest를 읽어서 request.session을 작성할 수 있다.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859class backends.base.SessionBase#This is the base class for all session objects. It has the following standard dictionary methods:__getitem__(key)# Example: fav_color = request.session['fav_color']__setitem__(key, value)# Example: request.session['fav_color'] = 'blue'__delitem__(key)# Example: del request.session['fav_color'].# This raises KeyError if the given key isn’t already in the session.__contains__(key)# Example: 'fav_color' in request.sessionget(key, default=None)# Example: fav_color = request.session.get('fav_color', 'red')pop(key, default=__not_given)# Example: fav_color = request.session.pop('fav_color', 'blue')keys() items() setdefault() clear()# It also has these methods:flush()# Deletes the current session data from the session and deletes the session cookie.# This is used if you want to ensure that the previous session data can’t be accessed again from the user’s browser# (for example, the django.contrib.auth.logout() function calls it).set_test_cookie()# Sets a test cookie to determine whether the user’s browser supports cookies.# Due to the way cookies work, you won’t be able to test this until the user’s next page request.# See Setting test cookies below for more information.test_cookie_worked()# Returns either True or False, depending on whether the user’s browser accepted the test cookie.# Due to the way cookies work, you’ll have to call set_test_cookie() on a previous, separate page request.# See Setting test cookies below for more information.delete_test_cookie()# Deletes the test cookie. Use this to clean up after yourself.set_expiry(value)# Sets the expiration time for the session. You can pass a number of different values:# •If value is an integer, the session will expire after that many seconds of inactivity.# For example, calling request.session.set_expiry(300) would make the session expire in 5 minutes.# •If value is a datetime or timedelta object, the session will expire at that specific date/time.# Note that datetime and timedelta values are only serializable if you are using the PickleSerializer.# •If value is 0, the user’s session cookie will expire when the user’s Web browser is closed.# •If value is None, the session reverts to using the global session expiry policy.# Reading a session is not considered activity for expiration purposes. Session expiration is computed from# the last time the session was modified.get_expiry_age()# Returns the number of seconds until this session expires.# For sessions with no custom expiration (or those set to expire at browser close), this will equal SESSION_COOKIE_AGE.# This function accepts two optional keyword arguments:# •modification: last modification of the session, as a datetime object. Defaults to the current time.# •expiry: expiry information for the session, as a datetime object, an int (in seconds), or None.# Defaults to the value stored in the session by set_expiry(), if there is one, or None.get_expiry_date()# Returns the date this session will expire. For sessions with no custom expiration# (or those set to expire at browser close), this will equal the date SESSION_COOKIE_AGE seconds from now.# This function accepts the same keyword arguments as get_expiry_age().get_expire_at_browser_close()# Returns either True or False, depending on whether the user’s session cookie will expire when the user’s Web browser is closed.clear_expired()# Removes expired sessions from the session store. This class method is called by clearsessions.cycle_key()# Creates a new session key while retaining the current session data.# django.contrib.auth. login() calls this method to mitigate against session fixation.cs 22. session 예제
1234567def post_comment(request, new_comment):if request.session.get('has_commented', False):return HttpResponse("You've already commented.")c = comments.Comment(comment=new_comment)c.save()request.session['has_commented'] = Truereturn HttpResponse('Thanks for your comment!')cs 1234567def login(request):m = Member.objects.get(username=request.POST['username'])if m.password == request.POST['password']:request.session['member_id'] = m.idreturn HttpResponse("You're logged in.")else:return HttpResponse("Your username and password didn't match.")cs 123456def logout(request):try:del request.session['member_id']except KeyError:passreturn HttpResponse("You're logged out.")cs - session은 JSON(dict) 타입이 기본
- class serializers.JSONSerializer 또는 class serializers.PickleSerializer 로 제어
- session안에 저장되어 있는 값들을 확인하고 처리
23. session Cookies 설정
1234567891011from django.http import HttpResponsefrom django.shortcuts import renderdef login(request):if request.method == 'POST':if request.session.test_cookie_worked():request.session.delete_test_cookie()return HttpResponse("You're logged in.")else:return HttpResponse("Please enable cookies and try again.")request.session.set_test_cookie()return render(request, 'foo/login_form.html')cs - session.test_cookie_worked()를 사용하여 현재 사용되고 있는지 확인
- session.delete_test_cookie()를 사용하여 현재 session 정보를 삭제
- set_test_cookie()를 사용하여 session 재설정
24. views의 외부에서 제어
1234567891011121314>>> from importlib import import_module>>> from django.conf import settings>>> SessionStore = import_module(settings.SESSION_ENGINE).SessionStore>>> from django.contrib.sessions.backends.db import SessionStore>>> s = SessionStore()>>> # stored as seconds since epoch since datetimes are not serializable in JSON.>>> s['last_login'] = 1376587691>>> s.create()>>> s.session_key'2b1189a188b44ad18c35e113ac6ceead'>>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead')>>> s['last_login']1376587691cs - SessionStore를 통해 settings에 설정되어 있는 SESSION_ENGINE를 저장
- SessionStore.create()를 사용하여 새로운 session을 생성
- 새로운 session에서 session_key를 확인
25. django.contrib.sessions.backends.db를 사용한 session
12345678>>> from django.contrib.sessions.models import Session>>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead')>>> s.expire_datedatetime.datetime(2005, 8, 20, 13, 35, 12)>>> s.session_data 'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...'>>> s.get_decoded(){'user_id': 42}cs - django.contrib.sessions.models의 Session을 통해 DB에 저장된 session 제어 가능
- session_data를 확인하고 get_decoded()로 복호화 가능
26. database-backed session 사용예제
1234567891011121314151617181920212223from django.contrib.sessions.backends.db import SessionStore as DBStorefrom django.contrib.sessions.base_session import AbstractBaseSessionfrom django.db import modelsclass CustomSession(AbstractBaseSession):account_id = models.IntegerField(null=True, db_index=True)@classmethoddef get_session_store_class(cls):return SessionStoreclass SessionStore(DBStore):@classmethoddef get_model_class(cls):return CustomSessiondef create_model_instance(self, data):obj = super().create_model_instance(data)try:account_id = int(data.get('_auth_user_id'))except (ValueError, TypeError):account_id = Noneobj.account_id = account_idreturn objcs 123class SessionStore(CachedDBStore):cache_key_prefix = 'mysessions.custom_cached_db_backend'# ...cs 'Flower in my dev > Django' 카테고리의 다른 글
<DJANGO>[MODEL] (0) 2017.05.07 <DJANGO>[rest_framework & Class based view] (0) 2017.05.01 <DJANGO>[rest_framework & Func based view] (0) 2017.04.12 <DJANGO>[Hello World] (0) 2017.03.05 <DJANGO>[pyenv] 사용하기 (0) 2017.03.05