쿠키(Cookie)





Http는 stateless라는 특성을 가지고 있다.

즉, 상태가 유지 되지 않는다는 것인데, 우리가 흔히 사용하는 서비스에서 로그인 기능은

사용자의 상태를 저장하며, 이에 따라 표시하는 웹 페이지의 컨텐츠가 다르다.


그렇다면 상태를 보존하기 위해서 특정 기법을 사용한다는 것인데,

그 중 하나가 쿠키이다.


쿠키란, 인터넷 사용자가 어떠한 웹 사이트를 방문할 경우 그 사이트가 사용하고 있는 서버를 통해

인터넷 사용자의 컴퓨터에 설치 되는 작은 기록 정보 파일을 일컫는다.

'쿠키'라는 이름의 어원은 동화인 '헨젤과 그레텔'에서 파생된 것이다.

이 동화에서는 지나온 길을 찾기 위해 주인공들이 쿠키 조각을 떨어뜨린다.

이처럼 쿠키를 통해 이전 상태를 파악할수 있도록 하는것이다.


다만 쿠키의 단점이라면, 보안상으로 상당히/굉장히/너무나 취약하다는 것이다.

이유는 사용자의 정보가 담긴 데이터를 서버와 클라이언트에서 주고 받기때문에

중간에 해커가 이 정보를 탈취하기라도 하면 큰일이기 때문이다.


따라서 실제로는 세션을 많이 사용하지만 우선 쿠키에 대한 예제 부터 살펴보도록하자.





카운터 예제


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var express = require('express');
var app = express();
 
// 쿠키 기능을 위한 미들 웨어, npm  install로 설치 해야함.
var cookieParser = require('cookie-parser')
 
app.use(cookieParser());
 
// count 라는 쿠키를 저장하고 있다가 count경로로 접근할 때마다 1씩 증가
app.get('/count',function(req, res){
    // 쿠키가 없다면 초기화 있다면 쿠키값을 받아옴
    if(req.cookies.count){
        var count = parseInt(req.cookies.count);
    }else{
        var count = 0;
    }
    
    res.cookie('count',count+1);
    res.send('count: ' + req.cookies.count);
})
 
app.listen('3000'function(){
    console.log('server start on port 3000');
});
cs


예제를 통해 살펴보도록하자.

위의 코드는 쿠키값을 1씩 증가시키며 화면에 출력하는 예제이다.


우선 node js에서는 cookie-parser라는 미들웨어로 쿠키 확인한다.

app.use로 import 된 cookie-parser를 사용한다고 지정해 준다.


해당 미들웨어에서 쿠키는 res내부 cookie라는 메소드로 지정할 수 있다.

첫번째 인자로 쿠키의 이름을 받고 두번째로 값을 받는다.

또한 쿠키의 값은 req.cookies 객체 내부의 값으로 전달된다.

사용자는 이를 호출하여 사용이 가능하다.


따라서 우선 if 문으로 req.cookie.count 값이 있는지 판별한다.

만약 쿠키 값이 있으면 count 변수에 쿠키 값을 넣고, 없으면 0을 넣는다.


그리고 현재의 쿠키값을, 이전의 쿠키값+1로 수정하고,

브라우저에 현재 쿠키값을 전달한다.


이를 실행하면 새로고침 할 때 마다 표시되는 값이 1씩 증가함을 볼 수 있다.



참고 : 생활코딩, 서버사이드 node js

저작자 표시
신고

express generator 사용으로 간편한 개발 환경 구축




express를 사용하다보면 맨땅에 헤딩하는 식으로 처음부터 모든 모듈을 import하고,

디렉토리를 생성한다.

이러한 시간 낭비를 줄이기 위하여 express generator를 사용해보자



1
2
sudo npm install -g express
sudo npm install -g express-generator
cs


우선 위의 명령어로 express와 express-generator를 설치한다.

설치를 완료하고 express -h 명령어를 입력하면 프로젝트를 시작하는데 사용할 수 있는 명령어가 표시된다.

일종의 help라고 생각하면 된다.


이제 node 개발환경을 세팅하기 위해 터미널에

