본문 바로가기
[ 빅데이터 ]

[빅데이터] 설문조사 앱 만들기(pycharm, Django)

by 히앤님 2020. 10. 14.
반응형
SMALL

[ 설문조사 폼 만들기 ]

Survey App 개발 (폼처리,CSRF,redirect등)


1. survey 앱 만들기

python manage.py startapp survey

 

2. 폴더를 만든다.(survey > templates > survey > list.html)

 

3. views.py에서 list.html 연결

def home(request):
    print("list 모듈 동작!")
	return render(request, "survey/list.html")

 

4. urls.py에 첫페이지 연결

from survey import views

urlpatterns=[
    path('',views.home),
]

 

5. config/settings.py로 가서 survey 등록

 

6. config/urls.py 가서 path 등록 -> 메인으로 가서 등록

 

 

7. models.py에 모델 설정

Survey 모델) 설문조사 문항과 답변 4개, 설문 진행상태(y=진행중 n=종료)

Answer 모델) 응답에 대한 순번과 응답번호

 

설문조사를 만들어서 그거에 대한 답을 테이블에 저장하는 것

autofield : 자동으로 순번 상승

# 설문조사 문항
class Survey(models.Model):
    # 설문 인덱스
    survey_idx = models.AutoField(primary_key=True)

    # 설문 문제
    question = models.TextField(null=True)

    # 답 1~4
    ans1 = models.TextField(null=True)
    ans2 = models.TextField(null=True)
    ans3 = models.TextField(null=True)
    ans4 = models.TextField(null=True)

    # 설문진행상태(y=진행중, n=종료)
    status = models.CharField(max_length=1, default="y")


# ------------------------------------------------------------
class Answer(models.Model):
    # 응답 아이디(자동필드 증가)
    answer_idx = models.AutoField(primary_key=True)

    # 설문 아이디
    survey_idx = models.IntegerField()

    # 응답 번호
    num = models.IntegerField()

 

8. 관리자모드에 survey 등록

admin.py에 surveyAdmin 저장하기

from survey.models import Survey, Answer


class SurveyAdmin(admin.ModelAdmin):
    list_display = ("question", "ans1", "ans2", "ans3", "ans4", "status")


admin.site.register(Survey, SurveyAdmin)
admin.site.register(Answer)

 

 

9. 모델만들기

적용하기 -> migrations 파일이 만들어짐

python manage.py makemigrations  #마이그레이션 만들기
python manage.py migrate         #마이그레이션 적용하기

sqlite에 테이블 만들어짐

 

 

10. admin에 들어가보자. -> 로컬 호스트로 들어가자

python manage.py runserver

 

DHCP이기 때문에 새로운 프로젝트를 만들면 새로운 IP가 만들어진다. (불안정한것)

따라서 터미널에서 IP ADDR 해서 ip 추가하자 127.0.0.1 로컬호스트 추가해놓음

서버 변경 후 입장

 

survey가 생겼다. / 파일 중 manage.py 생성

 

survey 추가해주자.

 

 

11. views.py 가서 필터 추가

Survey 수입하고 필터로 order by(정렬)하기

from survey.models import Survey
def home(request):
    print("list 모듈 동작!")
    # filter 조건절에 해당
    # [0] 레코드중에서 첫번째 요청
    # select * from survey_survey where status='y' => row 10
    # 최신 데이터 1개만 추출 / 내림차순 : order by('-xx')[index]
    survey = Survey.objects.filter(status='y').order_by('-survey_idx')[0]

    return render(request, "survey/list.html", {'survey': survey})

 

12. list.html 가서 값들 다 출력해보기

잘 나오는지 확인

 

확인 끝났으니 제대로 써보자.

 

13. list.html에서 style 추가하기

    <style>
        #wrap {width:550px; margin:auto}
        .sub { background:orange; font-size:30px}
    </style>

 

14. list.html 스타일 적용할 내용 제대로 쓰기

