Web/WebPage 검색 결과

18개 발견
  1. 미리보기
    2015.07.11 - Palpit

    [WebPage] 실전 웹 프로젝트 구축 !!(Client Part 3) - 웹 페이지 제작 강좌

  2. 미리보기
    2015.07.11 - Palpit

    [WebPage] 실전 웹 프로젝트 구축 !!(Client Part 2) - 웹 페이지 제작 강좌

  3. 미리보기
    2015.07.09 - Palpit

    [WebPage] 실전 웹 프로젝트 구축 !!(Client Part 1) - 웹 페이지 제작 강좌

  4. 미리보기
    2015.07.09 - Palpit

    [WebPage] 실전 웹 프로젝트 구축 !!(Server Part 2) - 웹 페이지 제작 강좌

  5. 미리보기
    2015.07.08 - Palpit

    [WebPage] 실전 웹 프로젝트 구축 !!(Server Part 1) - 웹 페이지 제작 강좌

  6. 미리보기
    2015.07.07 - Palpit

    [WebPage] 실전 웹 프로젝트 구축 !!(실전 예제) - 웹 페이지 제작 강좌

  7. 미리보기
    2015.07.07 - Palpit

    [WebPage] 4. 웹 프로그래밍의 필수요소, JavaScript와 jQuery - 웹 페이지 제작 강좌

  8. 미리보기
    2015.06.26 - Palpit

    [WebPage] 3-3. 장고 프로젝트 시작 - 웹 페이지 제작 강좌

조회수 확인

 


연결된 강좌이므로 아래 링크대로 따라주시면 이해가 더 쉬우실 것 입니다.

===========================================


1. 개발환경설정

2. CSS & Bootstrap 

3. CSS 선택자(Selector)

4. CSS 요소(Element)

5. Bootstrap Part. 1

6. Bootstrap Part. 2

7. 실전 예제 - 개인용 포트폴리오 페이지 제작

8. Python & Django

9. Django

10. 장고(Django) 프로젝트

11. JavaScript & jQuery

12. 실전 웹 프로젝트(예제)


13. 실전 웹 프로젝트(Timeline) Server Part.1


===========================================








7. 다음은 프로필 페이지(profile.html)를 구현하겠습니다.




  기존의 template.html 을 복사한 뒤, 아래처럼 간단히 nav 바까지 작성하도록 하겠습니다.



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
<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="utf-8"/>
        <title>Timeline Example</title>
        <link href="bootstrap/css/bootstrap.css" rel="stylesheet"/>
        <link href="timeline.css" rel="stylesheet"/>
        <link href="bootstrap/css/bootstrap-responsive.css" rel="stylesheet"/>
    </head>
    <body>
        <div class="navbar navbar-inverse navbar-fixed-top">
            <div class="navbar-inner">
                <div class="container">
                    <a class="btn btn-navbar" data-toggle="collapse" data-target="#navMenu"> <span class="icon-bar"> </span> <span class="icon-bar"> </span> <span class="icon-bar"> </span> </a>
                    <a class="brand" href="#"> TimeLine Service </a>
                    <div class="nav-collapse" id="navMenu">
                        <ul class="nav center">
                            <li>
                                <a href="timeline.html">Home</a>
                            </li>
                            <li class="active">
                                <a href="#">Profile</a>
                            </li>
                            <li>
                                <a href="account.html">Account</a>
                            </li>
                        </ul>
                        <div class="btn-group pull-right">
                            <a class="btn" id="adminBtn">
                                <i class="icon-pencil"> </i>
                                Admin
                                <span class="caret"> </span>
                            </a>
                            <a class="btn" id="logoutBtn">
                                <i class="icon-user"> </i>
                                Logout
                                <span class="caret"> </span>
                            </a>
                        </div>
                    </div>
                </div>
            </div>
        </div><!-- End of Navbar -->
 
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
        <script src="bootstrap/js/bootstrap.js"></script>
        <script src="timeline.js"></script>
        <script src="base64.js"></script>
        <script>
            $(document).ready(function() {
 
            });
       </script>
    </body>
</html>
 
cs

 




 기본 틀을 잡았으므로, 몸체를 작성하도록 하겠습니다.


 프로필 왼쪽 부분부터 작성하도록 하겠습니다. Navbar가 끝나는 부분에 작성하세요.




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
        </div><!-- End of Navbar -->
        <!-- Start Profile -->
        <div class="container bg">
            <!-- Start of Container -->
            <div class="row-fluid">
                <!-- Start of Row -->
                <div class="span4">
                    <!-- Start of Span4 -->
                    <div class="well sidebar_nav">
                        <a href="#" id="profile" class="thumbnail"> <img src="http://bit.ly/QyPwPM"/> </a>
                        <hr/>
                        <div>
                            <i class="icon-home"> </i> Seryu-dong
                            <br/>
                            <i class="icon-map-marker"> </i> Gwonseon-gu
                            <br/>
                            <i class="icon-globe"> </i> Suwon, Korea
                            <br/>
                        </div>
                        <hr/>
                        <ul class="nav nav-list">
                            <li class="active">
                                <a href="#"> <i class="icon-white icon-envelope"> </i> Contact Information </a>
                            </li>
                        </ul>
                        <form class="contact">
                            <br/>
                            <div class="alert alert-info">
                                <h4>Country: </h4>
                                <span>Korea, Republic of</span>
                            </div>
                            <div class="alert alert-danger">
                                <h4>Number: </h4>
                                <span>(031)000-0000</span>
                            </div>
                            <div class="alert alert-success">
                                <h4>Email: </h4>
                                <span>zhfldi4@gmail.com</span>
                            </div>
                        </form>
                    </div>
                </div><!-- End of Span4 -->
cs



 작성된 부분을 확인해 보도록 합시다.







 



 다음으로는 프로필 오른쪽 부분을 작성하겠습니다. Span4가 끝나는 부분에 작성하세요.






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
59
60
61
62
63
64
65
66
67
        </div><!-- End of Span4 -->
        <div class="span8"><!--Start of Span8 -->
            <div class="editbtn">
                <a class="btn btn-large" id="editBtn">Edit Profile</a>
            </div>
            <div class="hero-unit heromargin">
                <h1 id="bigid"> </h1>
                <h3 id="bignickname"> </h3>
                <h2 id="bigcomment"> </h2>
            </div>
        </div><!--End of Span8 -->
        <div class="span8"><!-- Start of Span 8 -->
            <ul class="nav nav-list">
                <li class="active">
                    <a href="#">
                        <h4>Comment</h4>
                    </a>
                </li>
            </ul>
            <div class="inside">
                <input type="text" style="width: 98%" id="comment"/>
            </div>
        </div><!--End of Span8 -->
        <div class="span8"><!-- Start of Span 8 -->
            <ul class="nav nav-list">
                <li class="active"><a href="#">
                    <h4>Other Information</h4>
                </a></li>
            </ul>
            <div class="tabbable inside"><!--Start of Tabbable -->
                <ul class="nav nav-tab">
                    <li class="active"><a href="#tab1" data-toggle="tab">Summary</a></li>
                    <li><a href="#tab2" data-toggle="tab">Nickname</a></li>
                    <li><a href="#tab3" data-toggle="tab">Country</a></li>
                    <li><a href="#tab4" data-toggle="tab">WEB</a></li>
                </ul>
                <div class="tab-content">
                    <div class="tab-pane active center" id="tab1">
                        <span class="label label-info" id="labelnick">
                            Nickname
                        </span>
                        <span class="label label-success betwwen" id="labelcountry">
                            Country
                        </span>
                        <span class="label label-important between" id="labelurl">
                            URL
                        </span>
                    </div>
                    <div class="tab-pane" id="tab2">
                        <input id="nickname" type="text" style="width: 95%" />
                    </div>
                    <div class="tab-pane" id="tab3">
                        <input id="country" type="text" style="width: 95%" />
                    </div>
                    <div class="tab-pane" id="tab4">
                        <input id="web" type="text" style="width: 95%" />
                    </div>
                </div>
            </div><!-- End of Tabbable -->
            <hr/>
            <div class="inside center">
                <a class="btn btn-large btn-danger" href="#" id="cancelBtn">Cancel</a>
                <a class="btn btn-large btn-info between" href="#" id="saveBtn">Save</a>
            </div>
        </div><!-- End of Span 8 -->
    </div><!-- End of Row -->
</div><!-- End of Container-->
cs





 화면 확인없이 바로 CSS를 작성한 뒤 확인하겠습니다. timeline.css 를 열어 아래 코드를 추가하세요.




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
/* profile */
.editbtn {
    float: right;
    margin: 20px;
}
.heromargin {
    margin: 15px;
}
.hero-unit h1 {
    color: #5b7dc1;
    font-size: 80px;
}
.hero-unit h3 {
    color: #5b7dc1;
    margin-left: 200px;
}
.hero-unit h2 {
    color: #5b7dc1;
    font-style: italic;
    margin-top: 20px;
    margin-bottom: -20px;
    margin-left: 20px;
}
.nav-list h4 {
    font-style: italic;
    font-weight: normal;
    font-size: 28px;
}
 
cs





 아래처럼 완성된 화면이 나오게 됩니다.










 마지막으로 스크립트 부분을 작성하여 데이터를 로드하겠습니다. timeline.js에 작성하세요.




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
var doGetProfile = function() {
    $.ajax({
        type: 'GET',
        url: baseUrl + 'api/profile/',
        beforeSend: function(req) {
            req.setRequestHeader('Authorization', loginstring);
        },
        success: function(data) {
            fillProfile(data);
        },
        error: function(msg) {
            alert("Fail to get data!");
        }
    });
};
 
var fillProfile = function(data) {
    $("#bigid").html(data.username);
    $("#bignickname").html("A.K.A " + data.nickname);
    $("#bigcomment").html(data.comment);
    
    $("#comment").val(data.comment);
    $("#nickname").val(data.nickname);
    $("#country").val(data.country);
    
    $("#web").val(data.url);
    $("#labelnick").html("Nickname: " + data.nickname);
    $("#labelcountry").html("Country: " + data.country);
    $("#labelurl").html("URL: " + data.url);
};
 
cs



 작성된 스크립트를 매핑하여 제대로 데이터가 전달되는 지 확인해 보도록 하겠습니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
        <script>
            $(document).ready(function() {
                getLoginString();
                doGetProfile();
                
                $("#adminBtn").click(goAdmin);
                // $("#saveBtn").click(doSetProfile);
                // $("#cancelBtn").click(doCancel);
                $("#logoutBtn").click(doLogout);
                
                $("input[type=text]").attr("disabled""disabled");
                $("#editBtn").toggle(function() {
                    $("input[type=text]").removeAttr("disabled");
                }, function() {
                    $("input[type=text]").attr("disabled""disabled");
                });
                
                $("#profile").click(function() {
                    alert("profile clicked");
                });
            });
       </script>
cs










 다음은 데이터를 설정하는 부분을 진행하도록 하겠습니다.



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
var doSetProfile = function() {
    var nickname = $("#nickname").val();
    var comment = $("#comment").val();
    var country = $("#country").val();
    var url = $("#web").val();
    
    $.ajax({
        type: 'POST',
        url: baseUrl + 'api/profile/',
        data: {
            nickname: nickname,
            comment: comment,
            country: country,
            url: url
        },
        beforeSend: function(req) {
            req.setRequestHeader('Authorization', loginstring);
        },
        success: function(data) {
            alert('OK');
            location.reload();
        },
        error: function(msg) {
            alert("Error!");
        }
    });
};
 
var doCancel = function() {
    location.reload();
};
 