express --ejs --css sass --git 명령어를 입력하면 디렉토리와 파일이 자동으로 생성된다.

위의 명령어는 기본 템플릿이 jade이기 때문에 변경해 준것이고, sass를 사용한다는 의미이다.

명령어는 자신에게 편한 대로 설정하여 사용하면 된다.





다음과 같이 폴더 및 파일이 생성된다.


저작자 표시
신고

 vanilla JS로 장고 CSRF Ajax 요청




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function parse_cookies() {
    var cookies = {};
    if (document.cookie && document.cookie !== '') {
        document.cookie.split(';').forEach(function (c) {
            var m = c.trim().match(/(\w+)=(.*)/);
            if(m !== undefined) {
                cookies[m[1]] = decodeURIComponent(m[2]);
            }
        });
    }
    return cookies;
}
var cookies = parse_cookies();
 
 
//
// SEND THE FORM!
//
var request = new XMLHttpRequest();
request.setRequestHeader('X-CSRFToken', cookies['csrftoken']); 
request.open("POST""/path/to/view/");
var formElement = document.querySelector("#myform");
request.send(new FormData(formElement));
cs


장고로 Ajax 요청을 보내면 CSRF 토큰에 대한 이슈가 있다.

이를 해결하기 위해 공식 홈페이지에서는 토큰을 첨부하는 JQuery 코드를 제공주는데,

바닐라 JS는 코드가 없어서 한참 헤멘 끝에 구글에서 예제코드를 찾을수 있었따.

JQuery를 사용하지 않고 vanilla JS로 사용할 경우 Ajax 함수 세팅에서 위와 같은 코드를 추가해 주면 된다.



출처 : http://musings.tinbrain.net/blog/2015/aug/28/vanilla-js-meets-djangos-csrf/

저작자 표시
신고

겨울 방학에 달에 다녀온 상근이는 여름 방학 때는 화성에 갔다 올 예정이다. (3996번) 화성에서는 지구와는 조금 다른 연산자 @, %, #을 사용한다. @는 3을 곱하고, %는 5를 더하며, #는 7을 빼는 연산자이다. 따라서, 화성에서는 수학 식의 가장 앞에 수가 하나 있고, 그 다음에는 연산자가 있다.


풀이


라인 단위로 받아 배열에 split 해주고,

순환하면서 문자열을 판별하여 미리 설정된 연산을 진행하면 된다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.util.Scanner;
 
/**
 * Created by homr on 2017. 6. 30..
 */
public class Main {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        String[] testCase = sc.nextLine().split("");
        int T = Integer.parseInt(testCase[0]);
 
        while(T!=0){
            String[] str = sc.nextLine().split(" ");
 
            double num = Double.parseDouble(str[0]);
 
            for(int i=1; i<str.length; i++){
                if(str[i].equals("@")){
                    num *= 3;
                }else if(str[i].equals("%")){
                    num += 5;
                }else{
                    num -= 7;
                }
            }
 
            System.out.printf("%.2f\n", num);
            T--;
        }
    }
}
cs


저작자 표시
신고

sns - 사용자 등록 구현



지금까지 만든 sns 서비스는 아직 회원가입 폼이 없다.

회원가입 역시 모델을 생성하지 않아도 된다.




1
2
3
4
urlpatterns = [
  url(r'^accounts/signup$', kilogram_views.CreateUserView.as_view(), name = 'signup'),
  url(r'^accounts/login/done$', kilogram_views.ResisteredView.as_view(), name = 'create_user_done')
]
cs


우선 url을 수정해야한다.

왜냐하면 사용자 등록 관련된 url이 없기 때문이다.

urls.py에 signup과 login/done을 추가한다.

이 두가지 url의 클래스는 각각 CreateUserView와 ResisteredView가 된다.





1
2
3
4
5
6
7
8
9
10
11
from django.views.generic.edit import CreateView
from django.contrib.auth.forms import UserCreationForm
from django.core.urlresolvers import reverse_lazy
 
class CreateUserView(CreateView):
    template_name = 'registration/signup.html'
    form_class = UserCreationForm
    success_url = reverse_lazy('create_user_done')
 
