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

lotto - MTV 연동하기




1
2
3
4
5
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', views.index, name='index'),
    url(r'^lotto/$', views.index, name='lotto'),
]
cs


뷰와 템플릿만 연결 했었는데, MTV를 모두 연동해보도록하자

이를 위해서 먼저 url 파일 부터 위와 같이 수정해준다.

이제부터 8000번 포트로 접근해도 로또 앱 페이지가 나온다.





1
2
3
4
from lotto.models import GuessNumbers
def index(request):
    lottos = GuessNumbers.objects.all()
    return render(request, "lotto/default.html", {"lottos": lottos})
cs


다음으로 뷰를 수정해야하는데, 현재는 index 함수 내에 데이터 없이 템플릿만 연결되어있다.

따라서 뷰가 모델의 값을 받아와 템플릿으로 전송해줘야한다.

이를 위해서 Shell 커맨드에서 사용했던 함수를 그대로 사용해주면된다.


우선 GuessNumbers.objects.all()을 이용하여 인스턴스를 모두 불러온다.

이렇게 불러온 데이터는 lottos 안에 저장되며, render 메소드의 3번째 인수로 템플릿에 전달된다.





1
2
3
4
5
6
<div class="container lotto">
  {% for lotto in lottos%}
  <h2>{{lotto.text}}</h2>
  <p> last update: {{lotto.update_date}} by {{lotto.name}}</p>
  <p> {{lotto.lottos|linebreaksbr}}</p>
  {% endfor %}
cs


이제 default.html 값을 수정해줘야 한다.

템플릿에서는 {%%}나 {{}} 를 통해서 파이썬의 문법을 그대로 사용할 수 있다.


일단 우리가 뷰에서 보낸 데이터는 lotto라는 이름으로 전달되었다.

따라서 for 반복문을 통하여 여러개의 로또 결과를 출력한다.

파이썬과 다르게 블럭으로 구분할수 없으므로 for문의 끝은 endfor로 닫아줘야한다.

p태그 안의 linebreaksbr은 자동으로 줄바꿈을 해주는 키워드이다.


이렇게 간단하게 MTV를 연동할 수 있었다.




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


저작자 표시
신고

lotto - shell을 이용한 장고 관리





이번에는 shell을 이용하여 장고를 관리하는 방법에 대해 알아보자

우선 $python manage.py shell을 입력하면 장고의 쉘 커맨드로 넘어가게 된다.

이렇게 하면 우리의 프로젝트를 그대로 사용하는것이 가능하다.


from lotto.models import GuessNumbers

from django.utils import timezone

즉, 위의 코드들을 그대로 불러와 사용이 가능하다는 것이다.


이렇게 위의 모델을 불러온다음 GuessNumbers.objects.all() 을 입력하면

전체 GuessNumbers의 인스턴스들을 볼 수 있다. 많이 사용하는 키워드 이므로 기억하도록하자.

만약 하나만 보고 싶다면 GuessNumbers.objects.get("조건")을 입력하면 된다.

여기서 조건은 name='kim' 등이 될 수도 있다.


만약에 g= GuessNumbers.objects.get(name='kim')이라는 임의의 객체를 불러와 저장한다음

g.name이나 g.update_date, g.text를 수정한 다음 g.save() 함수를 실행하면 

데이터베이스에서 변경된 정보가 반영된다.


또한 GuessNumbers.objects.filter("조건")으로 해당 조건에 만족하는 인스턴스들을 리턴할 수 있다.



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

저작자 표시
신고

+ Recent posts

티스토리 툴바