cs





 다음 스크립트 부분의 주석을 제거해주세요.(profile.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
 
        <script>
            $(document).ready(function() {
                getLoginString();
                doGetProfile();
                
                $("#adminBtn").click(goAdmin);
                $("#saveBtn").click(doSetProfile);
                $("#cancelBtn").click(doCancel);
                $("#logoutBtn").click(doLogout);
                
                $("input[type=text]").attr("disabled""disabled");
                $("#editBtn").toggle(function() {
                    $("input[type=text]").removeAttr("disabled");
                }, function() {
                    $("input[type=text]").attr("disabled""disabled");
                });
                
                $("#profile").click(function() {
                    alert("profile clicked");
                });
            });
       </script>
 
cs






 



8. 마지막으로 계정 페이지(account.html)를 구현하겠습니다.




  기존의 template.html 을 복사한 뒤, 아래처럼 간단히 nav 바까지 작성하도록 하겠습니다.



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
 
<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="utf-8"/>
        <title>Timeline Example</title>
        <link href="bootstrap/css/bootstrap.css" rel="stylesheet"/>
        <link href="timeline.css" rel="stylesheet"/>
        <link href="bootstrap/css/bootstrap-responsive.css" rel="stylesheet"/>
    </head>
    <body>
        <div class="navbar navbar-inverse navbar-fixed-top">
            <div class="navbar-inner">
                <div class="container">
                    <a class="btn btn-navbar" data-toggle="collapse" data-target="#navMenu"> <span class="icon-bar"> </span> <span class="icon-bar"> </span> <span class="icon-bar"> </span> </a>
                    <a class="brand" href="#"> TimeLine Service </a>
                    <div class="nav-collapse" id="navMenu">
                        <ul class="nav center">
                            <li>
                                <a href="timeline.html">Home</a>
                            </li>
                            <li class="active">
                                <a href="profile.html">Profile</a>
                            </li>
                            <li>
                                <a href="#">Account</a>
                            </li>
                        </ul>
                        <div class="btn-group pull-right">
                            <a class="btn" id="adminBtn"> <i class="icon-pencil"> </i> Admin <span class="caret"> </span> </a>
                            <a class="btn" id="logoutBtn"> <i class="icon-user"> </i> Logout <span class="caret"> </span> </a>
                        </div>
                    </div>
                </div>
            </div>
        </div><!-- End of Navbar -->
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
        <script src="bootstrap/js/bootstrap.js"></script>
        <script src="timeline.js"></script>
        <script>
            $(document).ready(function() {
 
            });
       </script>
    </body>
</html>
cs






nav바 밑부터 몸체를 작성하도록 하겠습니다.



 ID를 나타내는 부분과 Friend List 부터 작성하도록 하겠습니다.



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
<div class="container bg"><!-- Start of Container -->
    <div class="row-fluid">
        <div class="span12">
            <div class="inside">
                <h1>Account</h1>
                <h4 class="between">Python/Django</h4>
            </div>
            <h3>Change your personal information</h3>
        </div>
    </div><!-- ENd of row -->
    <div class="row-fluid">
        <div class="span12">
            <div class="inside center">
                <h2>ID</h2>
                <div class="write">
                    <input type="text" id="username" disabled="true"/>
                </div>
            </div>
        </div>
    </div><!-- ENd of row -->
    <div class="row-fluid">
        <div class="span12">
            <div class="inside">
                <h2> Friend List </h2>
                <ul class="nav nav-tabs nav-stacked" id="listarea">
                </ul>
                <li id="ignoreTemplate" style="display:none;">
                    <a>
                        <button class="btn btn-mini btn-info right10 ignoreBtn">
                            <i id="icon"> </i>
                        </button>
                        <span id="name" name="name"> </span>
                        <span id="ignored">:ignored </span>
                    </a>
                </li>
            </div>
        </div>
    </div>
    
</div><!-- End of Container -->
cs




 위 코드의 <!-- End of Container --> 바로 위에 아래 소스를 추가해주세요.




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
            <div class="row-fluid">
                <div class="span6 accountbox">
                    <div class="inside">
                        <h3>Old password</h3>
                        <input type="text" id="oldpassword" style="width:95%;"/>
                        <h3>New password</h3>
                        <input type="text" id="newpassword" style="width:95%;"/>
                        <div class="center">
                            <a class="btn" href="#" id="chkPwBtn">Check Password</a>
                            <a class="btn between" href="#" id="setPwBtn">Set Password</a>
                        </div>
                    </div>
                </div>
                <div class="span6 accountbox">
                    <div class="inside">
                        <h2>Name</h2>
                        <input type="text" id="getname" style="width:95%;"/>
                        <div class="center">
                            <a class="btn" href="#" id="getNameBtn">Get name</a>
                            <a class="btn between" href="#" id="setNameBtn">Set name</a>
                        </div>
                    </div>
                </div>
            </div><!-- End of Row -->
            <div class="row-fluid">
                <div class="span12 center">
                    <div class="inside">
                        <a class="btn btn-large btn-info" href="#" id="refreshBtn">Refrest</a>
                    </div>
                </div>
            </div><!-- ENd of Row -->
        </div><!-- End of Container -->
cs



 

 다음 CSS를 추가한 뒤, 페이지를 확인 하겠습니다.



1
2
3
4
5
6
7
8
/* account */
.accountbox {
    height : 250px;
}
.right10 {
    margin-right : 10px;
}
cs









  Password와 Name 정보를 받아오기 위한 자바스크립트를 작성하도록 하겠습니다.



 패스워드 관련 함수I입니다.


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
 
var doCheckPassword = function() {
    $.ajax({
        type: 'POST',
        url: baseUrl + 'api/user/checkpassword/',
        data: {
            password: $("#oldpassword").val()
        },
        beforeSend: function(req) {
            req.setRequestHeader('Authorization', loginstring);
        },
        success: function(data) {
            alert(data.status);
        },
        error: function(msg) {
            alert("Fail to get data!");
        }
    });
};
 
var doSetPassword = function() {
    $.ajax({
        type: 'POST',
        url: baseUrl + 'api/user/update/',
        data: {
            password:$('#newpassword').val()
        },
        beforeSend: function(req) {
            req.setRequestHeader('Authorization', loginstring);
        },
        success: function(data) {
            alert("OK");
            loginstring = "Basic " + Base64.encode(username + ":"+ $("#newpassword").val());
            setLoginString();
            $('#oldpassword').val($("#newpassword").val());
            $('#newpassword').val("");
        },
        error: function(msg) {
            alert(msg.responseText);
        }
    });
};
 
 
cs




 다음은 이름을 가져오는 함수를 구현하겠습니다.



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
 
 
var doGetName = function() {
    $.ajax({
        type : 'GET',
        url : baseUrl + 'api/user/name/',
        beforeSend : function(req) {
            req.setRequestHeader('Authorization', loginstring);
        },
        success : function(data) {
            $("#getname").val(data.name);
        },
        error : function(msg) {
            alert("Fail to get data!");
        }
    });
};
 
var doSetName = function() {
    $.ajax({
        type : 'POST',
        url : baseUrl + 'api/user/name/',
        data: {name: $("#getname").val()},
        beforeSend : function(req) {
            req.setRequestHeader('Authorization', loginstring);
        },
        success : function(data) {
            alert("OK!");
        },
        error : function(msg) {
            alert("Fail to set data!");
        }
    });
};
 
cs





 account.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
25
        <script>
            $(document).ready(function() {
                getLoginString();
                
                $("#adminBtn").click(goAdmin);
                $("#logoutBtn").click(doLogout);
                
                $("#username").val(username);
                
                $("#chkPwBtn").click(doCheckPassword);
                $("#setPwBtn").click(function() {
                    if ($("#newpassword").val() != "")
                        doSetPassword();
                    else 
                        alert("Fill the new password form.");
                });                
                
                $("#getNameBtn").click(doGetName);
                $("#setNameBtn").click(doSetName);
 
            });
       </script>
 
 
 
cs





 이름을 가져올 시, 해당 계정의 first name을 가져오는 것이므로 firstname이 설정이 되어있어야 공백으로 나타나지 않습니다.






9. Ignore 리스트를 뿌리는 기능을 구현하겠습니다.




 timeline.js에 작성합니다.



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
 
 
var doGetUserList = function() {
    $.ajax({
        type: 'GET',
        url : baseUrl + 'api/user/list/',
        beforeSend : function(req) {
            req.setRequestHeader('Authorization', loginstring);
        },
        success : function(data) {
            myIgnoreList = [];
            $('#listarea').html("");
            
            for (var i in data) {
                if (username == data[i].username) 
                    myIgnoreList = data[i].ignores;
            }
            
            for (var i in data) {
                if (username != data[i].username) 
                    doAppendIgnored(data[i], myIgnoreList);
            }
        },
        error : function(msg) {
            alert("Fail to get data!");
        }
 
    });
};
 
var doAppendIgnored = function(data, ignoreList) {
    var isIgnored = $.inArray(data.user, ignoreList);
    
    node = $('#ignoreTemplate').clone();
    $('#name', node).html(data.username);
    $('.ignoreBtn', node).attr("value", data.user);
    
    if (isIgnored == -1) {
        $("#ignored", node).html("");
        $('#icon', node).removeClass().addClass('icon-plus');
    } else {
        $('#ignored', node).html(": Ignored");
        $('#icon', node).removeClass().addClass("icon-minus");
    }
    
    node.show();
    $('#listarea').append(node);
    
};
 
cs

  




 스크립트에서 호출을 해줍니다. 페이지에서 확인을 하도록 하겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
        <script>
            $(document).ready(function() {
                getLoginString();
                
                $("#adminBtn").click(goAdmin);
                $("#logoutBtn").click(doLogout);
                
                $("#username").val(username);
                
                $("#chkPwBtn").click(doCheckPassword);
                $("#setPwBtn").click(function() {
                    if ($("#newpassword").val() != "")
                        doSetPassword();
                    else 
                        alert("Fill the new password form.");
                });                
                
                $("#getNameBtn").click(doGetName);
                $("#setNameBtn").click(doSetName);
 
                doGetUserList();
            });
       </script>
 









마지막으로 무시하기 위한 함수를 구현하겠습니다. account.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
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
 
<script>
    $(document).ready(function() {
        getLoginString();
 
        $("#adminBtn").click(goAdmin);
        $("#logoutBtn").click(doLogout);
 
        $("#username").val(username);
 
        $("#chkPwBtn").click(doCheckPassword);
        $("#setPwBtn").click(function() {
            if ($("#newpassword").val() != "")
                doSetPassword();
            else
                alert("Fill the new password form.");
        });
 
        $("#getNameBtn").click(doGetName);
        $("#setNameBtn").click(doSetName);
 
        doGetUserList();
 
        $(document).on("click"".ignoreBtn"function(e) {
            var id = parseInt($(this).val());
            var isIgnored = $.inArray(id, myIgnoreList);
 
            if (isIgnored == -1)
                myIgnoreList.push(id);
            else
                $.ajax({
                    type : 'POST',
                    url : baseUrl + 'api/profile/',
                    data : {
                        ignore : "[" + myIgnoreList.toString() + "]"
                    },
                    beforeSend : function(req) {
                        req.setRequestHeader('Authorization', loginstring);
                    },
                    success : function(data) {
                        alert("OK");
                        doGetUserList();
                    },
                    error : function(msg) {
                        alert("Fail to set data");
                    }
                });
        });
 
        $("#refreshBtn").click(doCancel);
    });
</script>
cs





  작성된 기능은 + 버튼을 누르면 해당 사용자가 무시되는 방식입니다.



 여기까지해서 모든 구현이 끝났습니다.










* 본 포스팅은 이재근 등 4명 저 "Fast Web Service Build up: 웹 서비스를 쉽고 빠르게 구축하는 기술" 저서를 참고하여 작성하였습니다






다른 카테고리의 글 목록

Web/WebPage 카테고리의 포스트를 톺아봅니다
조회수 확인

이전 장에 이어서 이번 장에서는 타임라인(Timeline) 서비스에 대해 클라이언트를 구현하겠습니다.





연결된 강좌이므로 아래 링크대로 따라주시면 이해가 더 쉬우실 것 입니다.

===========================================


1. 개발환경설정

2. CSS & Bootstrap 

3. CSS 선택자(Selector)

4. CSS 요소(Element)

5. Bootstrap Part. 1

6. Bootstrap Part. 2

7. 실전 예제 - 개인용 포트폴리오 페이지 제작

8. Python & Django

9. Django

10. 장고(Django) 프로젝트

11. JavaScript & jQuery

12. 실전 웹 프로젝트(예제)


13. 실전 웹 프로젝트(Timeline) Server Part.1


===========================================







1. template.html을 복사하여 timeline.html을 작성합니다. 




 base64.js를 추가해주는 것도 잊지 마세요.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="utf-8"/>
        <title>Timeline Example</title>
        <link href="bootstrap/css/bootstrap.css" rel="stylesheet"/>
        <link href="timeline.css" rel="stylesheet"/>
        <link href="bootstrap/css/bootstrap-responsive.css" rel="stylesheet"/>
    </head>
    <body>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
        <script src="bootstrap/js/bootstrap.js"></script>
        <script src="timeline.js"></script>
        <script src="base64.js"></script>
        <script>
            $(document).ready(function() {
 
            });
       </script>
    </body>
</html>
cs










2. 상단 Navbar를 작성합니다. 




body 태그 안에 작성해주세요.


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
<div class="navbar navbar-inverse navbar-fixed-top">
    <div class="navbar-inner">
        <div class="container">
            <a class="btn btn-navbar" data-toggle="collapse" data-target="#navMenu"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </a>
            <a class="brand" href="#">TimeLine Service</a>
            <div class="nav-collapse"id="navMenu">
                <ul class="nav center">
                    <li class="active">
                        <a href="#">Home</a>
                    </li>
                    <li>
                        <a href="profile.html">Profile</a>
                    </li>
                    <li>
                        <a href="account.html">Account</a>
                    </li>
                </ul>
                <div class="btn-group pull-right">
                    <a class="btn" id="adminBtn">
                        <i class="icon-pencil"></i>
                        Admin
                        <span class="caret"></span>
                    </a>
                    <a class="btn" id="logoutBtn">
                        <i class="icon-user"></i>
                        Logout
                        <span class="caret"></span>
                    </a>
                </div>
            </div>
        </div>
    </div>
</div><!-- End of NavBar -->
cs





실행 결과 아래와 같습니다.

  







 상단 메뉴 부분을 완성했으니 몸체 부분을 작성하도록 하겠습니다. 



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
59
60
61
62
63
64
65
66
67
68
69
        <div class="container bg">
            <!-- Start of Container -->
            <div class="timeline">
                <!-- Start of timeline -->
                <div class="span7 bottom15">
                    <div class="roundinside bottom15 center">
                        <fieldset>
                            <label class="lightblue bold leftalign" for="textarea"> Compose New Message </label>
                            <textarea class="input-xlarge span6" id="writearea" name="content" rows="3"></textarea>
                            <div>
                                <a class="btn btn-primary" id="writeBtn"> Write </a>
                                <a class="btn btn-info between" id="reloadBtn"> Refresh </a>
                            </div>
                        </fieldset>
                    </div>
                    <div class="roundinside" id="msgTemplate">
                        <a data-toggle="modal" class="getInfo">
                        <div class="name lightblue">
                            JACK
                        </div> </a>
                        <div class="content">
                            <a class="btn close" name="deleteTimeline">X</a>
                        </div>
                        <span class="date">2015/07/09</span>
                        <span class="like"> <a class="btn" id="like" name="like"> <i class="icon-chevron-up"></i> </a> </span>
                    </div>
                    <div id="timelinearea">
 
                    </div>
                </div>
                <div class="span4 submenu">
                    <div class="roundinside">
                        <span> ID: </span><span id="username"></span>
                    </div>
                    <div class="roundinside">
                        <div class="pagination pagination-centered">
                            <ul>
                                <li>
                                    <a><strong id="total"></strong>Total Timeline</a>
                                </li>
                                <li>
                                    <a><strong id="mine"></strong>My Timeline</a>
                                </li>
                            </ul>
                        </div>
                    </div>
                    <div class="roundinside center bottom15">
                        <input type="text" class="search" id="search" />
                        <a class="btn btn-info" id="searchBtn">
                            <i class="icon-search"></i>
                        </a>
                    </div>
                </div>
            </div><!-- End of Timeline -->
        </div><!-- End of Container -->
        <div class="modal hide fade" id="myModal">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">
                    x
                </button>
                <h2><span id="modalid"></span>'s Info</h2>
            </div>
            <div class="modal-body">
                <h3>Nick: <span id="modalnickname"></span></h3>
                <h3>Country: <span id="modalcountry"></span></h3>
                <h3>URL: <span id="modalurl"></span></h3>
                <h3>Comment: <span id="modalcomment"></span></h3>
            </div>
        </div><!-- End of MyModal -->
cs







3. 몸체를 작성했으니, CSS를 추가해서 꾸며보겠습니다.





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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/* timeline page */
.container .brand {
    color: white;
    font-size: 22px;
}
.timeline {
    padding-top: 5px;
    padding-left: 15px;
    padding-right: 15px;
}
.leftalign {
    text-align: left;
}
.bold {
    font-weight: bold;
}
.content {
    font-weight: bold;
    padding-left: 10px;
    margin-top: 3px;
}
.date {
    color: grey;
    font-size: 12px;
    margin-right: 15px;
}
.roundinside {
    padding: 10px;
    background-color: white;
    -webkit-border-radius: 6px;
    -moz-border-radius: 6px;
    border-radius: 6px;
    margin-bottom: 3px;
}
.bottom15 {
    margin-bottom: 15px;
}
.submenu {
    color: #5b7dc1;
    text-align: center;
    font-size: 18px;
    font-weight: bold;
    margin-bottom: 10px;
}
.submenu ul {
    margin-top: 7px;
}
.submenu li a {
    font-size: 13px;
}
.submenu li a strong {
    display: block;
    line-height: 0px;
    margin-top: 15px;
}
.search {
    width: 70%;
    margin-top: 8px;
}
 
cs







 아래처럼 더욱 간결한 UI를 선보이게 되었습니다.









 화면 구성을 보느라 더미 데이터와 스타일을 따로 추가해 주겠습니다. div의 id가 msgTemplate인 부분을 찾아서 아래와 같이 수정해 줍니다.



1
2
3
4
5
6
7
8
9
                    <div class="roundinside" id="msgTemplate" style="display: none;">
                        <div class="name lightblue">
                        </div>
                        <div class="content">
                            <a class="btn close" name="deleteMsg">X</a>
                        </div>
                        <span class="date"></span>
                        <span class="like"> <a class="btn" id="like" name="like"> <i class="icon-chevron-up"></i> </a> </span>
                    </div>
cs













4. 다음으로 자바스크립트를 작성하여 타임라인에 대한 여러 화면과 기능을 구현하겠습니다.




 이번에는 아래와 같이 많은 기능을 구현할 예정입니다.

  1) 타임라인 작성하기

  2) 타임라인 데이터 가져오기

  3) 타임라인 검색하기

  4) 내가 쓴 글 삭제하기

  5) Like 추가하기

  6) 메시지 개수 카운트하기



 먼저 timeline.js를 열어서 doLogin 함수 아래에 작성합니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
 