class RegisteredView(TemplateView):
    template_name = 'registration/signup_done.html'
cs

이 두 뷰는 아직 views안에 생성되지 않았으므로 구현해야한다.

위 코드 상단의 from django.views.generic.edit import CreateView는 객체를 생성하는 뷰이다.

즉, 폼이나 모델과 연결해서 새로운 데이터를 넣을때 CreateView를 사용한다.


그리고 기본적인 회원가입 폼으로 UserCreationForm 이라는 것이 있다.

그러나 아쉽게도 유저의 아이디와 패스워드만 확인하고 이메일은 확인하지 않는다.

따라서 우리는 이 기본 회원가입 폼에 이메일을 추가하여 사용한다.


먼저, CreateUserView는 CreateView를 상속받아 구현한다.

template_name은 'registaration/signup.html'으로 설정하면서 signup.html과 연결한다.


또한 form_class로 UserCreationView로 넣고,

로그인이 성공하면 이동할 url을 success_url에 넣어준다.

여기서 reverse_lazy를 사용하는 이유는 generic view의 경우, 

로딩 문제때문에 reverse_lazy를 사용해야한다고 공식문서에 명시되어있다.


그 다음으로 TemplateView를 상속받는 RegisteredView 클래스를 만들어준다.

그리고 template_name 을 'registaration/signup_done.html'으로 설정해서 연결한다.


이렇게 view 설정이 완료되었고 이제 템플릿 수정만 남았다.





1
2
<br>
<p>아이디가 없으신가요? <a href="{% url 'signup'%}">회원가입</a></p>
cs


우선 login.html 에 다음과 같은 코드를 추가한다.

로그인 폼 밑에 회원가입을 유도하는 텍스트이다.

만약 회원가입을  누르게 된다면 회원 가입 페이지로 넘어가게 된다.


아직은 registration의 signup.html 템플릿이 없으므로 에러가 발생한다.





1
2
3
4
5
6
7
8
9
10
{% extends 'kilogram/base.html' %}
{% block content %}
 
<form method="post" action="{% url 'signup' %}">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">회원가입</button>
</form>
 
{% endblock %}
cs


우선 다음과 같이 signup.html을 만든다.

버튼을 클릭하면 signup url로 post 요청을 보내게 된다.

현재는 UserCreationForm을 넣었으므로 장고에서 제공해주는 폼이 출력된다.





1
2
3
4
5
6
7
8
{% extends 'kilogram/base.html' %}
{% block content %}
 
<h2>회원가입이 완료되었습니다. </h2>
<br>
<a href="{% url 'login'%}">로그인하기</a>
 
{% endblock %}
cs


또한 회원가입이 완료 되었을 때 페이지를 출력한다.

템플릿의 이름은 signup_done.html이며,

회원가입이 정상적으로 완료됨을 알리는 동시에, 로그인하기 링크를 제공한다.





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django import forms
 
class CreateUserForm(UserCreationForm):
    email = forms.EmailField(required=True)
 
    class Meta:
        model = User
        fields = ("username""email""password1""password2")
 
    def save(self, commit=True):
        user = super(CreateUserForm, self).save(commit=False)
        user.email = self.cleaned_data["email"]
        if commit:
            user.save()
        return user
cs


좀 더 나아가서 이메일 필드를 추가해 보도록하자.

UserCreationForm을 수정할 것이기 때문에, CreateUserForm이라는 클래스가 상속받게 한다.

그리고 내부에 email 필드를 추가하고, 모델은 User와 연결하며,

필드는 username과 email, password1, password2를 연결한다.


그리고 저장을 위한 메소드는 save를 오버라이딩 해주는데, 

super 키워드로 부모클래스의 메소드를 호출하고 저장을 한다.

왜냐하면 아직 email을 추가하지 않았기 때문이다.

commit False에서 commit save를 하는 이유는 중복 저장을 막기 위함이다.





1
2
3
4
5
6
7
8
9
10
11
12
13
14
from django.views.generic.edit import CreateView
# from django.contrib.auth.forms import UserCreationForm
from django.core.urlresolvers import reverse_lazy
 