<div id="wrap">
    <form method="post" action="save_survey">
        {% csrf_token %}
        <p class="sub">{{survey.question}}</p>
        <p><input type="radio" name="num" value="1" >{{survey.ans1}}</p>
        <p><input type="radio" name="num" value="2" >{{survey.ans2}}</p>
        <p><input type="radio" name="num" value="3" >{{survey.ans3}}</p>
        <p><input type="radio" name="num" value="4" >{{survey.ans4}}</p>
        <p>
            <input type="hidden" name="survey_idx" value="{{survey.survey_idx}}" >
            <input type="submit" value="투표">
            <input type="button" value="결과확인" onclick="show_result()">
        </p>
    </form>
    <script>
        function show_result(){
            location.href= " show_result?survey_idx={{survey.survey_idx}} ";
        }
    </script>
</div>

autofield는 입력처리를 idx를 생략함(def insert 의 Address부분)

 

15. views.py에 결과창 연결

save_survey 정의하기

@csrf_protect
def save_survey(request):
    # 문제 번호와 응답번호를 Answer 객체에 저장한다.
    survey_idx = request.POST["survey_idx"]
    print("Type : ", type(survey_idx))
    # survey_survey primary key -> 1:n 질문에 대한 답변의 값(survey)
    # num :선택한 설문의 항목 번호
    dto = Answer(survey_idx=int(request.POST["survey_idx"]), num=request.POST["num"])
    # insert query 가 호출
    dto.save()

    return render(request, "survey/success.html", {'survey_idx': survey_idx})

 

 


[ #참고 # 리소스 파일 저장 ]

spring에서는 resource라는 파일에 img를 비롯한 css 파일을 넣어두었다.

우리도 pycharm에 static 이라는 이름의 resource 파일을 만들어서 거기에 img 폴더 안에 이미지를 저장한다.

 

디렉토리 경로 설정 후 파일 저장


16. success.html 파일 생성 후 입력

그 이미지를 불러와보자.

# 이미지 불러오기
{% load static %}
{% static "" as baseUrl %}

<head>
    <meta charset="UTF-8">
    <title>success.html</title>
    <style>
        #wrap {width:350px; margin:auto; }
        #wrap image {width:100px; }
    </style>

</head>
<body>
    <h2>설문이 완료되었습니다.</h2>
    <img src="{{baseUrl}}/img/logo.jpg"><br>
    <a href="/survey">투표하기</a> <br>
    </body>
</html>

 

17. urls.py에 path 등록

    path('save_survey',views.save_survey),

 

 

#17. view에 show_result 정의하기(결과창)

주의) get이다!

@csrf_protect
def show_result(request):
    # 문제 번호
    idx = request.GET["survey_idx"]

    # select * from survey where survey_idx=1 과 같다.
    ans = Survey.objects.get(survey_idx=idx)

    # 각 문항에 대한 값으로 리스트를 만들어 놓는다.
    answer = [ans.ans1, ans.ans2, ans.ans3, ans.ans4]

    # Survey.objects.raw("""SQL문""")
    surveyList = Survey.objects.raw("""
        SELECT survey_idx, num, count(num) sum_num FROM survey_answer
            WHERE survey_idx=%s
            GROUP BY survey_idx,num
            ORDER BY num
        """, idx)

    surveyList = zip(surveyList, answer)

    return render(request, "survey/result.html", {'surveyList': surveyList})

 

18. urls 에 등록

    path('show_result', views.show_result),

 

19. survey 폴더에 result.html 만들기

설문조사 결과를 출력한다.

view에서 정의한 surveyList의 SQL 문을 가져와서 결과를 띄운다. 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>result.html</title>
</head>
<body>
<div id="wrap">
    <h1>설문조사 결과보기 예제</h1>
    <table>
        <tr>
            <th>문항</th>
            <th>응답수</th>
        </tr>
        <tr>
        	<td>{{surveyList}}</td>     
            <td></td>  
        </tr>
        <tr>
            <td colspan="2">
                <input type="button" value="투표하기" onclick="location='/survey'">
            </td>
        </tr>
    </table>
</div>
</body>
</html>

이렇게 나오면 잘된거

 

21. 값 제대로 나오게 바꿔보자

jstl 사용하자. 현재 필요한 결과값들은 응답과 설문한 질문의 갯수들이다.

        {% for row, ans in surveyList %}
        <tr>
            <td>{{ans}}</td>
            <td>{{row.sum_num}}</td>
            <!--sql에 있는 테이블 row 가져오기-->
        </tr>
        {%endfor%}

 