var doWriteTimeline = function() {
    var msg = $("#writearea").val();
    
    $.ajax({
        type: 'POST',
        url: baseUrl + 'api/timeline/create/',
        data: {message: msg},
        beforeSend: function(req) {
            req.setRequestHeader('Authorization', loginstring);
        },
        success: function() {
            alert('OK');
            doReload();
        },
        error: function(msg) {
            alert("Fail to write data!");
        }
    });
};
 
cs



 다음으로는 메세지를 가져오는 함수를 구현하겠습니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var doGetTimeline = function() {
    $.ajax({
        type: 'GET',
        url: baseUrl + 'api/timeline/',
        beforeSend: function(req) {
            req.setRequestHeader('Authorization', loginstring);
        },
        success: function(data) {
            for (var i in data.messages) {
                doAppend(data.messages[i]);
            }
            
            $("#total").html(data.total_count);
            $("#mine").html($('[name=deleteMsg]').length - 1);
            $("#username").html(username);
            $("#writearea").val();
        },
        error: function() {
            alert("Fail to get data!");
        }
    });
};
 
cs



 계속해서 필요한 함수들을 작성하겠습니다.



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
 
var doAppend = function(data) {
    node = $('#msgTemplate').clone();
    
    $('.name', node).append(data.username);
    $('.content', node).append(data.message);
    $('.date', node).append(data.created);
    $('.like', node).prepend(data.liked + " ");
    $('#like', node).attr("value", data.id);
    $('#dislike', node).attr("value", data.id);
    
    if (username == data.username) 
        $('[name=deleteMsg]', node).attr("value", data.id);
    else 
        $('[name=deleteMsg]', node).remove();
        
    node.show();
    $('#timelinearea').append(node);
};
 
var doReload = function() {
    doClear();
    doGetTimeline();
};
 
var doClear = function() {
    $('#timelinearea').html('');
};
 
cs




 작성한 JS들을 연결하기 위해 timeline.html을 열어 작성해줍니다.




1
2
3
4
5
6
7
8
9
10
11
 
        <script>
            $(document).ready(function() {
                getLoginString();
                doGetTimeline();
                $('#adminBtn').click(goAdmin);
                $('#writeBtn').click(doWriteTimeline);
                $('#reloadBtn').click(doReload);
            });
        </script>
 
cs








 자 그럼 타임라인의 기능에 대해서 수행을 확인해 보겠습니다.



 먼저 계정으로 로그인 된 상태에서 타임라인을 작성해보도록 하겠습니다.







 Write를 눌러 제대로 개제되는 지 확인합니다.



보시는 바와 같이 제대로 타임라인에 개제 되었습니다.













5. 타임라인의 작성 구현 후, 타임라인 삭제 및 검색을 구현하겠습니다.




  먼저 삭제 기능을 구현하겠습니다. 삭제 기능은 timeline.html에 구현하도록 하겠습니다. html 내부의 script 태그 내에 작성해주세요.

 ( * 기존 live에서 on으로 대체하면서 매핑문제 때문에 html 내부에 구현하게 되었습니다.)




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$(document).on("click""[name=deleteMsg]"function(e) {
    var id = e.target.getAttribute('value');
    // alert(tmp);
 
    $.ajax({
        type : 'POST',
        url : 'http://127.0.0.1:8000/api/timeline/' + id + "/delete/",
        beforeSend : function(req) {
            req.setRequestHeader('Authorization', loginstring);
        },
        success : function(data) {
            doReload();
        },
        error : function(msg) {
            alert("Fail to delete data!");
        }
    });
 
});
cs





 그 다음, 타임라인 검색 기능을 구현하도록 하겠습니다.



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
var doSearchTimeline = function() {
    $.ajax({
        type: 'GET',
        url: baseUrl + 'api/timeline/find/',
        data: {query: $("#search").val()},
        beforeSend: function(req) {
            req.setRequestHeader('Authorization', loginstring);
        },
        success: function(data) {
            doClear();
            for (var i in data) {
                doAppend(data[i]);
            }
            
            $("#total").html(data.length);
            $("#mini").html($('[name=deleteMsg]').length - 1);
            $("#search").val("");
        },
        error: function() {
            alert("Fail to get Data!");
        }
    });
};
 
 
cs




 마지막으로 구현하지 않았던 로그아웃 기능을 구현하여 테스트 해보겠습니다.




1
2
3
4
5
6
 
var doLogout = function() {
    resetLoginString();
    window.location = "login.html";
};
 
cs






 timeline.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
25
26
27
28
29
30
31
32
<script>
    $(document).ready(function() {
        getLoginString();
        doGetTimeline();
        $('#adminBtn').click(goAdmin);
        $('#writeBtn').click(doWriteTimeline);
        $('#reloadBtn').click(doReload);
        $(document).on("click""[name=deleteMsg]"function(e) {
            var id = e.target.getAttribute('value');
            // alert(tmp);
 
            $.ajax({
                type : 'POST',
                url : 'http://127.0.0.1:8000/api/timeline/' + id + "/delete/",
                beforeSend : function(req) {
                    req.setRequestHeader('Authorization', loginstring);
                },
                success : function(data) {
                    doReload();
                },
                error : function(msg) {
                    alert("Fail to delete data!");
                }
            });
 
        });
        $("#searchBtn").click(doSearchTimeline);
        $("#logoutBtn").click(doLogout);
 
    });
 
</script>
cs






 삭제, 검색, 로그아웃이 잘 되는지 확인하시고 다음으로 넘어가 주세요.











6. Like기능과 Modal Dialog 표시를 구현하겠습니다.




  코멘트에 호감을 표시하는 기능인 Like를 먼저 구현해보도록 하겠습니다. Like 기능 역시 timeline.html에 작성합니다.

 



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
$(document).on("click""[name=like]"function(e) {
    var id = e.target.getAttribute('value');
 
    $.ajax({
        type : 'POST',
        url : baseUrl + 'api/timeline/' + id + '/like/',
        beforeSend : function(req) {
            req.setRequestHeader('Authorization', loginstring);
        },
        success : function() {
            doReload();
        },
        error : function(msg) {
            alert("Fail to set data!");
        }
    });
});
 
cs




 다음으로는 Modal Dialog에 대해 구현하겠습니다. 이 기능 또한 timeline.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
25
 
 
$(document).on("click"".name.lightblue"function(e) {
    var username = $(this).html();
    
    $.ajax({
        type: 'GET',
        url: baseUrl + 'api/profile/' + username + '/',
        beforeSend: function(req){
            req.setRequestHeader('Authorization', loginstring);
        },
        success: function(data) {
            $("#modalid").html(data.username);
            $("#modalnickname").html(data.nickname);
            $("#modalcountry").html(data.country);
            $("#modalcomment").html(data.comment);
            $("#modalurl").html(data.url);
            $("#myModal").modal("show");
        },
        error: function(msg) {
            alert("Fail to get data!");
        }
    });
});
 
cs




 두 기능을 구현한 뒤, Like 아이콘 클릭시 count가 되는지, 사용자 아이디를 클릭 시, Modal 이 뜨는지 확인하세요.



 

 다음 장에서는 Profile과 Account 창 구현을 하도록 하겠습니다.






* 본 포스팅은 이재근 등 4명 저 "Fast Web Service Build up: 웹 서비스를 쉽고 빠르게 구축하는 기술" 저서를 참고하여 작성하였습니다

다른 카테고리의 글 목록

Web/WebPage 카테고리의 포스트를 톺아봅니다
조회수 확인

이제 클라이언트(Client)를 개발할 차례입니다. 




연결된 강좌이므로 아래 링크대로 따라주시면 이해가 더 쉬우실 것 입니다.

===========================================


1. 개발환경설정

2. CSS & Bootstrap 

3. CSS 선택자(Selector)

4. CSS 요소(Element)

5. Bootstrap Part. 1

6. Bootstrap Part. 2

7. 실전 예제 - 개인용 포트폴리오 페이지 제작

8. Python & Django

9. Django

10. 장고(Django) 프로젝트

11. JavaScript & jQuery

12. 실전 웹 프로젝트(예제)


13. 실전 웹 프로젝트(Timeline) Server Part.1


===========================================







시작하기전 CORS(Cross Origin Resource Sharing)을 처리하기 위하여 settings.py를 열어서 아래와 같이 해당 소스를 추가해줍니다. MIDDLEWARE_CLASSES를 아래로 대체하세요.


 * 가장 하단에 보시면 '프로젝트명.cors.XsSharingMiddleware', 형식으로 추가되었음을 확인 할 수 있습니다.