from .forms import CreateUserForm
 
class CreateUserView(CreateView):
    template_name = 'registration/signup.html'
    form_class =  CreateUserForm
    # form_class = UserCreationForm
    success_url = reverse_lazy('create_user_done')
 
class RegisteredView(TemplateView):
    template_name = 'registration/signup_done.html'
cs


이렇게 변경된 폼을 적용하기 위해서 views 도 수정해 줘야한다.

.forms의 CreateUserForm을 추가해준 후 CreateUserView의 form_class를 변경해준다.




출처 : 인프런, 파이썬 웹 프로그래밍, Django로 웹 서비스 개발하기

저작자 표시
신고

sns - 로그인과 로그아웃 구현하기



지난시간에 이어 로그인과 인증 관련 기능을 구현해보자

장고는 기본적으로 인증 기능을 가지고 있다.

django.contrib.auth.modelsuser라는 클래스에서 기능을 가지고 있으므로

모델을 만들어 줄 필요는 없다.

뷰도 마찬가지로 이미 구현이 되어있으므로 템플릿만 수정 하면 된다.





1
2
3
4
5
6
7
8
9
<ul class="nav navbar-nav navbar-right">
  {% if user.is_active %}
  <li><a href="{%url 'login' %}"> <span class="glyphicon glyphicon-heart"></span> {{user.username}}</a></li>
  <li><a href="{% url 'logout' %}">Logout</a></li>
  {% else %}
  <li><a href="{%url 'login' %}"> <span class="glyphicon glyphicon-user"></span> Login</a></li>
  <li><a href="{% url 'admin:index' %}">Admin</a></li>
  {% endif %}
</ul>
cs


원래 있던 base.html 템플릿을 수정하자.

여기서 조건문을 사용하여 로그인 여부에 따라서 네비게이션 바가 다르게 보이도록한다.

if user.is_active는 유저의 로그인 상태가 액티브인지 판별하고,

만약 그렇다면 네이게이션 바는 유저의 이름과 로그 아웃 버튼을 출력한다.


만약 로그인 하지 않았으면, 로그인 단추와 관리자 페이지로 이동하는 버튼을 출력한다.





1
2
3
$ python manage.py shell
>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('cow''cow@mooow.com''1q841q84')
cs


아직 가입 폼이 만들어지지 않았으므로 사용자 아이디 생성은 shell 환경에서 진행하도록 하자

우선 django.contrib.auth.models를 추가하고 User.objects.create_user 명령어로 생성한다.


admin 페이지에서 user을 확인해 보면 아이디가 생성됨을 확인할 수 있지만

네비게이션 바의 login을 누르면 에러가 발생한다.

에러는 registration/login.html이 아직 없다는 내용이다.

로그인 뷰는 있는데, 이 로그인 뷰의 템플릿이 없기때문에 발생하는 에러이다.





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{% extends 'kilogram/base.html' %}
{% block content %}
 
{% if user.is_active %}
<h2> Welcome, {{user.username}} </h2>
<a href="{% url 'logout' %}">로그아웃</a>
 
{% else %}
{% if form.errors %}
<p>ID나 비밀번호가 일치하지 않습니다.</p>
{% endif %}
 
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<input type="hidden" name="next" value="" />
{{ form.as_p }}
<button type="submit">로그인</button>
</form>
 
{% endif %}
 
{% endblock %}
cs


그렇다면 로그인 템플릿을 만들어 보도록하자.

Templates 아래에 registration 폴더를 만들고, login.html 파일을 생성한다.

소스 코드는 위와 같다.


base.html의 네비게이션 바를 확장하여 사용하고 blockcententendblock 안에 내용이 들어간다.

이 또한 로그인 했을 때와 하지 않았을 때로 나뉘며 로그인 했을 때는 간단한 인사와 로그아웃 버튼이,

하지 않았을 때는 아이디와 패스워드 입력 폼이 나온다.


입력 폼의 submit을 클릭하면 login으로 post 요청을 준다.

