django 06. 두번째 장고앱 10 - POST 처리

|

django 06. 두번째 장고앱 10 - POST 처리

파이썬 웹 프로그래밍 - Django로 웹 서비스 개발하기

  • POST 폼을 처리할 vote 페이지를 작성한다.
  • form의 action 값은 vote 페이지로 설정되어 있다.

<form action="{% url 'polls:vote' question.id %}" method="POST">

  • views.py 의 vote 함수가 POST 처리 할 수 있도록 수정한다.
  • question.choice_set.get(pk = request.POST['choice']) 를 통해서 POST form에서 선택된 라디오 버튼의 value 값을 가져올 수 있다.
  • 예외 처리를 통해서 올바르지 않은 라디오 버튼을 선택시 error_message를 전달한다.
  • 예외 처리에서 문제가 없으면 .save()를 통해 업데이트 한다.
  • vote 페이지가 POST를 처리하고 나면 return redirect('polls:results', question_id = question.id)를 통해 result 페이지로 이동시킨다.
def vote(request, question_id): #POST를 처리할 수 있도록 작성한다.
    question = get_object_or_404(Question, pk = question_id)
    try:
        # POST form에서 'choice' name 값을 갖는 input의 value 값을 가져온다.
        selected_choice = question.choice_set.get(pk = request.POST['choice'])
    except:
        return render(request, 'polls/detail.html', {
            'question' : question,
            'error_message' : "You didn't select a choice"
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        return redirect('polls:results', question_id = question.id)

django 06. 두번째 장고앱 9 - 간단한 폼 직접 만들기

|

django 06. 두번째 장고앱 9 - 간단한 폼 직접 만들기

파이썬 웹 프로그래밍 - Django로 웹 서비스 개발하기

detail.html 템플릿에 form 을 추가

  • 지난번 실습에서는 form 클래스(form.py)를 사용해서 form을 작성했으나, 이번에는 2개의 모델을 갖고 (Question, Choice) custom form을 작성한다.
  • form 안에는 보안을 위해서 csrf_token을 무조건 넣어준다.
  • input 의 name 값은 post의 dictionary 처럼 사용 할 수 있다.
  • forloop.counter를 통해서 반복하면서 하나씩 증가하는 임의의 숫자를 추가할 수 있다. (1부터 시작)

views.py 내의 DetailView 클래스

class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'

detail.html 템플릿 코드


<h2>{{question.question_text}}</h2>

{%if error_message %} <p><strong>{{ error_message }}</strong></p>{% endif %}

<form action="{% url 'polls:vote' question.id %}" method="POST">
  {% csrf_token %}
  <!-- 해당 question의 선택지들을 하나씩 보여준다 .all()이 아닌것 주의 -->
  {% for choice in question.choice_set.all %}
    <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{choice.id}}">
    <label for="choice{{ forloop.counter }}">{{choice.choice_text}}</label><br>
  {% endfor %}
  <input type="submit" value="투표">
</form>

랜더링된 detail.html 코드



<h2>최고의 고기는?</h2>

<form action="/polls/1/vote/" method="POST">
  <input type='hidden' name='csrfmiddlewaretoken' value='XGkLxShVgsOnJBte8eObFGWctzk9hcgq0qKVj0LMHDQVWAYOnxbYcAzkezRCjXZw' />
  <!-- 해당 question의 선택지들을 하나씩 보여준다 -->

    <input type="radio" name="choice" id="choice1" value="1">
    <label for="choice1">돼지</label><br>

    <input type="radio" name="choice" id="choice2" value="2">
    <label for="choice2">치킨</label><br>

    <input type="radio" name="choice" id="choice3" value="3">
    <label for="choice3"></label><br>

    <input type="radio" name="choice" id="choice4" value="6">
    <label for="choice4"></label><br>

    <input type="radio" name="choice" id="choice5" value="7">
    <label for="choice5"></label><br>

  <input type="submit" value="투표">
</form>

django 06. 두번째 장고앱 8 - 하드코딩 URL 제거, namespace, app_name

|

django 06. 두번째 장고앱 8 - 하드코딩 URL 제거

파이썬 웹 프로그래밍 - Django로 웹 서비스 개발하기

하드코딩된 URL을 제거한다

  • 기존의 하드코딩된 index.html의 URL 링크

{% for question in latest_question_list %}
<li><a href="/polls/{{question.id}}">{{question.question_text}}</a></li>
{% endfor %}

  • 하드코딩 대신에 url 마다 갖고 있는 name 값(urls.py)을 활용한다.
  • 하드코딩 url 보다 url의 name 값을 사용하는 것이 유지보수를 위해서 더 좋다.
  • html 내에서 url 'url 네임값' 전달할 파라미터 형식으로 작성 가능하다.

{% for question in latest_question_list %}
<li><a href="{% url 'detail' question.id%}">{{question.question_text}}</a></li>
{% endfor %}

네임스페이스

  • url의 name 값을 사용하다 보면 이름이 중복되는 문제가 발생할 수 있다.
  • 중복을 방지하기 위해서 app_name 이라는 url 네임스페이스를 사용할 수 있다.
  • 네임스페이스 예시
# myapp/urls.py
app_name = 'polls' #url 네임 스페이스

# mysite/urls.py
url(r'^video/', include('video.urls', namespace='video'))
  • index.html 의 링크 name 값에도 polls:detail 처럼 네임 스페이스를 함께 적어야 한다. (중요 : 띄어쓰기 없음)

{% for question in latest_question_list %}
<li><a href="{% url 'polls:detail' question.id%}">{{question.question_text}}</a></li>
{% endfor %}

level 1. 제일 작은 수 제거하기

|

level 1. 제일 작은 수 제거하기

출처

문제

rm_small함수는 list타입 변수 mylist을 매개변수로 입력받습니다. mylist 에서 가장 작은 수를 제거한 리스트를 리턴하고, mylist의 원소가 1개 이하인 경우는 []를 리턴하는 함수를 완성하세요. 예를들어 mylist가 [4,3,2,1]인 경우는 [4,3,2]를 리턴 하고, [10, 8, 22]면 [10, 22]를 리턴 합니다.

풀이 (python)

# 풀이1
def rm_small(mylist):
    mylist.remove(min(mylist)) #min() - O(N) 시간복잡도
    return mylist


# 풀이2 - filter 사용
def rm_small(mylist):
    return list(filter(lambda x: x > min(mylist), mylist))


# 풀이3
def rm_samll(mylist):
    return [i for i in mylist if i > min(mylist)]

# 아래는 테스트로 출력해 보기 위한 코드입니다.
my_list = [4, 3, 2, 1]
print("결과 {} ".format(rm_small(my_list)))

배운점

  • min(), max() 함수를 이용하면 인수로 반복 가능(iterable)한 자료형을 입력받아 그 최소값, 최대값을 리턴한다.
  • iterable 의 의미는 member를 하나씩 차례로 반환 가능한 object를 말한다.
  • iterable 의 예로는 sequence type인 list, str, tuple,dic 이 대표적이다.

level 1. 평균구하기

|

level 1. 평균구하기

출처

문제

def average(list): 함수를 완성해서 매개변수 list의 평균값을 return하도록 만들어 보세요. 어떠한 크기의 list가 와도 평균값을 구할 수 있어야 합니다.

풀이 (python)

def average(list):
	v = 0
	for i in list:
		v = v + i
	return v / len(list)


# 아래는 테스트로 출력해 보기 위한 코드입니다.
list = [5,3,4]
print("평균값 : {}".format(average(list)));
  • 4개월 뒤에 해당 다시 풀어보았다.
#풀이1 - ZeroDivisionError 예외처리 필요
def average(list):
    return sum(list) / len(list) # sum() - O(N) 시간복잡도

#풀이2 - ZeroDivisionError 예외처리
def average(list):
    if not len(list):
        return 0
    return sum(list) / len(list)

#풀이3 - reduce, lambda
from functools import reduce
def average(list):
    return reduce(lambda x,y: x+y) / len(list)

다른사람 풀이

def average(list):
    return (sum(list) / len(list))

배운점

  • sum 함수를 사용하면 리스트 각 요소들의 총 합을 구할 수 있구나!

풀이 1 (java)

public class GetMean {
	public int getMean(int[] array) {
		int sum = 0;
		for (int e : array) {
			sum += e;
		}
		return sum / array.length;
	}


	public static void main(String[] args) {
		int x[] = {5, 4, 3};
		GetMean getMean = new GetMean();
		System.out.println("평균값 : " + getMean.getMean(x));
	}
}

풀이 2 (java)

import java.util.stream.*;

public class GetMean {
	public int getMean(int[] array) {
		int sum = IntStream.of(array).sum();
		return sum / array.length;
	}


	public static void main(String[] args) {
		int x[] = {5, 4, 3};
		GetMean getMean = new GetMean();
		System.out.println("평균값 : " + getMean.getMean(x));
	}
}

배운점

  • java.util.stream 패키지를 통해서 array의 합계를 구할 수 있다.