1
2
3
4
5
6
7
8
9
10
MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    #'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'timelineproject.cors.XsSharingMiddleware',
)
cs



그리고 나서 아래 주소에 접속하여 cors.py를 받아서 settings.py가 들어있는 폴더에 저장해줍니다.

https://gist.github.com/3733574



우선 프로젝트 틀을 갖추기 위해서 새로운 프로젝트를 생성하여 Bootstrap 까지 복사하겠습니다.



그리고 join.html, timeline.css, timeline.js 까지 생성해 놓겠습니다.



완료된 프로젝트 구조는 아래와 같습니다.







다음 해당되는 파일들을 아래 경로에다가 넣어주세요.


timelineproject -> templates -> timeline


templates폴더 생성한 뒤, timeline 생성해서 넣어주시면 됩니다.







1. 먼저 HTML의 틀을 잡겠습니다. join.html을 열어 아래와 같이 작성해주세요.





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="utf-8"/>
        <title>Timeline Example</title>
        <link href="bootstrap/css/bootstrap.css" rel="stylesheet"/>
        <link href="timeline.css" rel="stylesheet"/>
        <link href="bootstrap/css/bootstrap-responsive.css" rel="stylesheet"/>
    </head>
    <body>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
        <script src="bootstrap/js/bootstrap.js"></script>
        <script src="timeline.js"></script>
        <script>
            $(document).ready(function() {
                
            });
       </script>
    </body>
</html>
cs




 - Bootstrap, jQuery 라이브러리 추가를 위한 간단한 코드와 HTML 틀을 구성하기 위한 소스입니다.











2. 다음으로 네비게이션으로 상단 메뉴를 구성하겠습니다.






 위에서 작성한 join.html의 body 태그에 작성해주세요.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        <div class="navbar navbar-inverse navbar-fixed-top">
            <div class="navbar-inner">
                <div class="container">
                    <a class="btn btn-navbar" data-toggle="collapse" data-target="#navMenu">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </a>
                    <a class="brand" href="login.html">TimeLine service</a>
                    <div class="nav-collapse" id="navMenu">
                        <div class="btn-group pull-right">
                            <a class="btn" id="adminBtn">
                                <i class="icon-pencil"></i>
                                ADMIN
                            </a>
                        </div>
                    </div>
                </div>
            </div>
        </div><!-- End of NavBar -->
cs



 - 화면의 Navigation Bar를 생성하기 위해 작성한 코드입니다.




실행 결과 아래와 같이 나옵니다.












3. 메뉴를 완성했으니, 페이지 레이아웃을 구성해보도록 하겠습니다.





navbar 밑에 작성하세요.



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
<div class="container">
            <!-- Start of Container -->
            <div class="row-fluid">
                <!-- Start of Row -->
                <div class="span12">
                    <div class="inside">
                        <br>
                        <div class="lighblue">
                            <h1>Create Account</h1>
                        </div>
                        <div>
                            <h3>Join our Service!</h3>
                        </div>
                        <br>
                    </div>
                </div>
            </div><!-- End of Row -->
            <div class="row-fluid">
                <!-- Start of Row2 -->
                <div class="span6">
                    <div class="inside center">
                        <h2>ID</h2>
                        <input type="text" placeholder="Input Your ID" id="username"/>
                    </div>
                </div>
                <div class="span6">
                    <div class="inside center">
                        <h2>PASSWORD</h2>
                        <input type="text" placeholder="Input your Password" id="password"/>
                    </div>
                </div>
            </div><!-- End of Row 2 -->
            <div class="row-fluid">
                <!-- Start of Row3 -->
                <div class="span12">
                    <div class="inside center">
                        <h2>NAME</h2>
                        <input type="text" placeholder="Input your Name" id="name"/>
                    </div>
                </div>
            </div><!-- End of Row3 -->
            <div class="row-fluid">
                <!-- Start of Row 4 -->
                <div class="span12">
                    <div class="inside center">
                        <a class="btn btn-large btn-info" id="joinBtn">Join Now!</a>
                    </div>
                </div>
            </div><!-- End of Row 4 -->
        </div><!-- End of Container -->
cs




실행결과 간단한 화면이 구성될 것 입니다. 그러나 상단의 메뉴바와 문구가 약간 겹치는 현상이 있습니다. 

본격적으로 CSS를 추가하여 조절하도록 하겠습니다.







4. CSS를 열어서 아래와 같이 작성합니다.





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
/* join page */
body {
    background-color: #C0DEED;
    padding-top: 60px;
    padding-bottom: 40px;
    font-family: calibri;
}
.row-fluid div[class*="span"] {
    background-color: white;
    -webkit-border-radius: 6px;
    -moz-border-radius: 6px;
    border-radius: 6px;
    margin-bottom: 10px !important;
}
.center {
    text-align: center;
    font-size: 16px;
}
.inside {
    margin: 10px;
}
.lighblue {
    color: #5b7dc1;
}
 
cs




 실행결과 좀 더 깔끔하게 구현되어 집니다.














5. JS를 준비된 API와 연동하기 위해 timeline.js를 열어서 아래와 같이 작성합니다.







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
var baseUrl = 'http://127.0.0.1:8000/';
var username;
var password;
 
var doJoin = function() {
    var name = $("#name").val();
 
    username = $("#username").val();
    password = $("#password").val();
 
    $.ajax({
        type : 'POST',
        url : baseUrl + 'api/user/create/',
        data : {
            username : username,
            password : password,
            name : name
        },
        success : function() {
            alert("OK");
            location.href = "login.html";
        },
        error : function(msg) {
            alert("Error!");
        },
    });
 
};
 
var goAdmin = function() {
    location.href = baseUrl + "admin/";
};
 
cs






다음은 작성된 js를 html에 연결하는 코드를 작성하겠습니다. join.html을 열어 아래 부분을 추가합니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
        <script>
            $(document).ready(function() {
                $("#joinBtn").click(function() {
                    var name = $("#name").val();
                    var username = $("#username").val();
                    var password = $("#password").val();
                    
                    if (name != "" && username != "" && password != "")
                        doJoin();
                    else 
                        alert("Fill all forms");
                });
                $("#adminBtn").click(goAdmin);
            });
        </script>
cs





이렇게 하면 계정생성 페이지가 완성이 되었습니다.


간단하게 테스트 결과 login.html의 부재로 인해 깔끔하지가 않습니다. 다음으로 로그인 페이지를 만들도록 하겠습니다.








6. template.html을 작성한 뒤, 복사하여 login.html의 틀을 잡겠습니다.






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="utf-8"/>
        <title>Timeline Example</title>
        <link href="bootstrap/css/bootstrap.css" rel="stylesheet"/>
        <link href="timeline.css" rel="stylesheet"/>
        <link href="bootstrap/css/bootstrap-responsive.css" rel="stylesheet"/>
    </head>
    <body>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
        <script src="bootstrap/js/bootstrap.js"></script>
        <script src="timeline.js"></script>
        <script>
            $(document).ready(function() {
 
            });
       </script>
    </body>
</html>
cs




위와 같이 작성된 template.html을 토대로 복사하여서 login.html을 똑같이 만듭니다.







7. login.html의 레이아웃을 구성 하겠습니다.





 먼저 상단 네비게이션 바를 구성하겠습니다. body 태그 위에서부터 작성하세요.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    <body>
        <div class="navbar navbar-inverse navbar-fixed-top">
            <div class="navbar-inner">
                <div class="container">
                    <a class="btn btn-navbar" data-toggle="collapse" data-target="#navMenu">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </a>
                    <a class="brand" href="login.html">TimeLine Service</a>
                    <div class="nav-collapse" id="navMenu">
                        <div class="btn-group pull-right">
                            <a class="btn" id="adminBtn">
                                <i class="icon-pencil"></i>
                                ADMIN
                            </a>
                        </div>
                    </div>
                </div>
            </div>
        </div><!-- End of NavBar -->
cs






다음으로 레이아웃을 구성하겠습니다. 네비바 다음부터 작성해주세요.


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
        </div><!-- End of NavBar -->
        <div class="container bg logincontainer"><!-- Start of Container -->
            <div class="row-fluid"><!-- Start of Row -->
                <div class="span8">
                    <div class="inside center loginbox">
                        <h1 class="bigfont lightblue middlemsg">Time Line Service</h1>
                    </div>
                </div>
                <div class="span4">
                    <div class="inside center loginbox"><br>
                        <div class="alert alert-info">
                            <h4>Login Please</h4>
                        </div>
                        I D : <input type="text" id="username" class="width50"/> <br>
                        P W : <input type="password" id="password" class="width50" />
                        <div class="inside">
                            <a class="btn btn-primary" id="loginBtn"
                                Login
                            </a>
                            <a class="btn btn-primary between" id="registerBtn">
                                Register
                            </a>
                        </div>
                    </div>
                </div>
            </div><!-- End of Row -->
        </div><!-- End of Container -->
cs






실행 결과 아래와 같습니다. 추가적으로 CSS를 적용시켜야 합니다.









8. timeline.css를 작성 하겠습니다.





 가장 하단 부터 작성하시면 되겠습니다. (이전에 작성한 코드 맨 하단에)



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
/* login page */
.logincontainer {
    padding: 15px;
    margin-top: 120px;
}
.between {
    margin-left: 30px;
}
.bg {
    padding: 15px;
    background: url('http://bit.ly/MTt30q');
}
.loginbox {
    height: 200px;
}
.middlemsg {
    padding-top: 80px;
}
.bigfont {
    font-size: 60px;
    font-weight: bold;
}
.width50 {
    width: 50%;
}
 
cs




 더욱 깔끔한 구성으로 바뀌었습니다.













9. 직접적으로 인증을 하기 위한 javascript를 작성 하겠습니다.





 장고(Django)에서도 사용한 Basic Auth를 통해 인증을 구현하도록 하겠습니다.

 - 간단히 설명한다면, Basic Auth는 암호화 방법으로 base64 encoding을 사용합니다. 

 - 그럼 아래 링크로 접속하여 소스를 복사해서 timeline.js와 같은 경로에 넣어줍니다.(base64.js 파일명으로)

  http://www.webtoolkit.info/javascript-base64.html



 다음으로 login.html에 아래 코드를 추가합니다.


1
        <script src="base64.js"></script>
cs




 timeline.js를 열어서 아래 코드를 추가합니다.


1
var loginstring;
cs



맨 상단에 var password 밑에 위 코드를 추가해 주시고, 로그인에 필요한 기능 함수를 맨 하단에 작성하도록 하겠습니다.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
var doLogin = function() {
    username = $("#username").val();
    password = $("#password").val();
    loginstring = "Basic " + Base64.encode(username + ":" + password);
    
    $.ajax({
        type: 'GET',
        url: baseUrl + 'api/login/',
        beforeSend: function(req) {
            req.setRequestHeader('Authorization', loginstring);
        },
        success: function(data) {
            alert("Login Success");
            setLoginString();
            window.location = "timeline.html";
        },
        error: function() {
            alert("Fail to get data!");
        }
    });
};
 
cs





 다음으로는 쿠키를 통해서 로그인 상태에 대해 담는 그릇을 생성하겠습니다.



 위 코드 아래 부분에 다음과 같이 작성합니다.



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
 
function setCookie(name, value, day) {
    var expire = new Date();
    expire.setDate(expire.getDate() + day);
    cookies = name + '=' + escape(value) + '; path=/ ';
    
    if (typeof day != 'undefined')
        cookies += ';expires=' + expire.toGMTString() + ';';
    
    document.cookie = cookies;
}
 