그리고 로그인의 에러가 발생하면 'ID나 비밀번호가 일치하지 않습니다'라는 텍스트를 출력한다.





1
2
# Auth settings
LOGIN_REDIRECT_URL = '/kilogram/'
cs

만약 로그인이 성공하면 account의 profile 페이지로 넘어가는데,

이를 변경하기위해서는 settings.py를 수정해야한다.


여기서 LOGIN_REDIRECT_URL을 로그인 후 연결될 url로 바꾸어준다.

이로써 로그인 리다이렉션이 완료된다.





1
2
3
4
5
6
7
8
{% extends 'kilogram/base.html' %}
{% block content %}
 
<h2> 잘 가요, 안녕. </h2>
<p><a href="{%url 'login'%}">다시 로그인하기</a></p>
 
{% endblock %}
 
cs


그리고 로그아웃을 클릭하면 장고 관리자페이지의 로그아웃 화면이나온다.

이렇게 되는 이유는 아직 로그아웃의 템플릿 파일이 없기 때문이다.

이 또한 파일명이 정해져 있는데, registrationlogged_out.html이다.


이렇게 미리 정해진 파일명은 장고 공식 문서나 소스 내부에서 확인이 가능하다.




출처 : 인프런, 파이썬 웹 프로그래밍, Django로 웹 서비스 개발하기

저작자 표시
신고

 sns - 앱 초기화




다시 새로운 어플리케이션을 만들어보자.

이번에는 sns를 구현하면서 로그인/로그아웃 기능을 중점적으로 다루어볼 것이다.

또한 이미지 업로드 기능도 사용해 보도록하자.





먼저 새로운 프로젝트를 만들기 위해서

$django-admin startproject mysite를 콘솔창에 입력해주자


다음으로 어플리케이션을 만들어야하는데

$python manage.py startapp kilogram을 입력한다.

이렇게 만들어진 어플리케이션은 settings.py에 어플 이름으로 등록한다.







또한 LANGUAGE_CODE='ko-kr',  TIMEZONE = 'Asia/Seoul'을 변경해주고

정적 파일 사용을 위해 STATIC_ROOT = os.path.join(BASE_DIR,'stiatic')을 추가한다.


작업이 끝났으면 관리자 페이지의 관리자 계정을 만들어준다.

$python manage.py createsuperuser 명령어를 콘솔창에 입력하면 된다.





1
2
3
4
5
6
7
8
9
from django.conf.urls import url
from django.contrib import admin
from . import views
 
app_name ='kilogram'
 
urlpatterns = [
    url(r'^$', views.IndexView.as_view(), name = 'index'),
]
cs


이번에는 url을 include 방식으로 적용해볼것이다.

따라서 kilogram 디렉토리 안에 urls.py를 생성한다.


상단에 app_name을 지정하면 다른 어플리케이션과 충돌하지 않는 네임스페이스가 생성된다.

그리고 url에 기존방식과 다르게 views.IndexView.as_view()가 사용되었는데,

이는 views 내부로 접근할 때 함수가 아니라 클래스로 접근한다는 뜻이다.

따라서 function_based view가 아니라 generic view로 접근한다.





1
2
3
4
5
6
7
8
9
from django.conf.urls import url, include
from django.contrib import admin
from kilogram import views as kilogram_views
 
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', kilogram_views.IndexView.as_view(), name = 'root'),
    url(r'^kilogram/', include('kilogram.urls')),
]
cs


마찬가지로 이 경로에 접근하기 위해서 mysite의 url도 지정 해줘야한다.

kilogram으로 접근했을 때 kilogram.urls 파일로 연결시켜주며 이를 위해서 include 함수가 사용된다.

include 함수를 사용하기 위해서는 반드시 from django.conf.urls import include의 명시가 필요하다.


그리고 일반적인 localhost:8000번으로 접근했을때도 kilogram 앱으로 연결시켜주기 위해서 url을 추가한다.

이를 위해서 kilogram의 views를 추가해야하는데 다른 어플리케이션과의 충돌을 피하기 위해 

as 키워드로 kilogram_views라는 별칭을 만든다.