결과 잘 나옴

 

설문을 등록할 수 있는 폼을 만들어보자.

22. 설문 등록폼 write.html 만들기

write.html의 views정의를 write로, DB에 데이터를 입력하는 request.post를 insert로 지정해 줄 것이기 때문에 입력값을 action="insert"로 미리 설정해두었다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>write.html</title>

    <style>
        #wrap { width:450px; margin:auto }

        #table { border-collapse: collapse; width:100% }
        #th,td { padding:8px; text-align:left;
        border-bottom: 1px solid #ddd;
        }
        tr:hover { background:#f5f5f5; cursor:pointer }
    </style>
</head>

<body>
<div id="wrap"><h1> write (설문 등록폼) </h1>
<form method="post" action="insert">
    <!-- view.py의 save_question 를 정의한 곳으로 이동해서 DB로 보낼 것. -->

    {% csrf_token%}

  <table>
    <tr><td>질문</td><td><input type="text" name="question"></td></tr>
    <tr><td>응답1</td><td><input type="text" name="ans1"></td></tr>
    <tr><td>응답2</td><td><input type="text" name="ans2"></td></tr>
    <tr><td>응답3</td><td><input type="text" name="ans3"></td></tr>
    <tr><td>응답4</td><td><input type="text" name="ans4"></td></tr>
    <tr><td>상태</td><td><input type="text" name="status"></td></tr>
    <tr><input type="submit"></tr>
  </table>

</form>
</div>
</body>
</html>

submit 후 insert > DB로 들어갈 것이다.

 

23. views.py로 가서 write와 insert 정의하기

# write.html 연결
def write(request):
    return render(request, "survey/write.html")


# write에 받은거 DB 연동
def insert(request):
    # 데이터 베이스에 입력 처리 (idx 는 Oracle의 순번과 동일)
    addq = Survey(question=request.POST['question'],
                  ans1=request.POST['ans1'],
                  ans2=request.POST['ans2'],
                  ans3=request.POST['ans3'],
                  ans4=request.POST['ans4'],
                  status=request.POST['status'],
                  )
    addq.save()
    return redirect("/survey/list")

 

24. 설문 목록을 볼 수 있는 survey_list.html 만들기

설문 목록창은 설문의 리스트 갯수 출력(survey_count), 내용 출력(table), 설문등록폼으로 이동하기 위한 버튼(location = 'write'), jstl을 이용해 목록 나열 후, 질문 목록에 '상세보기 창 이동 링크'(a태그)를 걸어두었다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>survey_list.html</title>

    <style>
        #wrap { width:450px; margin:auto }

        #table { border-collapse: collapse; width:100% }
        #th,td { padding:8px; text-align:left;
        border-bottom: 1px solid #ddd;
        }
        tr:hover { background:#f5f5f5; cursor:pointer }
    </style>
</head>

<body>
<div><h3> survey_list</h3>

<p> 여기는 설문 리스트 : {{survey_count}}</p>

    <table>
        <thead>
        <tr>
            <th>번호</th>
            <th>질문</th>
            <th>응답1</th>
            <th>응답2</th>
            <th>응답3</th>
            <th>응답4</th>
            <th>상태</th>
        </tr>
        </thead>
        <tfoot>
        <tr>
            <th colspan="5">
                <input type="button" value="등록" onclick="location='write'">
            </th>
        </tr>
        </tfoot>
        <tbody>
        <!--jstl 사용-->
        {% for e in items %}
            <tr>
                <td>{{e.survey_idx}}</td>
                <td>
                    <a href ="------ 입력예정 ------">{{e.question}}</a>
                </td>
                <td>{{e.ans1}}</td>
                <td>{{e.ans2}}</td>
                <td>{{e.ans3}}</td>
                <td>{{e.ans4}}</td>
                <td>{{e.status}}</td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
</div>
</body>
</html>

 

25. views.py로 가서 list 정의하기

survey를 정렬한 items와 갯수인 survey_count 를 리턴해준다.

#질문목록 정의 / 갯수
def list(request):
    items = Survey.objects.order_by('survey_idx')

    # group 함수
    survey_count = Survey.objects.all().count()

    # 이제 이 값을 urls에 넘겨줘야지.
    return render(request, "survey/survey_list.html", {'items': items,
                                                       'survey_count': survey_count})

 

26. urls.py에서 path를 지정해준다.

    path('list', views.list),
    path('write', views.write),
    path('insert', views.insert),

 

27. 설문 상세 페이지인 detail.html 를 만든다.

기본적인 정보를 출력하는 테이블과 리스트, 수정, 삭제로 onclick이 걸린 버튼을 만든다.

추후 script를 설정할꺼니 이름만 정해두자.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>upform.html</title>

    <style>
        #wrap { width:450px; margin:auto }

        #table { border-collapse: collapse; width:100% }
        #th,td { padding:8px; text-align:left;
        border-bottom: 1px solid #ddd;
        }
        tr:hover { background:#f5f5f5; cursor:pointer }
    </style>
</head>

<body>
<div id="wrap">
<h1> survey 수정 </h1>
<form method="post" name="form1">

    <!--사이트 위조 방지 설정이 기본적으로 설정 체크-->
    {% csrf_token%}

  <input type="hidden" name="survey_idx">
  <table>
    <tr>
        <td>질문</td>
        <td><input type="text" name="question"></td>
    </tr>
    <tr>
        <td>응답1</td>
        <td><input type="text" name="ans1"></td>
    </tr>
    <tr>
        <td>응답2</td>
        <td><input type="text" name="ans2"></td>
    </tr>
    <tr>
        <td>응답3</td>
        <td><input type="text" name="ans3"></td>
    </tr>
    <tr>
        <td>응답4</td>
        <td><input type="text" name="ans4"></td>
    </tr>
    <tr>
        <td>상태</td>
        <td><input type="text" name="status"></td>
    </tr>

    <tr>
        <th colspan="2"> <!--버튼 추가-->
            <input type="button" value="리스트" onclick="gourl()">
            <input type="button" value="수정" onclick="update()">
            <input type="button" value="삭제" onclick="del()">
        </th>
    </tr>
  </table>

</form>
</div>
</body>
</html>

 

28. views.py 에서 detail를 정의한다.

addq는 추가한 설문들이 수정 또는 삭제를 거친 후 최종적으로 정해진 값 idv와 인덱스번호 idx가 같은 경우를 변수로 담는다.

# 상세페이지
def detail(request):
    idv = request.GET['survey_idx']
    # select * from address_address where idx = idv
    addq = Survey.objects.get(survey_idx=idv)
    return render(request, 'survey/detail.html', {'addq': addq})

 

29. survey_list.html에서 상세페이지로 이동하는 a 태그 링크를 걸어준다.

                <td>
                    <a href ="detail?survey_idx={{e.survey_idx}}">{{e.question}}</a>
                </td>

 

30. detail.html에서 survey_idx에 따른 설문 값을 볼 수 있도록 value 값을 설정해준다.

단, 그 값들은 views.py에서 정의한 addq의 조건에 한한다.

<input type="hidden" name="survey_idx" value="{{addq.survey_idx}}">
  <table>
    <tr>
        <td>질문</td>
        <td><input type="text" name="question" value="{{addq.question}}"></td>
    </tr>
    <tr>
        <td>응답1</td>
        <td><input type="text" name="ans1" value="{{addq.ans1}}"></td>
    </tr>
    <tr>
        <td>응답2</td>
        <td><input type="text" name="ans2" value="{{addq.ans2}}"></td>
    </tr>
    <tr>
        <td>응답3</td>
        <td><input type="text" name="ans3" value="{{addq.ans3}}"></td>
    </tr>
    <tr>
        <td>응답4</td>
        <td><input type="text" name="ans4" value="{{addq.ans4}}"></td>
    </tr>
    <tr>
        <td>상태</td>
        <td><input type="text" name="status" value="{{addq.status}}"></td>
    </tr>

 

31. views.py 에서 update와 delete를 정의한다.

삭제와 수정기능에 addq를 변경, 또는 지우는 기능을 부여한다.

# 삭제 기능
# csrf_protect는 csrf 방식을 검증한다.
# 앞으로 post 방식일 때는 반드시 사용을 원칙으로 한다.
@csrf_protect
def delete(request):
    idv = request.POST['survey_idx']
    print("survey_idx:", idv)
    # delete * from address_address where idx = idv
    # 선택한 데이터의 레코드가 삭제됨
    addq = Survey.objects.get(survey_idx=idv).delete()
    return redirect('/survey/list')

# =====================================================
# 수정 기능
@csrf_protect
def update(request):
    idv = request.POST['survey_idx']
    question = request.POST['question']
    ans1 = request.POST['ans1']
    ans2 = request.POST['ans2']
    ans3 = request.POST['ans3']
    ans4 = request.POST['ans4']
    status = request.POST['status']

    print("survey_idx:", idv)
    print("question:", question)
    print("ans1:", ans1)
    print("ans2:", ans2)
    print("ans3:", ans3)
    print("ans4:", ans4)
    print("status:", status)

    # 수정 데이터 베이스 처리(idx=id -> 값을 넣으면 수정, 없으면 auto로 생성되므로 없어도됨)
    addq = Survey(survey_idx=idv, question=question, ans1=ans1, ans2=ans2, ans3=ans3, ans4=ans4, status=status)

    # 데이터 레코드가 수정됨
    addq.save()

    return redirect('/survey/list')

 

 

32. detail.html에 리스트이동, 수정, 삭제 기능을 위한 script를 추가해준다.

</form>
</div>
    <script>
    //리스트로 이동
    function gourl(){
        location="/survey/list"
    }
    //삭제
    function del(){
        document.form1.action="delete";
        document.form1.submit();
    }
    //수정
    function update(){
        document.form1.action="update";
        document.form1.submit();
    }

    </script>
</body>

리스트는 location만 걸면 되고, 삭제, 수정 기능은 view.py에서 지정해둔 기능을 수행한다. "delete"와 "delete"가 def 한 그 기능이다.

 

정리 ) 뷰에서 수정버튼 누르면 스크립트로 가고 컨트롤러가 요청을 맵핑(url)오고 모델 보고 뷰의 업데이트로 가세요.

 