function getCookie(name) {
    name = name + '=';
    var cookieData = document.cookie;
    var start = cookieData.indexOf(name);
    var value = '';
    
    if (start != -1) {
        start += name.length;
        var end = cookieData.indexOf(';', start);
        
        if (end == -1
            end = cookieData.length;
        
        value = cookieData.substring(start, end);
    }
    
    return unescape(value);
}
 
cs




 추가적으로 쿠키를 이용해서 로그인 데이터를 유지하기 위한 함수를 더 작성하도록 하겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
function getLoginString() {
    loginstring = getCookie("loginstring");
    username = getCookie("username");
}
 
function setLoginString() {
    setCookie("loginstring", loginstring, 1);
    setCookie("username", username, 1);
}
 
function resetLoginString() {
    setCookie("loginstring""""-1");
    setCookie("username""""-1");
}
 
function checkLoginString() {
    if (loginstring == "") {
        history.back();
    }
}
 
cs





 마지막으로 작성된 기능들에 대해 login.html에서 연결해보도록 하겠습니다.



1
2
3
4
5
6
7
8
9
10
11
 
        <script>
            $(document).ready(function() {
                $("#registerBtn").click(function() {
                    location.href = "join.html";
                });
                $("#loginBtn").click(doLogin);
                $("#adminbtn").click(goAdmin);
            });
       </script>
 
cs





 로그인 화면에서 계정에 대한 로그인을 시도해서 Login Success 가 뜨는 지 확인합니다.

 다음으로 넘어가는 timeline.html이 부재로 미완성이라는 것을 염두해 둡니다.
















여기까지해서 간단한 로그인 및 계정 생성을 구현하였습니다.



다음 장에서 타임라인에 대한 구현을 진행하도록 하겠습니다.



질문 사항은 댓글이나 DISQUS를 통해 달아주세요.





* 본 포스팅은 이재근 등 4명 저 "Fast Web Service Build up: 웹 서비스를 쉽고 빠르게 구축하는 기술" 저서를 참고하여 작성하였습니다



다른 카테고리의 글 목록

Web/WebPage 카테고리의 포스트를 톺아봅니다
조회수 확인

이전 장에 이어서 계속해서 api를 구현하도록 하겠습니다.




연결된 강좌이므로 아래 링크대로 따라주시면 이해가 더 쉬우실 것 입니다.

===========================================


1. 개발환경설정

2. CSS & Bootstrap 

3. CSS 선택자(Selector)

4. CSS 요소(Element)

5. Bootstrap Part. 1

6. Bootstrap Part. 2

7. 실전 예제 - 개인용 포트폴리오 페이지 제작

8. Python & Django

9. Django

10. 장고(Django) 프로젝트

11. JavaScript & jQuery

12. 실전 웹 프로젝트(예제)


13. 실전 웹 프로젝트(Timeline) Server Part.1


===========================================








17. 다음으로는 사용자 목록을 가져오는 기능을 구현하도록 하겠습니다.





 - 사용자 목록 가져오기: api/user/list/


 URI

 Method 

 api/user/list/

 GET 

 가입된 사용자 목록을 보여주는 API 입니다.

 Input Parameter

 None

 Output

 회원 프로필 리스트

 


urls.py에 코드를 추가합니다.



1
    url(r'^api/user/(?P<method>list)/$', user_view),
cs





user_view에 추가해주도록 합니다. 생성 부분과 수정 부분의 소스는 생략했습니다.


1
2
3
4
5
6
7
8
9
def user_view(request, method):
    if method == 'create' and request.method == 'POST':
        skip this source
    elif method == 'update' and request.method == 'POST':
        skip this source
    elif method == 'list':
        users = UserProfile.objects.all()
    else:
        return HttpResponse('bad request', status=400)
cs




views.py를 위와 같이 작성해 주시고, models.py를 작성해야합니다. 


models.py의 class UserProfile 부분을 아래와 같이 수정해줍니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class UserProfile(models.Model):
    user = models.OneToOneField(User)
    nickname = models.CharField(max_length=128)
    comment = models.TextField()
    country = models.CharField(max_length=128, blank=True)
    url = models.CharField(max_length=128, blank=True)
    ignores = models.ManyToManyField(User, related_name='ignore_set', blank=True, null=True)
    
    def __unicode__(self):
        return "%s" % (self.user,)
    
    def serialize(self):
        data = {
            'user': self.user_id,
            'username': self.user.username,
            'nickname': self.nickname,
            'comment': self.comment,
            'country': self.country,
            'url': self.url,
            'ignores': [],
        }
        return data
    
cs




다시 views.py로 돌아와 아래 코드를 elif list 부분에 추가해줍니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import json
 
def user_view(request, method):
    if method == 'create' and request.method == 'POST':
        skip this source
    elif method == 'update' and request.method == 'POST':
        skip this source
    
    elif method == 'list':
        users = UserProfile.objects.all()
        serialized = []
        for u in users:
            serialized.append(u.serialize())
        j = json.dumps(serialized, ensure_ascil=False)
        return HttpResponse(j, content_type='application/json; charset=utf-8')
        
    else:
        return HttpResponse('bad request', status=400)
cs






이제 사용자 목록을 확인 할 수 있게 되었습니다. 그런데 뭔가 복잡해 보이기 때문에 모듈화를 해줘야 할 것 같습니다.

views.py 하단에 아래 코드를 추가합니다.


1
2
3
4
5
6
7
8
 
def serialize(objs):
    return map(lambda x:x.serialize(), objs)
 
def toJSON(objs, status=200):
    j = json.dumps(objs, encoding="utf-8", ensure_ascii=False)
    return HttpResponse(j, status=status, content_type='application/json; charset=utf-8')
 
cs


그 다음 user_view 부분을 아래와 같이 수정해줍니다.



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
import json
 
def user_view(request, method):
    if method == 'create' and request.method == 'POST':
        try:
            username = request.POST.get('username')
            password = request.POST.get('password')
            if User.objects.filter(username__exact=username).count():
                return HttpResponse('duplicate id'400)
            user = User.objects.create_user(username, password=password)
            user.first_name = request.POST.get('name''')
            user.save()
            profile = UserProfile()
            profile.user = user
            profile.save()
            return toJSON({'status':'create Success'})
        except:
            return toJSON({'status':'create failed'}, 400)
    elif method == 'update' and request.method == 'POST':
        try:
            username = request.POST.get('username')
            password = request.POST.get('password')
            newpassword = request.POST.get('newpassword')
            user = User.objects.get(username__exact = username)
            if user.check_password(password) is False:
                return toJSON({'status':'wrong password'}, 400)
            else:
                user.set_password(newpassword)
                user.first_name = request.POST.get('name', user.first_name)
                user.save()
        except:
            return toJSON({'status':'bad request'}, 400)
        return toJSON({'status':'updated'})
    
    elif method == 'list':
        users = UserProfile.objects.all()
        return toJSON(serialize(users))
        
    else:
        return toJSON({'status':'bad request'}, 400)
 
cs









18. 사용자에 대한 api 구현은 끝이 났습니다. 다음으로는 타임라인 API를 작성하도록 하겠습니다.






 - 타임라인 목록 가져오기: api/timeline/


 URI

 Method 

 api/timeline/

 GET 

 타임라인 목록을 가져오는 API(로그인 필요)

 Input Parameter

 page - 가져오고 싶은 페이지

 per_page - 한 페이지에 몇 개씩 볼 것인가


 Output

 {

    'total_page': 전체 페이지 수,

    'total_count': 전체 메시지 수,

    'messages': [{

        메시지 정보

    }]

  }







먼저 UserProfile과 마찬가지로 Message 모델serialize 함수를 추가해 줍니다. models.py를 열어서 추가합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
class Message(models.Model):
    user = models.ForeignKey(User)
    message = models.CharField(max_length=128)
    created = models.DateTimeField(auto_now_add=True)
 
    def serialize(self):
        data = {
            'id': self.id,
            'user': self.user_id,
            'username': self.user.username,
            'liked': self.like_set.count(),
            'message': self.message,
            'created': self.created.ctime()
        }
    
        return data
 
cs






다음으로 timeline_view를 수정해줍니다.



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
 
from django.core.paginator import Paginator
 
@need_auth
def timeline_view(request):
    messages = Message.objects.order_by('-created').all()
    
    try:
        tweet_per_page = int(request.GET.get('per_page'10))
        page_num = int(request.GET.get('page'1))
        
        pages = Paginator(messages, tweet_per_page)
        
        resp = {
            'total_page': pages.num_pages,
            'total_count': pages.count,
            'messages': serialize(pages.page(page_num).object_list)
        }
        
        return toJSON(resp)
    
    except:
        resp = {
            'status''pagination error'
        }
        return toJSON(resp, 400)
 
cs








19. 다음으로 타임라인에 메시지 남기기 기능을 구현하겠습니다.





 - 타임라인에 메시지 남기기: api/timeline/create/


 URI

 Method 

 api/timeline/create/

 POST 

 타임라인에 메시지를 작성하는 API(로그인 필요)

 Input Parameter

 

  message - 가져 오고 싶은 페이지


 Output

  - 성공시

    {'status': 'create success'}


  - 실패시

    {'status': 'bad request'}







urls.py에 아래 코드를 추가합니다.



1
2
 
    url(r'^api/timeline/create/$', message_create_view),
cs




다음으로 views.py에 아래 코드를 추가합니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
@need_auth
def message_create_view(request):
    if request.method != 'POST':
        return toJSON({'status''bad request'}, 400)
    
    message = Message()
    
    try:
        message.user = request.user
        message.message = request.POST.get('message''')
        message.save()
        
        return toJSON({'status''create success'})
        
    except:
        return toJSON({'status''bad request'}, 400)
cs




 타임라인 글 생성이 잘 되는지 확인하기 위해 간단히 Rest Console로 테스트 해보겠습니다.


 Request URI를 아래와 같이 설정하고 


  http://localhost:8000/api/timeline/create/



 파라미터를 아래와 같이 설정해줍니다.






설정 뒤 Send 를 눌러서 Response Body 탭을 눌러 아래와 같이 떴는지 확인합니다.














20. 특정 메시지 조회 기능을 구현하도록 하겠습니다.






 - 타임라인에서 특정 메시지 조회: api/timeline/메시지ID/


 URI

 Method 

 api/timeline/메시지ID/

 GET 

 타임라인에 있는 메시지를 조회하는 API(로그인 필요)

 Input Parameter


 None


 Output

 - 성공시

    메시지 출력

 

 - 실패시

   {'status': 'not found'}







urls.py에 아래와 같은 코드를 입력합니다.



1
2
   url(r'^api/timeline/(?P<num>\d+)/$', message_view),
 
cs



views.py에서 아래 코드를 추가해줍니다.


1
2
3
4
5
6
7
8
9
10
11
@need_auth
def message_view(request, num):
    try:
        message = Message.objects.get(id = num)
        
        return toJSON(message.serialize())
        
    except:
        return toJSON({'status''not found'}, 400)
    
    return HttpResponse(None)
cs




아까 작성한 메시지를 조회하기 위해 Rest Console을 통해 조회합니다.


http://localhost:8000/api/timeline/1/ 를 URI로 입력하여 파라미터를 지워준 뒤, Send 해서 아래와 같이 뜨는 지 확인합니다.


똑같이 뜨는게 아니라 자신의 아이디나 올린 날짜등은 다를 수 있습니다. JSON으로 내뱉는 게 확실히 나오는 지 확인하기 위함 입니다.













21. 특정 메시지 삭제 기능을 구현하도록 하겠습니다.







 - 타임라인에서 특정 메시지 삭제: api/timeline/메시지ID/delete/


 URI

 Method 

 api/timeline/메시지ID/delete/

 POST 

 타임라인에 메시지를 삭제하는 API(로그인 필요)

 Input Parameter


 None


 Output

 - 성공시

    {'status': 'deleted'}

 

 - 실패시

   {'status': 'forbidden'}

   {'status': 'not found'}






urls.py에 아래와 같은 코드를 입력합니다.


1
2
    url(r'^api/timeline/(?P<num>\d+)/delete/$', message_delete_view),
 
cs

 


views.py에서 아래 코드를 추가해줍니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
@need_auth
def message_delete_view(request, num):
    try:
        message = Message.objects.get(id = num)
        if message.user == request.user:
            message.delete()
            return toJSON({'status''deleted'})
        else:
            return toJSON({'status''forbidden'}, 401)
        
    except:
        return toJSON({'status''not found'}, 400)
 
cs





Rest Console로 생성하였던 타임라인 메시지를 삭제합니다. 삭제 기능이 잘 되는지 반응을 살펴보시기 바랍니다. 일일이 확인하는 작업을 올리진 않겠습니다. 후에 클라이언트 페이지를 만들면서도 확인 가능하나 구현 후 바로 확인해보시길 바랍니다.









22. 특정 메시지에 Like 표시하는 기능을 구현하도록 하겠습니다.







 - 타임라인에서 특정 메시지 Like 표시: api/timeline/메시지ID/like/


 URI

 Method 

 api/timeline/메시지ID/like/

 POST 

 특정 메시지에 Like 표시하는 API(로그인 필요)

 Input Parameter


 None


 Output

 - 성공시

    {'status': 'created'}

 

 - 실패시

   {'status': 'bad request'}




urls.py에 아래와 같은 코드를 입력합니다.

   


1
2
    url(r'^api/timeline/(?P<num>\d+)/like/$', like_view),
 
cs



views.py에서 아래 코드를 추가해줍니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
@need_auth
def like_view(request, num):
    try:
        message = Message.objects.get(id=num)
        like = Like()
        like.user = request.user
        like.message = message
        like.save()
        
    except:
        return toJSON({'status''bad request'}, 400)
    
    return toJSON({'status''created'})
 
 
cs











23. 타임라인에서 검색하기 기능을 구현하도록 하겠습니다.







 - 타임라인에서 검색하기: api/timeline/find/


 URI

 Method 

 api/timeline/find/

 GET 

 타임라인에 메시지를 검색하는 API(로그인 필요)

 Input Parameter


 query - 검색하고 싶은 검색어


 Output

 - 성공시: 검색한 단어가 포함된 메시지 

 - 실패시: {'status': 'no'}





urls.py에 아래와 같은 코드를 입력합니다.

   


1
2
 
    url(r'^api/timeline/find/$', find_view),
cs

 


views.py에서 아래 코드를 추가해줍니다.



1
2
3
4
5
6
7
8
@need_auth
def find_view(request):
    query = request.GET.get('query''')
    
    result = Message.objects.filter(Q(message__contains=query)|Q(user__userprofile__nickname__contains=query))
 
    return toJSON(serialize(result))
 
cs








24. 다음으로 사용자의 이름 수정 기능을 구현하도록 하겠습니다.





 - 사용자 이름 변경 or 수정하기 : api/user/name/


 URI

 Method 

 api/user/name/

 GET, POST

 현재 로그인한 사용자의 이름을 변경하거나 가져오는 API (로그인 필요)

 Input Parameter

POST: 이름 수정

 name - 바꾸고자 하는 이름


GET: 이름 가져오기

 None


 Output

 1. 이름 수정 시(POST)

  - 성공시: {'status': 'updated'}

  - 실패시: {'status': 'bad request'}


 2. 이름 가져올 때(GET)

  {'name': 이름}






urls.py에 아래와 같은 코드를 입력합니다.

   

1
2
 
    url(r'^api/user/name/$', name_view),
cs




views.py에서 아래 코드를 추가해줍니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
@need_auth
def name_view(request):
    if request.method == 'GET':
        data = {
            'name': request.user.first_name,
        }
        
        return toJSON(data)
    
    if request.method == 'POST':
        try:
            name = request.POST.get('name')
            request.user.first_name = name
            request.user.save()
            
            return toJSON({'status''updated'})
            
        except:
            return toJSON({'status''bad request'}, 400)
cs










25. 암호를 확인하고 설정하는 API를 구현하도록 하겠습니다.






 - 암호를 확인하고 설정하기 : api/user/checkpassword/, api/user/setpassword/


 URI

 Method 

 api/user/checkpassword/

 POST

 현재 로그인 한 사용자의 비밀번호가 맞는지 확인하는 API (로그인 필요)

 Input Parameter


 password - 비밀번호


 Output

 

 비밀번호 맞을 때: {'status': 'ok'}


 비밀번호 틀릴 때: {'status': 'no'}





 URI

 Method 

 api/user/setpassword/

 POST

 현재 로그인 한 사용자의 비밀번호를 변경하는 API (로그인 필요)

 Input Parameter


 password - 비밀번호


 Output

 

 비밀번호 변경 성공 시: {'status': 'ok'}






urls.py에 아래와 같은 코드를 입력합니다.



1
2
3
    url(r'^api/user/checkpassword/$', checkpassword_view),
    url(r'^api/user/setpassword/$', setpassword_view),
    
cs



views.py에서 아래 코드를 추가해줍니다.


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
        
@need_auth
def checkpassword_view(request):
    try:
        password = request.POST.get('password')
        if request.user.check_password(password):
            return toJSON({'status''OK'})
        
    except:
        pass
    return toJSON({'status''no'})
 
@need_auth
def setpassword_view(request):
    try:
        password = request.POST.get('password')
        if password:
            request.user.set_password(password)
            request.user.save()
            return toJSON({'status''OK'})
        
    except:
        pass
    
    return toJSON({'status''no'})
cs







26. Profile을 조회하는 API를 구현하도록 하겠습니다.






 - Profile 조회하기 : api/profile/사용자아이디/


 URI

 Method 

 api/profile/사용자아이디/

 GET

 URI에 명시된 사용자의 프로필을 가져오는 API

 Input Parameter


 None


 Output

 

 URI에 명시된 사용자의 프로필





urls.py에 아래와 같은 코드를 입력합니다.

 

1
2
    url(r'^api/profile/(?P<username>\w+)/$', profile_view),
 
cs




views.py에서 아래 코드를 추가해줍니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
 
 
@need_auth
def profile_view(request, username):
    if request.method == 'GET':
        try:
            userprofile = User.objects.get(username=username).userprofile
            return toJSON(userprofile.serialize())
            
        except:
            return toJSON({'status''not found'}, 400)
        
 
cs










27. 현재 로그인한 사용자의 프로필을 가져오거나 수정하는 API를 구현하도록 하겠습니다.






urls.py에 아래와 같은 코드를 입력합니다.

 

1
2
3
4
    url(r'^api/profile/$', profile_view),
 
 
 
cs




views.py에서 아래 코드를 추가해줍니다. 기존의 profile_view에 username 파라미터가 없을 때, POST 형식으로 받았을 때를 추가하겠습니다.



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
 
 
@need_auth
def profile_view(request, username=None):
    if username == None:
        username = request.user
    
    if request.method == 'GET':
        try:
            userprofile = User.objects.get(username=username).userprofile
            return toJSON(userprofile.serialize())
            
        except:
            return toJSON({'status''not found'}, 400)
        
    elif request.method == 'POST':
        profile = request.user.userprofile
        profile.nickname = request.POST.get('nickname', profile.nickname)
        profile.comment = request.POST.get('comment', profile.comment)
        profile.country = request.POST.get('country', profile.country)
        profile.url = request.POST.get('url', profile.url)
        ignores = request.POST.get('ignore', None)
        if ignores:
            ignores = json.loads(ignores)
            profile.set_ignorelist(ignores)
        
        profile.save()
        
        return toJSON({'status''updated'})
        
cs





 다음으로 ignore 속성에 대한 설정이 없었으므로, models.py를 수정하도록 하겠습니다.



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
class UserProfile(models.Model):
    user = models.OneToOneField(User)
    nickname = models.CharField(max_length=128)
    comment = models.TextField()
    country = models.CharField(max_length=128, blank=True)
    url = models.CharField(max_length=128, blank=True)
    ignores = models.ManyToManyField(User, related_name='ignore_set', blank=True, null=True)
    
    def __unicode__(self):
        return "%s" % (self.user,)
    
    def get_ignorelist(self):
        ignores = []
        for k in self.ignores.all():
            ignores.append(k.id)
        return ignores
    
    def set_ignorelist(self, ignores):
        self.ignores = []
        for k in ignores:
            try:
                ignore = User.objects.get(id = k)
                self.ignores.add(ignore)
                self.save()
                
            except:
                pass
    def serialize(self):
        data = {
            'user': self.user_id,
            'username': self.user.username,
            'nickname': self.nickname,
            'comment': self.comment,
            'country': self.country,
            'url': self.url,
            'ignores': self.get_ignorelist(),
        }
        return data
 
 
 
cs





마지막으로 timeline_view를 수정하여서 api 구현을 완료합니다.




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
 
@need_auth
def timeline_view(request):
    messages = Message.objects.order_by('-created').all()
    ignore = request.user.userprofile.get_ignorelist()
    messages = messages.exclude(user__id__in = ignore)
    
    try:
        tweet_per_page = int(request.GET.get('per_page'10))
        page_num = int(request.GET.get('page'1))
        
        pages = Paginator(messages, tweet_per_page)
        
        resp = {
            'total_page': pages.num_pages,
            'total_count': pages.count,
            'messages': serialize(pages.page(page_num).object_list)
        }
        
        return toJSON(resp)
    
    except:
        resp = {
            'status''pagination error'
        }
        return toJSON(resp, 400)
 
cs










28. 정상적으로 로그인 되었는지 확인하는 API를 구현하도록 하겠습니다.





 - 로그인 확인하기 : api/login/


 URI

 Method 

 api/login/

 GET

 로그인 테스트에 사용할 API

 Input Parameter


 None


 Output

 

 {'status': 'ok', ,'user': 로그인 한 사용자의 프로필 }




urls.py에 아래와 같은 코드를 입력합니다.

 

1
2
 
    url(r'^api/login/$', login_view),
cs




views.py에서 아래 코드를 추가해줍니다.


1
2
3
4
@need_auth
def login_view(request):
    return toJSON({'status''OK''user':request.user.userprofile.serialize()})
 
cs









28. 마지막으로 Template Page를 설정하겠습니다.






 지금까지 우리는 Django를 이용해 API를 개발하였습니다. 여기에는 템플릿을 사용하지도 않았고 HTML을 쓰지도 않았습니다.


 하지만 실제 서비스를 운영하려면 API만 가지고는 불가능 합니다. 아래 방법을 통해 html 페이지를 제공하기 위한 방법을 확인하면서 서버 부분을 마치겠습니다.



urls.py에 아래와 같은 코드를 입력합니다.

 


1
2
 
    url(r'^home/(?P<page>\w+).html$', serve_html),
cs





views.py에서 아래 코드를 추가해줍니다.



1
2
3
4
5
from django.shortcuts import render_to_response
 
def serve_html(reqeust, page):
    return render_to_response(page+'.html')
 
cs





여기까지 작성으로 Server 딴에서의 작업은 끝이 났습니다.



모든 기능에 이상이 없는지 체크하시고 다음 장에서 뵙도록 하겠습니다.




질문 사항은 댓글/ DISQUS를 통해 달아주세요.



* 본 포스팅은 이재근 등 4명 저 "Fast Web Service Build up: 웹 서비스를 쉽고 빠르게 구축하는 기술" 저서를 참고하여 작성하였습니다


다른 카테고리의 글 목록

Web/WebPage 카테고리의 포스트를 톺아봅니다
조회수 확인

이전 장에서의 예제를 뒤로하고 타임라인 서비스를 개발해보도록 하겠습니다.



 




연결된 강좌이므로 아래 링크대로 따라주시면 이해가 더 쉬우실 것 입니다.

===========================================


1. 개발환경설정

2. CSS & Bootstrap 

3. CSS 선택자(Selector)

4. CSS 요소(Element)

5. Bootstrap Part. 1

6. Bootstrap Part. 2

7. 실전 예제 - 개인용 포트폴리오 페이지 제작

8. Python & Django

9. Django

10. 장고(Django) 프로젝트

11. JavaScript & jQuery

12. 실전 웹 프로젝트(예제)


13. 실전 웹 프로젝트(Timeline) Server Part.1


===========================================






흔히 쓰이는 페이스 북의 기능 축소판을 구현한다고 보시면 됩니다.


 구현하기 위한 기능들은 아래와 같습니다.

 - 글 관리

 - 글 쓰기

 - 글 지우기

 - 글 Like 하기

 - 회원 관리

 - 회원 가입

 - 비밀번호 수정

 - 정보 수정

 - 프로필 관리

 - 프로필 등록

 - 프로필 수정

 - 프로필 조회

 - 로그인






서버 구현으로 본격적으로 시작하겠습니다.




1. cmd 창을 열어 장고 프로젝트 생성합니다.




 cd \

 mkdir work

 cd work

 django-admin.py startproject timelineproject

 cd timelineproject

 manage.py runserver







 장고(Django)에서는 기본적으로 8000번 포트를 사용하여 서버를 구동합니다. 따라서 자신의 컴퓨터를 뜻하는 127.0.0.1의 8000번 포트라는 뜻의 127.0.0.1:8000으로 접속하면 아래와 같은 화면을 볼 수 있습니다.









2. 을 생성하겠습니다.




 manage.py startapp timeline

 cd timeline

 dir











3. 프로젝트를 설정해야 합니다. Aptana Studio를 열어서 콘솔에서 만든 프로젝트를 추가합니다.






 File -> New -> PyDev Prject 를 선택합니다.







name은 TimelineProject로 지정하고 Use default 를 체크해제하여 방금 생성한 폴더 경로를 지정해줍니다. 다음 Finish.













4. 생성된 프로젝트를 오른쪽 클릭하여 PyDev-> Set as Django Project를 선택합니다.

















5. settings.py 를 수정합니다. 해당되는 부분을 아래와 같이 수정합니다.





 (* Databases, Installed_apps, Middleware_classes, Staticfiles_dirs,template_dirs )


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
 
DATABASES = {
    'default': {
        'ENGINE''django.db.backends.sqlite3'# Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME''database',                      # Or path to database file if using sqlite3.
        'USER''',                      # Not used with sqlite3.
        'PASSWORD''',                  # Not used with sqlite3.
        'HOST''',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT''',                      # Set to empty string for default. Not used with sqlite3.
    }
}
 
 
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
    'timeline',
)
 
MIDDLEWARE_CLASSES = (
    'django.middleware.common.CommonMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    #'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
cs




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import os
# Additional locations of static files
STATICFILES_DIRS = (
    # Put strings here, like "/home/html/static" or "C:/www/django/static".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
    os.path.join(os.path.dirname(__file__), '..''static'),
)
 
 
TEMPLATE_DIRS = (
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
    os.path.join(os.path.dirname(__file__), '..''templates'),
)
cs











6. 모델을 생성할 차례입니다. Models.py를 열어 작성합니다.







1
2
3
4
5
6
7
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
 
class UserProfile(models.Model):
    user = models.OneToOneField(User)
 
cs




 User 모델을 사용하기 위해 import를 하고 UserProfile 모델은 User에서 제공하지 않는 정보를 다루기 위한 모델로 1:1의 관계를 갖습니다. 

 

 다음으로 UserProfile에 들어갈 정보에 대한 필드(nickname, comment, country, url, ignores)를 작성하겠습니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
 
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
 
class UserProfile(models.Model):
    user = models.OneToOneField(User)
    nickname = models.CharField(max_length = 128)
    comment = models.TextField()
    country = models.CharField(max_length = 128, blank = True)
    url = models.CharField(max_length = 128, blank = True)
    ignores = models.ManyToManyField(User, related_name = 'ignore_set', blank = True, null = True)
    
cs





 다음으로 사용자가 쓴 메시지가 저장될 Message 모델을 만들어 보도록 하겠습니다.



1
2
3
4
5
class Message(models.Model):
    user = models.ForeignKey(User)
    message = models.CharField(max_length = 128)
    created = models.DateTimeField(auto_now_add = True)
    
cs


 각 사용자가 보낸 Message 와의 관계를 통해 메시지가 누가 언제 작성했는지 알수 있습니다.





 다음으로 Like 모델을 작성하겠습니다.



1
2
3
4
class Like(models.Model):
    user = models.ForeignKey(User)
    message = models.ForeignKey('Message')
    
cs




 다음으로 콘솔에서 mange.py syncdb를 실행해서 모델이 정상적으로 생성되었는지 확인합니다. 간단히 계정 생성을 해주시길 바랍니다.



 







7. 관리자 기능을 제공하기 위해 urls.py를 수정합니다. 간단히 아래와 같이 주석 제거해주시면 됩니다.







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from django.conf.urls import patterns, include, url
 
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
 
urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'timelineproject.views.home', name='home'),
    # url(r'^timelineproject/', include('timelineproject.foo.urls')),
 
    # Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
 
    # Uncomment the next line to enable the admin:
    url(r'^admin/', include(admin.site.urls)),
)
 
cs









8. admin.py 파일을 만들어서 각 모델을 매핑(Mapping)해줘야 합니다. 아래와 같이 작성하여서 app 폴더에 넣어줍니다.






 admin.site.register 함수를 통해 관리자 모듈에 등록할 모델을 추가하면 됩니다. User 모듈의 경우 자동으로 admin에 추가되어 있으니 걱정하지 않으셔도 됩니다.




1
2
3
4
5
6
7
 
from django.contrib import admin
from timeline.models import *
 
admin.site.register(Message)
admin.site.register(Like)
admin.site.register(UserProfile)
cs









9. admin 사이트에 접속하여 제대로 매핑이 되어 아래처럼 나오는 지 확인합니다.

 https://localhost:8000/admin/





















10. 간단하게 User Profile을 생성해줍니다.











기본 폼으로 나오기 때문에 어떤 사용자가 추가되었는 지 자세히 나오지 않습니다. 아래코드를 수정하여 화면을 바꿔봅시다.



1
2
3
4
5
6
7
8
9
10
class UserProfile(models.Model):
    user = models.OneToOneField(User)
    nickname = models.CharField(max_length = 128)
    comment = models.TextField()
    country = models.CharField(max_length = 128, blank = True)
    url = models.CharField(max_length = 128, blank = True)
    ignores = models.ManyToManyField(User, related_name = 'ignore_set', blank = True, null = True)
    
    def __unicode__(self):
        return "%s"%(self.user,)
cs





__unicode__ 부분 추가로 사용자 아이디를 보이게 했습니다.















11. 다음으로 로그인 구현을 하도록 하겠습니다. urls.py를 열어 추가하도록 하겠습니다.







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from django.conf.urls import patterns, include, url
from timeline.views import *
 
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
 
urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'timelineproject.views.home', name='home'),
    # url(r'^timelineproject/', include('timelineproject.foo.urls')),
 
    # Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
 
    # Uncomment the next line to enable the admin:
    url(r'^admin/', include(admin.site.urls)),
    
    url(r'^api/timeline/$', timeline_view),
)
 
cs




 urls.py에 입력한 view를 생성하기 위해 views.py를 열어 timeline_view를 생성합니다.


1
2
3
4
5
6
 
from django.http import HttpResponse
from timeline.models import *
 
def timeline_view(request):
    return HttpResponse('Hello World')
cs





 접속 결과 간단한 View가 생성되었습니다.









 하지만 회원제로 운영해야 하므로 HTTP Basic Authentication 인증을 통해 인증 기능을 추가하도록 하겠습니다.



 단계별로 인증 절차를 살펴봅시다.

  1) 사용자는 브라우저를 통해 서버에 페이지를 요청

  2) 서버는 사용자의 요청에 인증 정보가 들어 있는지 확인

  3) 인증 정보가 확인이 되어 올바르다면 요청한 페이지를 전송

  4) 인증 정보가 없거나 틀리면 사용자에게 인증 요청 페이지를 전송






 12. 401 에러를 통해 페이지를 수정합니다.






1
2
3
4
5
6
7
8
9
10
from django.http import HttpResponse
from timeline.models import *
 
def timeline_view(request):
    response = HttpResponse()
    
    response.status_code = 401
    response['WWW-Authenticate'= 'Basic realm="timeLine Service"'
    
    return response
cs





 인증 화면에 대해 묻는 화면으로 바뀌었습니다.














13. 인증을 하기위한 인증 정보를 볼수 있는 코드를 더 추가하여 결과를 살펴보도록 하겠습니다.





* 10번째 라인의 if 문을 유심히 살펴보세요! 자신의 아이디와 비번을 입력하라는 뜻입니다!


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from django.http import HttpResponse
from timeline.models import *
import base64
 
def timeline_view(request):
    if 'HTTP_AUTHORIZATION' in request.META:
        auth = request.META['HTTP_AUTHORIZATION']
        key = base64.decodestring(auth.split(' ')[1])
        id, pw = key.split(':')
        if id == 'your_id' and pw == 'your_pwd':
            return HttpResponse('Hello id: %s, pwd: %s' %(id, pw))
    
    response = HttpResponse()
    
    response.status_code = 401
    response['WWW-Authenticate'= 'Basic realm="timeLine Service"'
    
    return response
cs




 계정을 입력해서 로그인이 되면 아래와 같은 화면이 뜹니다.





하지만 하나의 계정만으로 인증이 가능한 위 방법은 비효율적입니다.


데코레이터를 만들어서 위와 같은 인증시 문제를 풀어보도록 하겠습니다.







14. 아래와 같은 코드를 views.py에 작성합니다.







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
from django.http import HttpResponse
from django.contrib.auth import authenticate, login, logout
from timeline.models import *
import base64
 
def need_auth(functor):
    def try_auth(request, *args, **kwargs):
        if 'HTTP_AUTHORIZATION' in request.META:
            basicauth = request.META['HTTP_AUTHORIZATION']
            user = None
            try:
                b64key = basicauth.split(' ')[1]
                key = base64.decodestring(b64key)
                (username,pw) = key.split(':')
        
                user = authenticate(username=username,password=pw)
            except:
                pass
 
            if user is not None:
                login(request, user)
                request.META['user'= user
                return functor(request, *args, **kwargs)
 
        logout(request)
        response = HttpResponse()
        response.status_code = 401
        response['WWW-Authenticate'= 'Basic realm="timeLine Service"'
        return response
    return try_auth
 
@need_auth
def timeline_view(request):
    return HttpResponse('Hello world')
cs










15. 이제 본격적으로 API를 구현 할 차례입니다. 사용자 추가하기 API부터 생성해보도록 하겠습니다.






 - 사용자 추가하기: api/user/create/


 URI

 Method 

 api/user/create/

 POST 

 사용자를 추가하는 API 입니다. 아이디와 비밀번호를 파라미터로 받고 유저를 만들어 줍니다.

 Input Parameter

 username - 만들고자 하는 아이디

 password - 비밀번호

 name - 사용자 이름(optional)


 ex)

 username = palpit

 password = papitpw

 name = Yeonsu

 Output

 1. 성공 시 { 'status': 'create success' }

 2. 중복 아이디 {'status': 'duplicate id'} - 400

 3. 에러 (잘못된 파라미터 , 여백 등) { 'status': 'create fail' } - 400





먼저 url을 추가하기 위해 urls.py 을 수정하도록 하겠습니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from django.conf.urls import patterns, include, url
from timeline.views import *
 
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
 
urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'timelineproject.views.home', name='home'),
    # url(r'^timelineproject/', include('timelineproject.foo.urls')),
 
    # Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
 
    # Uncomment the next line to enable the admin:
    url(r'^admin/', include(admin.site.urls)),
 
    url(r'^api/timeline/$', timeline_view),
    url(r'^api/user/(?P<method>create)/$', user_view),
)
 
cs



 다음으로 뷰에 user_view를 생성해 줍니다. views.py에 아래 코드를 추가합니다.


1
2
3
4
5
6
7
 
def user_view(request, method):
    if method == 'create' and request.method == 'POST':
        return HttpResponse('OK')
    else:
        return HttpResponse('bad request', status = 400)
 
cs




이제 접속을 통해 확인해보도록 하겠습니다. http://localhost:8000/api/user/create 에 접속합니다.







주소창에 입력해서는 GET 요청밖에 할 수 밖에 없으므로 bad request밖에 뜨지 않을 것입니다. 


이런 상황을 타파하기 위해서 Rest Console을 통해 해소할 것 입니다.



아래 주소를 통해 Rest Console을 설치합니다.

http://www.restconsole.com


Chrome에 추가하는 형식이므로 설치가 간단하므로 스크린 샷을 찍진 않았습니다.




설치를 다하셨다면 Rest Console을 실행을 시켜줍니다.



Rest Console의 Request URI에 요청하고자 하는 주소를 입력합니다.


http://localhost:8000/api/user/create/ 를 입력합니다. (뒤에 슬래시 붙이는 거에 유의하세요!)


전송방식은 POST로 설정하고 Send를 눌러주세요.







이렇게하면 자동으로 스크롤이 아래로 내려가면서 어떠한 결과가 나왔는 지 Response에 나오게 됩니다.




이제 본격적으로 user create api를 완성 해 보도록 하겠습니다.



Rest Console에 보면 Request Payload부분에 key : value 형식으로 원하는 파라미터를 넣어서 Request 할 수 있습니다. 생성하고자 하는 유저 이름과 비밀번호를 설정해놓겠습니다. (아직 Send 를 누르지 마세요)







views.py에 user_view부분을 아래와 같이 코드를 작성합니다.





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 
 
def user_view(request, method):
    if method == 'create' and request.method == 'POST':
        try:
            username = request.POST.get('username')
            password = request.POST.get('password')
            if User.objects.filter(username__exact=username).count():
                return HttpResponse('duplicate id'400)
            user = User.objects.create_user(username, password=password)
            user.first_name = request.POST.get('name''')
            user.save()
            profile = UserProfile()
            profile.user = user
            profile.save()
            return HttpResponse('create success')
        except:
            return HttpResponse('bad request', status=400)
    else:
        return HttpResponse('bad request', status=400)
 
cs




다음으로 Rest Console로 돌아와서 Send를 눌러 확인을 해보면 아래와 같이 Response Preview에 성공을 알리는 문구가 나와야 합니다.










16. 생성에 관한 부분을 생성했으니 이제 사용자 비밀번호 변경 api를 생성해보도록 하겠습니다.






 - 사용자 비밀번호 변경하기: api/user/update/


 URI

 Method 

 api/user/update/

 POST 

  아이디와 비밀번호를 기반으로 비밀번호를 수정 할 수 있는 API 입니다.

 Input Parameter

 username - 수정하고자 하는 아이디

 oldpassword - 수정 하고자 하는 아이디의 비밀번호

 newpassword - 바꾸고 싶은 비밀번호

 name - 사용자 이름(optional)


 Output

 1. 성공 시 { 'status': 'updated' }

 2. 잘못된 비밀번호 {'status': 'wrong password'} 

 3. 에러 (잘못된 파라미터 , 여백 등) { 'status': 'bad request' } 






 urls.py를 열어 아래 코드를 추가합니다.



1
2
    url(r'^api/user/(?P<method>update)/$', user_view),
 
cs




생성에 이어서 update 도 user_view를 통해 접근하므로, views.py에 user_view 부분에 코드를 추가해줍니다.

if 부분은 위에서 작성한 create 부분이므로 생략했습니다!!


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
def user_view(request, method):
    if method == 'create' and request.method == 'POST':
        skip this source...    
 
    elif method == 'update' and request.method == 'POST':
        try:
            username = request.POST.get('username')
            password = request.POST.get('password')
            newpassword = request.POST.get('newpassword')
            user = User.objects.get(username__exact = username)
            if user.check_password(password) is False:
                return HttpResponse('wrong password', status = 400)
            else:
                user.set_password(newpassword)
                user.first_name = request.POST.get('name', user.first_name)
                user.save()
        except:
            return HttpResponse('bad request', status=400)
        return HttpResponse('updated')
    else:
        return HttpResponse('bad request', status=400)
cs




 이렇게 작성을 하고 Rest Console을 통해 이전에 생성한 계정의 비밀번호를 변경해보도록 하겠습니다.



Request URI를 http://localhost:8000/api/user/update/ 설정하고


POST방식으로 그대로 유지하시고


Request Payload 에 newpassword를 추가해서 작성합니다.







send를 눌러 확인해봅니다.


아래 화면과 같이 updated란 문구가 나와야 정상 작동한 것입니다.










이번 장이 너무 길어져서 다음 장에서 이어서 서버 구축하겠습니다.




 * 본 포스팅은 이재근 등 4명 저 "Fast Web Service Build up: 웹 서비스를 쉽고 빠르게 구축하는 기술" 저서를 참고하여 작성하였습니다.

다른 카테고리의 글 목록

Web/WebPage 카테고리의 포스트를 톺아봅니다
조회수 확인

마지막 장으로 지금까지 배워온 기술들을 토대로 실전 프로젝트를 진행해보도록 하겠습니다.


먼저 실전 예제를 통해 몸을 풀어봅시다.



클라이언트 페이지를 생성할 것입니다.



1. 먼저 Aptana Studio에서 프로젝트를 생성합니다. 프로젝트 명은 ClientExample 로 지정합니다.











2. BootStrap 모듈을 프로젝트에 끌어다 놓습니다.








3. 프로젝트 오른쪽 클릭하여 html 파일을 생성합니다. (example.html)



4. 생성된 html 파일에 아래와 같이 기본 틀 코드를 입력합니다.



1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="utf-8"/>
        <title>Client Example</title>
    </head>
    <body>
        
    </body>
</html>
 
cs





5. 다음으로 bootstrap과 jquery를 추가해줘야 합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="utf-8"/>
        <title>Client Example</title>
        
        <link href="bootstrap/css/bootstrap.css" rel="stylesheet"/>
        <link href="bootstrap/css/bootstrap-responsive.css" rel="stylesheet"/>
    </head>
    <body>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
        <script src="bootstrap/js/bootstrap.js"></script>
    </body>
</html>
 
cs



 head 태그에 bootstrap css와 body 태그에 jquery js 및 bootstrap js를 추가해줬습니다.





6. 배경을 간단히 작성하겠습니다. Head 태그안에 작성하세요.




1
2
3
4
5
6
7
 
        
        <style type="text/css">
            body {
                background-color: #C0DEED;
            }
       </style>
cs






7. 네비게이션 메뉴를 추가 구성하겠습니다. Body 태그안에 작성하세요.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
        <!-- Start of NavBar -->
        <div class="navbar navbar-inverse navbar-fixed-top">
            <div class="navbar-inner">
                <div class="container">
                    <a class="brand" href="#">EXAMPLE</a>
                    <a class="btn btn-navbar" data-toggle="collapse" data-target="#navMenu">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </a>
                    <div class="nav-collapse" id="navMenu">
                        <ul class="nav">
                            <li class="active">
                                <a href="#">Home</a>
                            </li>
                            <li>
                                <a href="#">Menu2</a>
                            </li>
                        </ul>
                    </div>
                </div>
            </div>
        </div>
        <!-- End of NavBar -->
cs





 현재까지 작성된 페이지 입니다.








 data-toggle="collapse" 속성은 화면이 작아지는 경우 자동으로 메뉴를 접도록 해줍니다. 위 화면의 경우 화면이 작아져서 메뉴를 사용자가 펼친 경우입니다. 








8. 페이지의 메인은 부트스트랩의 hero-unit을 통해 구현하겠습니다.



1
2
3
4
5
6
7
8
9
        <!-- End of NavBar -->
        <div class="container">
            <div class="hero-unit">
                <h1>BlueBlackBerry</h1>
                <br>
                <h3>Stay Hungry, Stay Foolish...</h3>
            </div>
        </div>
        <!-- End of container -->
cs



 body 의 스타일을 추가합니다.



1
2
3
4
5
6
7
        <style type="text/css">
            body {
                background-color: #C0DEED;
                padding-top: 60px;
                padding-bottom: 40px;
            }
       </style>
cs








9. 이제 다음 라인으로 span4 속성을 이용한 3열 레이아웃을 만들어 보겠습니다.

 

코드 작성은 클래스 container 안에 hero-unit div가 끝나는 지점에 입력하겠습니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
            </div><!-- End of hero-unit -->
            <div class="row-fluid">
                <div class="span4">
                    <h2>Span 4</h2>
                    <input id="first" class="btn btn-danger" type="button" value="Section 2"/>
                </div>
                <div class="span4">
                    <h2>Span 4</h2>
                    <input id="second" class="btn btn-info" type="button" value="Alert Color"/>
                </div>
                <div class="span4">
                    <h2>Span 4</h2>
                    <input id="third" class="btn btn-primary" type="button" value="Progress"/>
                </div>
            </div>
cs




 span을 위한 style을 추가하겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        <style type="text/css">
            body {
                background-color: #C0DEED;
                padding-top: 60px;
                padding-bottom: 40px;
            }
            
            .row-fluid div[class*="span"] {
                background-color: white;
                -webkit-border-radius: 6px;
                -moz-border-radius: 6px;
                border-radius: 6px;
                margin-bottom: 10px !important;
                text-align: center;
            }
       </style>
cs











10. 다음 줄은 2열 컴포넌트 입니다. SPAN6을 사용해서 만들게 됩니다. row-fluid가 끝나는 부분에 작성하세요.



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
            <div class="row-fluid">
                <div class="span6">
                    <h2>SPAN 6</h2>
                    <div class="tabbable">
                        <!-- Only required for left/right tabs -->
                        <ul class="nav nav-tabs">
                            <li class="active">
                                <a href="#tab1" data-toggle="tab">Section 1</a>
                            </li>
                            <li>
                                <a href="#tab2" data-toggle="tab" id="section2">Section 2</a>
                            </li>
                        </ul>
                        <div class="tab-content">
                            <div class="tab-pane active" id="tab1">
                                Section 1.
                            </div>
                            <div class="tab-pane" id="tab2">
                                Section 2.
                            </div>
                        </div>
                    </div>
                </div>
                <div class="span6">
                    <h2>SPAN 6</h2>
                    <div class="progress">
                        <div id="bar" class="bar" style="width: 50px;"></div>
                    </div>
                    <div class="progress progress-danger progress-striped active">
                        <div id="bar" class="bar" style="width: 50px;"></div>
                    </div>
                </div>
            </div><!-- End of span6 row-->
        </div>
        <!-- End of container -->
cs












11. 마지막 1열 레이아웃 SPAN 12 부분입니다. span 6이 끝나는 부분에 작성하세요.



1
2
3
4
5
6
7
8
9
10
            </div><!-- End of span6 row-->
            <div class="row-fluid">
                <div class="span12">
                    <br>
                    <div class="alert alert-error fade in" id="alert">
                        <a class="close" data-dismiss="alert" href="#">x</a>
                        <strong>SPAN 12</strong>
                    </div>
                </div>
            </div><!-- ENd of span12 row -->
cs










12. 이제 스크립트 부분입니다. </body> 태그 바로 위에 작성하세요.




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
        <script src="bootstrap/js/bootstrap.js"></script>
        <script>
            $(document).ready(function() {
                
                $("#first").click(function() {
                    $("#section2").trigger("click");
                });
                
                $("#second").toggle(function() {
                    $("#alert").removeClass("alert-error");
                    $("#alert").addClass("alert-info");
                }, function() {
                    $("#alert").removeClass("alert-info");
                    $("#alert").addClass("alert_error");
                });
                
                $("#third").click(function() {
                    var width = $("#bar").width();
                    $(".bar").width(width + 50);
                });
            });
       </script>
cs









Span 4를 클릭하여 반응을 살펴봅니다.






 * 본 포스팅은 이재근 등 4명 저 "Fast Web Service Build up: 웹 서비스를 쉽고 빠르게 구축하는 기술" 저서를 참고하여 작성하였습니다

다른 카테고리의 글 목록

Web/WebPage 카테고리의 포스트를 톺아봅니다
조회수 확인

4.1 웹 스크립트 언어, JavaScript


 자바스크립트는 웹 프로그래밍을 위해서는 반드시 알아야할 언어입니다. HTML 만으로는 페이지를 표현하는 것 밖에 할 수 없기 때문에, 다양한 기능을 적용한 웹을 위해서 자바스크립트를 사용하기 때문입니다. 문법도 어렵지 않고, 바로바로 실행해 볼 수 있어서 쉬운 편에 속하는 언어입니다. 이 장에서는 자바스크립트의 문법과 활용을 알아보겠습니다.



 4.1.1 자바스크립트란?


  - 자바스크립트(JavaScript)는 HTML, CSS와 함께 브라우저가 서버나 컴파일러 등의 다른 외부 모듈 없이 직접 해석 할 수 있는 객체 기반 스크립트 언어 입니다. 객체기반이라는 말이 어려울 수 있으나 자바스크립트의 모든 것은 객체로 이루어져 있다는 것이고, 지금 어렵다해도 프로그래밍을 하면서 이해하리라 생각됩니다.



  4.1.1.1 개발환경의 설정

 

   본 프로젝트는 모두 이클립스와 Aptana Studio를 사용합니다. 이 장에서 설명할 JavaScript와 jQuery 역시 동일한 환경에서 작업할 것입니다. 



   JavaScript는 HTML 파일 내부에 <script> 태그로 내장할 수 있고, 확장자가 js인 파일로 외부에 작성한 뒤에 포함시킬 수도 있습니다. 브라우저가 직접 해석하기 때문에 컴파일 없이 바로바로 확인해 볼 수 있습니다.



   


  4.1.1.2 개발할 때의 주의사항

   

   자바스크립트를 이용한 개발을 할 때 주의사항은 크로스 브라우징입니다. 특히나 크롬을 이용해서 개발을 하다보면 많이 생기는 문제 중에 하나가 바로 인터넷 익스플로러에서 오류가 난다는 것 입니다. 자바스크립트는 무척 오래되었고, 많은 발전이 있었으며 방대한 언어입니다. 때문에 각 브라우저마다 호환되는 버전도 다르고 양식도 조금 다릅니다. 크롬에서 사용하는 자바스크립트 엔진은 무척이나 많은 것을 허용하기 때문에 대부분 스크립트가 잘 동작합니다. 





  4.1.1.3 개발 시작

   

   아래 순서대로 시작해보도록 하겠습니다.


    1) 우선 Aptana Studio를 실행하여 Web 프로젝트를 생성합니다.

    2) 프로젝트 이름은 Chapter4 라고 정합니다.

    3) 파일을 하나 추가합니다. HTML 포맷으로 선택하여 4-1이라 지정합니다.






 4.1.2 자바스크립트의 기초


  - 언어를 배울 때 기본은 문법입니다. 자바스크립트는 문법적인 부분에서 무척 자유로운 언어입니다. 어느 정도의 규칙을 무시해도 오류가 없거나, 오류가 있다고 해도 실행이 되는 부분이 있습니다. 문법을 작성시에 정확한 문법과 구조를 가지고 프로그래밍을 하는 습관을 들이는 것이 중요합니다.





  4.1.2.1 다양한 활용을 위한, Pop-up(Dialog)

   

   1) alert

  
    alert()은 경고 창을 화면에 띄우는 함수입니다.

    그럼 아래 코드를 <head> 태그 안에 작성하여 실행해봅시다.


  