1
2
3
4
5
from django.shortcuts import render, redirect
from django.views.generic.base import TemplateView
 
class IndexView(TemplateView):
    template_name = 'kilogram/index.html'
cs


url이 다 수정되었으므로 views를 수정해야한다.

generic view로 설정했으므로 IndexView라는 클래스를 만든다.

이 클래스는 템플릿을 그냥 그대로 보여주는 기능만 하기 때문에 

from django.views.generic.base import TemplateView를 추가하여 상속받아 사용한다.


그리고 template_name을 지정해주면 해당 템플릿이 출력된다.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
  <title>Kilogram</title>
 
  <!-- Bootstrap -->
  <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
 
  {% load static %}
  <link rel="stylesheet" type="text/css" href="{% static 'kilogram/style.css' %}" />
 
  <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
  <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
  <!--[if lt IE 9]>
  <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
  <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
  <![endif]-->
</head>
<body>
  <nav class="navbar navbar-default navbar-static-top">
  <div class="container-fluid">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="{% url 'kilogram:index' %}"> <span class="glyphicon glyphicon-camera"> </span> Kilogram </a>
    </div>
    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse">
      <ul class="nav navbar-nav navbar-right">
        <li><a href="#"> <span class="glyphicon glyphicon-user"></span> Login</a></li>
        <li><a href="#">Logout</a></li>
        <li><a href="{% url 'admin:index' %}">Admin</a></li>
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>
  <div class="container">
    <div>
      {% block content %}
      {% endblock %}
    </div>
  </div>
  <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
  <!-- Include all compiled plugins (below), or include individual files as needed -->
  <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
cs


템플릿은 항상 해당 앱 내부에 templates/앱 이름/ 아래 넣어줘야한다.

이 앱에서는 templates/kilogram/~~~.html을 넣어주면 된다.


우선 모든 페이지의 base가 되는 base.html을 생성해주자.

base.html을 위의 네비게이션 바를 만드는 것이고,

이것을 베이스로 모든 템플릿을 생성할 것이다.





1
2
3
4
5
6
{% extends 'kilogram/base.html' %}
{% block content %}
 
<h1>Kilogram Main Page</h1>
 
{% endblock %}
cs


따라서 base.html을 extends하여 만든 index.html은

위와 같이 간단하게 만들어 질 수 있다.




출처 : 인프런, 파이썬 웹 프로그래밍, Django로 웹 서비스 개발하기


저작자 표시
신고

'WEB > Django' 카테고리의 다른 글

[Django] sns - 사용자 등록 구현  (0) 2017.06.30
[Django] sns - 로그인과 로그아웃 구현하기  (0) 2017.06.30
[Django] sns - 앱 초기화  (0) 2017.06.29
[Django] lotto - 앱 다듬기  (0) 2017.06.28
[Django] lotto - POST 처리  (0) 2017.06.28
[Django] lotto - form 만들기  (0) 2017.06.28

lotto - 앱 다듬기



1
url(r'^lotto/(?P<lottokey>[0-9]+)/detail/$', views.detail, name = "lotto_detail"),
cs


전반적인 과정을 끝이났고 추가적인 기능을 구현해보자.

우선 디테일 페이지를 구현하기 위해 urls.py를 수정한다.

위의 코드는 숫자로 구별해서 디테일 페이지와 연결하는 것이다.


이 숫자를 파라미터로 전달하기 위해서는

(?P<변수이름>전달할값)과 같은 문법을 사용한다.





1
2
3
def detail(request, lottokey):
    lotto = GuessNumbers.objects.get(pk = lottokey)
    return render(request, "lotto/detail.html", {"lotto": lotto})
cs


따라서 이 url과 연결하기 위한 view의 detail 함수를 만들어 준다.

url에서 전달 받은 값은 2번째 인자에서 부터 넣어줄 수 있다.

이렇게 받은 키값은 primary key이므로 GuessNumbers의 많은 인스턴스들로 부터

해당 primary key의 값만 추출하여 lotto에 저장할 수 있다.