33. urls.py에서 path를 지정해준다.

 

    path('detail', views.detail),
    path('update', views.update),
    path('delete', views.delete),

 

설정은 다 마쳤다. 이제 원래 우리가 첫페이지로 사용했던 list.html에 survey_list.html로 가는 버튼을 만들어주자.

 

34. list.html에 질문목록 버튼 생성

        <p class="sub">{{survey.question}}</p>
        <p><input type="radio" name="num" value="1" >{{survey.ans1}}</p>
        <p><input type="radio" name="num" value="2" >{{survey.ans2}}</p>
        <p><input type="radio" name="num" value="3" >{{survey.ans3}}</p>
        <p><input type="radio" name="num" value="4" >{{survey.ans4}}</p>
        <p>
            <input type="hidden" name="survey_idx" value="{{survey.survey_idx}}" >
            <input type="submit" value="투표">
            <input type="button" value="결과확인" onclick="show_result()">

            <input type="button" value="질문목록" onclick="location='list'">

        </p>

 

35. 완성 화면

 

투표, 결과보기,질문목록,질문등록
질문 수정, 삭제 기능

스프링보다 쉽다. 처음부터 끝까지 혼자 해보니 확실히 실력이 느는 느낌 :)

 

[에러] idx가 올라가면 계속 에러가 난다.