1
2
3
        <script>
            alert("경고!!");
        </script>
cs






   실행을 시키면 아래처럼 경고창이 하나 뜨게됩니다.









   2) confirm

  
    confirm() 함수는 사용자에게 선택을 하게 하는 Dialog 함수입니다.

    사용자에게 Yes 혹은 No를 확인 받아 처리할 수 있도록 만들어졌습니다. 


1
2
3
4
        <script>
            confirm("당신은 학생입니까?");
        </script>
 
cs


 








   3) prompt

  
    prompt() 함수는 사용자에게 직접 값을 입력 받도록 하는 함수입니다.




1
2
3
4
5
 
        <script>
            prompt("당신의 나이를 알려주세요"0);
        </script>
 
cs












  4.1.2.2 C 혹은 JAVA와는 조금 다른 자바스크립트

   

   1) 주석


    그럼 이번에는 프로그래밍 언어에는 반드시 들어가 있는 특징인 주석에 대해서 알아보겠습니다. 주석은 브라우저가 코드를 한줄 한줄 해석할 때 해석하지 않고 그냥 넘어가도록 하는 부분을 만드는 것으로 사실 상 코드의 실행과는 관계없는 무시해버리는 상태로 만드는 것을 뜻합니다.



 

 // : 한 줄 주석

 

 /* */ : 범위 주석

 

 자바스크립트의 주석 문법






   2) 변수


    프로그래밍 언어들에서 다양한 값을 가질 수 있고 변경될 수 있는 개념을 가진 것을 변수라고 합니다. 이 변수는 모든 프로그래밍 언어의 기본이며 앞으로 가장 많이 다루게 될 것 입니다. 


1
2
3
4
5
6
7
<script>
    var numberVar;
    numberVar = 1;
 
    var stringVar;
    stringVar = "Test";
</script>
cs


    자바스크립트에서는 변수를 선언할 때 다른 언어와는 다르게 var형식으로 선언을 하고 있습니다. 정수나 문자열 배열 등 모든 변수에는 var를 통해 선언하게 됩니다.



    자바스크립트의 특징 중에 var 키워드를 생략할 수 있습니다. 추후에 Scope를 다루는 부분에서 다시 설명하겠지만 지금까지 선언되지 않았던 변수가 var 키워드 없이 사용되었다면 그 위치에서 선언된 것처럼 인식하게 됩니다.




   3) 자료형


    변수에서 설명한 것처럼 자바스크립트는 선언할 때 자료형을 지정하지 않습니다. 코르들 해석할 때 할당된 값을 가지고 형태를 나중에 자동으로 브라우저가 해석하여 지정하는 것 입니다.



    아래는 자바스크립트가 지원하는 자료형입니다.