이렇게 받은 값을 detail.html로 전달해 주자




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
{% load staticfiles %}
<html lang="ko">
<head>
  <title>My Little Lotto</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
  <link href="//fonts.googleapis.com/css?family=Space+Mono" rel="stylesheet">
  <link rel="stylesheet" href="{% static 'css/lotto.css'%}">
</head>
 
<body>
  <div class="page-header">
  <h1>My Lotto Page</h1>
  </div>
  <div class="container lotto">
    <h2>{{lotto.text}}</h2>
    <p> by {{lotto.name}}</p>
    <p> {{lotto.update_date}}</p>
    <p> {{lotto.lottos|linebreaksbr}}</p>
  </div>
</body>
</html>
cs


다음으로 detail.html을 추가해 준다.






1
2
3
4
5
6
<div class="page-header">
<h1>My Lotto Page
  <a href="{% url 'new_lotto' %}"><span class="glyphicon glyphicon-plus btn btn-default"></span></a></h1>
</div>
 
<h2><a href="{% url 'lotto_detail' lottokey=lotto.pk %}">{{lotto.text}}</a></h2>
cs


그리고 추가한 default.html을 수정한다.

먼저 로또를 추가할 수 있는 new_lotto 링크 버튼을 추가한 한다.


그리고 해당 로또 값을 클릭하면 'detail'이라는 이름을 가진 url값으로 넘어가고

lottokey라는 lotto.pk도 함께 전달한다.




출처 : 인프런, 파이썬 웹 프로그래밍, Django로 웹 서비스 개발하기


저작자 표시
신고

'WEB > Django' 카테고리의 다른 글

[Django] sns - 로그인과 로그아웃 구현하기  (0) 2017.06.30
[Django] sns - 앱 초기화  (0) 2017.06.29
[Django] lotto - 앱 다듬기  (0) 2017.06.28
[Django] lotto - POST 처리  (0) 2017.06.28
[Django] lotto - form 만들기  (0) 2017.06.28
[Django] lotto - MTV 연동하기  (0) 2017.06.28

lotto - POST 처리




지난 시간에 폼을 만들었는데, submit를 클릭해도 데이터가 처리되지않았다.

이유는 views/post에 있다.

왜냐하면 같은 url을 모두 lotto/form.html으로 랜딩하게 되어있기 때문이다.

만약 get으로 접근했다면 이와 같은 처리가 맞지만 post는 다르게 처리해야한다.





1
2
3
4
5
6
7
8
9
10
11
from django.shortcuts import render, redirect
def post(request):
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            lotto = form.save(commit = False)
            lotto.generate()
            return redirect('index')
    else:
        form = PostForm()
        return render(request, "lotto/form.html",{"form": form})
cs


따라서 이를 판별해야한다.

post 내부 함수는 default가 get으로 동작하기 때문에

if 조건문을 이용하여 post로 접근했는지 확인 해야한다.

이를 위해서 request.method를 사용한다. 만약 post로 접근했다면 'post'가된다.

'get'으로 접근했다면 기존의 코드를 그대로 적어준다.


post를 판별했으면 form으로 받은 데이터를 처리해야한다.

PostForm(request.POST)으로 폼 데이터를 가져올수 있는데 이 데이터가 정상적이지 않을수 있으므로

if form.is_valid()로 다시 한번 확인을 거쳐야한다.


만약 제대로 데이터가 들어왔다면 lotto안에 form의 데이터를 가져오는데

commit=False 인자로 데이터 베이스에는 저장하지 않는다.

왜냐하면 generate()를 호출해서 저장하기를 원하기 때문이다.


모든 작업이 완료되었으면 index url로 redirect 시킨다.

redirect의 인자는 url을 하드코딩 하는것이 아니라 url name을 그대로 입력해주면 된다.

redirect도 render와 마찬가지로 from django.shortcuts 안에 있으므로 추가시켜준다.




출처 : 인프런, 파이썬 웹 프로그래밍, Django로 웹 서비스 개발하기

저작자 표시
신고

'WEB > Django' 카테고리의 다른 글