params로 해야 숫자가 높아져도 에러가 나지 않는다.

 

 

 

 

▼ 전체 코드 보기

더보기

[전체 코드]

1. detail.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>upform.html</title>

    <style>
        #wrap { width:450px; margin:auto }

        #table { border-collapse: collapse; width:100% }
        #th,td { padding:8px; text-align:left;
        border-bottom: 1px solid #ddd;
        }
        tr:hover { background:#f5f5f5; cursor:pointer }
    </style>
</head>

<body>
<div id="wrap">
<h1> survey 수정 </h1>
<form method="post" name="form1">

    <!--사이트 위조 방지 설정이 기본적으로 설정 체크-->
    {% csrf_token%}

    <!--인덱스 번호는 필요 없음

    -->
  <input type="hidden" name="survey_idx" value="{{addq.survey_idx}}">
  <table>
    <tr>
        <td>질문</td>
        <td><input type="text" name="question" value="{{addq.question}}"></td>
    </tr>
    <tr>
        <td>응답1</td>
        <td><input type="text" name="ans1" value="{{addq.ans1}}"></td>
    </tr>
    <tr>
        <td>응답2</td>
        <td><input type="text" name="ans2" value="{{addq.ans2}}"></td>
    </tr>
    <tr>
        <td>응답3</td>
        <td><input type="text" name="ans3" value="{{addq.ans3}}"></td>
    </tr>
    <tr>
        <td>응답4</td>
        <td><input type="text" name="ans4" value="{{addq.ans4}}"></td>
    </tr>
    <tr>
        <td>상태</td>
        <td><input type="text" name="status" value="{{addq.status}}"></td>
    </tr>

    <tr>
        <th colspan="2"> <!--버튼 추가-->
            <input type="button" value="리스트" onclick="gourl()">
            <input type="button" value="수정" onclick="update()">
            <input type="button" value="삭제" onclick="del()">
        </th>
    </tr>
  </table>

</form>
</div>
    <script>
    function gourl(){
        location="/survey/list"
    }
    //두 함수의 공통기능을 분석해서 하나의 함수로 변경해보기
    function del(){
        document.form1.action="delete";
        document.form1.submit();
    }
    function update(){
        document.form1.action="update";
        document.form1.submit();
    }

    </script>
</body>
</html>

 

2. list.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <title>list.html</title>
    <style>
        #wrap {width:550px; margin:auto}
        .sub { background:orange; font-size:30px}
    </style>
</head>
<body>
<div id="wrap">
    <form method="post" action="save_survey">
        {% csrf_token %}
        <p class="sub">{{survey.question}}</p>
        <p><input type="radio" name="num" value="1" >{{survey.ans1}}</p>
        <p><input type="radio" name="num" value="2" >{{survey.ans2}}</p>
        <p><input type="radio" name="num" value="3" >{{survey.ans3}}</p>
        <p><input type="radio" name="num" value="4" >{{survey.ans4}}</p>
        <p>
            <input type="hidden" name="survey_idx" value="{{survey.survey_idx}}" >
            <input type="submit" value="투표">
            <input type="button" value="결과확인" onclick="show_result()">

            <!--===============================================================-->
            <input type="button" value="질문목록" onclick="location='list'">
            <!--===============================================================-->
        </p>

    </form>
    <script>
        function show_result(){
            location.href= " show_result?survey_idx={{survey.survey_idx}} ";
        }
    </script>
</div>
</body>
</html>

 

3. result.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>result.html</title>
</head>
<body>
<div id="wrap">
    <h1>설문조사 결과보기 예제</h1>
    <table>
        <tr>
            <th>문항</th>
            <th>응답수</th>
        </tr>
        {% for row, ans in surveyList %}
        <tr>
            <td>{{ans}}</td>
            <td>{{row.sum_num}}</td>
            <!--sql에 있는 테이블 row 가져오기-->
        </tr>
        {%endfor%}
        <tr>
            <td colspan="2">
                <input type="button" value="투표하기" onclick="location='/survey'">
            </td>
        </tr>
    </table>
</div>
</body>
</html>

4. success.html

<!DOCTYPE html>
<html lang="ko">

# 이미지 불러오기
{% load static %}
{% static "" as baseUrl %}

<head>
    <meta charset="UTF-8">
    <title>success.html</title>
    <style>
        #wrap {width:350px; margin:auto; }
        #wrap image {width:100px; }
    </style>

</head>
<body>
    <h2>설문이 완료되었습니다.</h2>
    <img src="{{baseUrl}}/img/logo.jpg"><br>
    <a href="/survey">투표하기</a> <br>
    <a href="show_result?survey_idx={{survey_idx}}">설문조사 결과 보기</a> <br>


</body>
</html>

 

5. survey_list.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>survey_list.html</title>

    <style>
        #wrap { width:450px; margin:auto }

        #table { border-collapse: collapse; width:100% }
        #th,td { padding:8px; text-align:left;
        border-bottom: 1px solid #ddd;
        }
        tr:hover { background:#f5f5f5; cursor:pointer }
    </style>
</head>

<body>
<div><h3> survey_list</h3>

<p> 여기는 설문 리스트 : {{survey_count}}</p>

    <table>
        <thead>
        <tr>
            <th>번호</th>
            <th>질문</th>
            <th>응답1</th>
            <th>응답2</th>
            <th>응답3</th>
            <th>응답4</th>
            <th>상태</th>
        </tr>
        </thead>
        <tfoot>
        <tr>
            <th colspan="5">
                <input type="button" value="등록" onclick="location='write'">
            </th>
        </tr>
        </tfoot>
        <tbody>
        <!--jstl 사용-->
        {% for e in items %}
            <tr>
                <td>{{e.survey_idx}}</td>
                <td>
                    <a href ="detail?survey_idx={{e.survey_idx}}">{{e.question}}</a>
                </td>
                <td>{{e.ans1}}</td>
                <td>{{e.ans2}}</td>
                <td>{{e.ans3}}</td>
                <td>{{e.ans4}}</td>
                <td>{{e.status}}</td>
            </tr>
        {% endfor %}
        </tbody>
    </table>
</div>
</body>
</html>

6. write.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>write.html</title>

    <style>
        #wrap { width:450px; margin:auto }

        #table { border-collapse: collapse; width:100% }
        #th,td { padding:8px; text-align:left;
        border-bottom: 1px solid #ddd;
        }
        tr:hover { background:#f5f5f5; cursor:pointer }
    </style>
</head>

<body>
<div id="wrap"><h1> write (설문 등록폼) </h1>
<form method="post" action="insert">
    <!-- view.py의 save_question 를 정의한 곳으로 이동해서 DB로 보낼 것. -->

    {% csrf_token%}

  <table>
    <tr><td>질문</td><td><input type="text" name="question"></td></tr>
    <tr><td>응답1</td><td><input type="text" name="ans1"></td></tr>
    <tr><td>응답2</td><td><input type="text" name="ans2"></td></tr>
    <tr><td>응답3</td><td><input type="text" name="ans3"></td></tr>
    <tr><td>응답4</td><td><input type="text" name="ans4"></td></tr>
    <tr><td>상태</td><td><input type="text" name="status"></td></tr>
    <tr><input type="submit"></tr>
  </table>

</form>
</div>
</body>
</html>

7. models.py

from django.db import models


# Create your models here.

# 설문조사 문항
class Survey(models.Model):
    # 설문 인덱스
    survey_idx = models.AutoField(primary_key=True)

    # 설문 문제
    question = models.TextField(null=True)

    # 답 1~4
    ans1 = models.TextField(null=True)
    ans2 = models.TextField(null=True)
    ans3 = models.TextField(null=True)
    ans4 = models.TextField(null=True)

    # 설문진행상태(y=진행중, n=종료)
    status = models.CharField(max_length=1, default="y")


# ------------------------------------------------------------
class Answer(models.Model):
    # 응답 아이디(자동필드 증가)
    answer_idx = models.AutoField(primary_key=True)

    # 설문 아이디
    survey_idx = models.IntegerField()

    # 응답 번호
    num = models.IntegerField()


# =============================================================
# 설문 등록
# 위에 survey에 정의되어있음

8. urls.py

from django.urls import path

from survey import views

urlpatterns=[
    path('',views.home),
    path('save_survey',views.save_survey),
    path('show_result', views.show_result),

    # ================================================

    path('list', views.list),
    path('write', views.write),
    path('insert', views.insert),

    # ================================================
    path('detail', views.detail),
    path('update', views.update),
    path('delete', views.delete),
]

9. views.py

from django.shortcuts import render, redirect
from django.views.decorators.csrf import csrf_protect

from survey.models import Survey, Answer


# Create your views here.
def home(request):
    print("list 모듈 동작!")
    # filter 조건절에 해당
    # [0] 레코드중에서 첫번째 요청
    # select * from survey_survey where status='y' => row 10
    # 최신 데이터 1개만 추출 / 내림차순 : order by('-xx')[index]
    survey = Survey.objects.filter(status='y').order_by('-survey_idx')[0]

    return render(request, "survey/list.html", {'survey': survey})


# -------------------------------------------------------------------

@csrf_protect
def save_survey(request):
    # 문제 번호와 응답번호를 Answer 객체에 저장한다.
    survey_idx = request.POST["survey_idx"]
    print("Type : ", type(survey_idx))
    # survey_survey primary key -> 1:n 질문에 대한 답변의 값(survey)
    # num :선택한 설문의 항목 번호
    dto = Answer(survey_idx=int(request.POST["survey_idx"]), num=request.POST["num"])
    # insert query 가 호출
    dto.save()

    return render(request, "survey/success.html", {'survey_idx': survey_idx})


# -------------------------------------------------------------------
@csrf_protect
def show_result(request):
    # 문제 번호
    idx = request.GET["survey_idx"]

    # select * from survey where survey_idx=1 과 같다.
    ans = Survey.objects.get(survey_idx=idx)

    # 각 문항에 대한 값으로 리스트를 만들어 놓는다.
    answer = [ans.ans1, ans.ans2, ans.ans3, ans.ans4]

    # Survey.objects.raw("""SQL문""")
    surveyList = Survey.objects.raw("""
        SELECT survey_idx, num, count(num) sum_num FROM survey_answer
            WHERE survey_idx=%s
            GROUP BY survey_idx,num
            ORDER BY num
        """, idx)

    # [[ans.ans1, surveyList???
    surveyList = zip(surveyList, answer)

    return render(request, "survey/result.html", {'surveyList': surveyList})


# ========================================================
# 질문목록 정의 / 갯수
def list(request):
    items = Survey.objects.order_by('survey_idx')

    # group 함수
    survey_count = Survey.objects.all().count()

    # 이제 이 값을 urls에 넘겨줘야지.
    return render(request, "survey/survey_list.html", {'items': items,
                                                       'survey_count': survey_count})


# write.html 연결
def write(request):
    return render(request, "survey/write.html")


# write에 받은거 DB 연동
def insert(request):
    # 데이터 베이스에 입력 처리 (idx 는 Oracle의 순번과 동일)
    addq = Survey(question=request.POST['question'],
                  ans1=request.POST['ans1'],
                  ans2=request.POST['ans2'],
                  ans3=request.POST['ans3'],
                  ans4=request.POST['ans4'],
                  status=request.POST['status'],
                  )
    addq.save()
    return redirect("/survey/list")


# ========================================================
# 상세페이지
def detail(request):
    idv = request.GET['survey_idx']
    # select * from address_address where idx = idv
    addq = Survey.objects.get(survey_idx=idv)
    return render(request, 'survey/detail.html', {'addq': addq})


# 삭제 기능
# csrf_protect는 csrf 방식을 검증한다.
# 앞으로 post 방식일 때는 반드시 사용을 원칙으로 한다.
@csrf_protect
def delete(request):
    idv = request.POST['survey_idx']
    print("survey_idx:", idv)
    # delete * from address_address where idx = idv
    # 선택한 데이터의 레코드가 삭제됨
    addq = Survey.objects.get(survey_idx=idv).delete()
    return redirect('/survey/list')


# 수정 기능
@csrf_protect
def update(request):
    idv = request.POST['survey_idx']
    question = request.POST['question']
    ans1 = request.POST['ans1']
    ans2 = request.POST['ans2']
    ans3 = request.POST['ans3']
    ans4 = request.POST['ans4']
    status = request.POST['status']

    print("survey_idx:", idv)
    print("question:", question)
    print("ans1:", ans1)
    print("ans2:", ans2)
    print("ans3:", ans3)
    print("ans4:", ans4)
    print("status:", status)

    # 수정 데이터 베이스 처리(idx=id -> 값을 넣으면 수정, 없으면 auto로 생성되므로 없어도됨)
    addq = Survey(survey_idx=idv, question=question, ans1=ans1, ans2=ans2, ans3=ans3, ans4=ans4, status=status)

    # 데이터 레코드가 수정됨
    addq.save()

    return redirect('/survey/list')

 

 

 

반응형
LIST

댓글