[Django] sns - 앱 초기화  (0) 2017.06.29
[Django] lotto - 앱 다듬기  (0) 2017.06.28
[Django] lotto - POST 처리  (0) 2017.06.28
[Django] lotto - form 만들기  (0) 2017.06.28
[Django] lotto - MTV 연동하기  (0) 2017.06.28
[Django] lotto - shell을 이용한 장고 관리  (0) 2017.06.28

lotto - form 만들기



어느정도 앱이 윤곽을 보이고 있지만 아직 데이터를 입력받는 폼이 없다.

관리자 페이지에서 일일이 데이터를 입력할수도 없기 때문에

폼 양식을 작성하여 웹 페이지에 출력해야한다.




1
2
3
4
5
6
7
8
from django import forms
from .models import GuessNumbers
 
class PostForm(forms.ModelForm):
 
    class Meta:
        model = GuessNumbers
        fields = ('name''text',)
cs


장고에서 폼 양식을 만드는 법은 아주 간단하다.

먼저, lotto 안에 forms.py를 만들어준다.


여기에 장고가 제공해주는 기본 폼인 from django import forms를 추가한다.

또한 데이터베이스 입력을 위하여 from .models import GuessNumbers도 추가해준다.


또한 폼을 위한 class PostForm을 만드는데, 이는 forms.ModelForm을 상속받는다.

이 안에 class Meta를 선언하고 다시 Meta 클래스 안에 model 이라는 변수를 선언하는데,

어떤 모델을 사용할 것인지를 지정하는 것이다.

우리는 사용할 모델로 GuessNumbers를 넣는다.


또한 fields는 어떤 필드를 입력받을것인가를 지정하는것이므로

name과 text만 입력해 주도록하자.

나머지는 자동 생성 될 것이다.





1
url(r'^lotto/new$', views.post, name = "new_lotto"),
cs


작업이 완료되었으면 urls.py를 수정해야한다.

위와 같은 코드를 추가 하는데, view에 post 메소드로 접근하라는 뜻이다.

이 url의 이름은 new_lotto가 된다.


따라서 현재까지의 작업이 완료되고, 서버에 접근하면 에러가 나는데,

views에 post가 없기 때문이다.




1
2
3
4
5
import .forms import PostForm
 
def post(request):
    form = PostForm()
    return render(request, "lotto/form.html",{"form": form})
cs


그러므로 views에 post를 추가해주자.

post 메소드는 앞서 만든 form 데이터를 불러와서 lotto/form.html 템플릿에 전달하게 된다.

그렇다면 당연히 템플릿은 이를 받아 랜더링 해야한다.





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html> {% load staticfiles %}
<html lang="ko">
 <head>
  <title>My Little Lotto</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
  <link href="//fonts.googleapis.com/css?family=Space+Mono" rel="stylesheet">
  <link rel="stylesheet" href="{% static 'css/lotto.css' %}"> 
 </head>
 <body>
  <div class="page-header">
   <h1>My Little New Lotto</h1>
  </div>
  <div class="container lotto">
   <form method="POST" class="post-form"> {%csrf_token%} {{form.as_p}} <button type="submit" class="save btn btn-default">Save</button> </form>
  </div>
 </body>
</html>
cs


위의 코드로 lotto/form.html을 만들어 준다.

여기서 {%csrf_token%}이란 보안을 위해 form 태그안에 꼭 작성해줘야하는 키워드이다.

그리고 생성한 폼을 추가하기 위하여 {{form.as_p}}를 넣는다.

추가적으로 submit 버튼을 추가함으로써 폼 추가도 완료되었다.



출처 : 인프런, 파이썬 웹 프로그래밍, Django로 웹 서비스 개발하기


저작자 표시
신고

'WEB > Django' 카테고리의 다른 글

[Django] lotto - 앱 다듬기  (0) 2017.06.28
[Django] lotto - POST 처리  (0) 2017.06.28
[Django] lotto - form 만들기  (0) 2017.06.28
[Django] lotto - MTV 연동하기  (0) 2017.06.28
[Django] lotto - shell을 이용한 장고 관리  (0) 2017.06.28
[Django] lotto - views와 템플릿 연동  (0) 2017.06.28

+ Recent posts

티스토리 툴바