25/10/01 장고

344th·2025년 12월 11일

AWS AI

목록 보기
19/48

가상환경 활성화 후

django-admin startproject config .
django-admin startapp [프로젝트명]
python manage.py runserver
# db.sqlite3 파일, 즉 db 만들어진 거 확인 가능
python manage.py migrate
# 만들어진 db migrate

Django Shell

: Django 프로젝트와 상호 작용하도록 특별히 구성된 대화형 Python 환경

: 프로젝트의 모델, 설정 및 기타 Django 구성 요소에 직접 접근 가능하여

: 개발, 디버깅 및 데이터 조작을 위한 강력한 도구

python manage.py shell
>>> from pybo.models import Question, Answer
>>> from django.utils import timezone
# 객체화
>>> q = Question(subject='pybo가 무엇인가요?', content='pybo에 대해서 알고 싶
습니다.', create_date=timezone.now())
# 저장
>>> q.save()

데이터 저장이 잘 됐는지 결과를 db browser 에서 확인

확인했다면 꼭 꺼줄 것(shell 과 같이 실행되면 충돌 발생 가능)

# shell 에서도 저장된 데이터 확인 가능
>>> q.id
1
>>> q.subject
'pybo가 무엇인가요?'
>>> q.create_date
datetime.datetime(2025, 10, 1, 0, 36, 39, 694400, tzinfo=datetime.timezone.utc) 
# Questions 테이블에 저장된 모든 데이터 조회
# 한 가지 자료형이 아니므로 object 자료형으로 나옴
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>, <Question: Question object (2)>]> 
# 리스트로 묶을 수 있으므로 for문 활용 가능
>>> list(Question.objects.all())
[<Question: Question object (1)>, <Question: Question object (2)>]

데이터 유형이 출력되므로 사람이 보기 불편함

Question 모델에 str 메서드를 추가해 subject 필드가 뜨도록 함

class Question(models.Model):
	...
    def __str__(self):
        return self.subject

모델이 수정되었으므로 장고 셸을 다시 시작해 변경사항이 반영된 것을 확인한다

>>> quit()
python manage.py shell
# 다시 필요한 모델 임포트
>>> from pybo.models import Question, Answer
>>> from django.utils import timezone
# 다시 Question 모델의 모든 데이터 확인
# id 가 아닌 제목이 표시되는 것을 확인 가능
>>> Question.objects.all()
<QuerySet [<Question: pybo가 무엇인가요?>, <Question: 장고 모델 질문입니다.>]>

모델이 수정되었는데 왜 makemigrations, migrate 명령을 실행하지 않는가?
makemigrations, migrate 명령은 모델의 속성이 추가되거나 변경된 경우에 실행해야 하는 명령이다.
→ 지금은 메서드가 추가된 것이므로 이 과정은 하지 않아도 된다.

조건으로 데이터 조회

>>> Question.objects.filter(id=1)
<QuerySet [<Question: pybo가 무엇인가요?>]>

>>> Question.objects.filter(id__in=[1,2]) 
<QuerySet [<Question: pybo가 무엇인가요?>, <Question: 장고 모델 질문입니다.>]>

# 1보다 크고 10보다 작은
>>> Question.objects.filter(id__gte=1, id__lte=10) 
<QuerySet [<Question: pybo가 무엇인가요?>, <Question: 장고 모델 질문입니다.>]>

# 제목이 장고를 포함하는
>>> Question.objects.filter(subject__contains='장고') 
<QuerySet [<Question: 장고 모델 질문입니다.>]>

>>> Question.objects.get(id=1)    
<Question: pybo가 무엇인가요?>
  • filter : 조건에 해당하는 데이터를 모두 찾아줌(여러 값)
  • get : 조건에 해당하는 데이터 하나를 찾아줌(한 개의 값)

filter() 에서의 __ 활용 방법은 무궁무진

https://docs.djangoproject.com/ko/5.2/topics/db/queries/

데이터 덮어쓰기(수정)

>>> q = Question.objects.get(id=2)
>>> q.subject
'장고 모델 질문입니다.'
>>> q.subject = 'Django Model Question'
>>> q.save()

save() 필요

데이터 덮어쓰기(삭제)

>>> q = Question.objects.get(id=1)
>>> q.delete()
(1, {'pybo.Question': 1})

delete함수를 수행하면 해당 데이터가 데이터베이스에서 즉시 삭제되며(save() 필요 x)

삭제된 데이터의 추가 정보가 반환된다

# 삭제되어서 2번 데이터밖에 보이지 않음
>>> Question.objects.all()
<QuerySet [<Question: Django Model Question>]>

연결된 데이터 확인

>>> q = Question.objects.get(id=2)
>>> a = Answer(question=q, content='네 자동으로 생성됩니다.', create_date=time
zone.now())
>>> a.save()

question_id 로 간소화되어 표현

>>> a.question.id 
2

>>> a.question
<Question: Django Model Question>

연결된 데이터로 조회하기: 질문을 통해 답변 찾기

연결모델명_set

Question 과 Answer 테이블은

일대다 관계 ← 질문 1개에는 1개 이상의 답변이 달릴 수 있다

  • 그러므로 Question 테이블로 Answer 테이블 데이터를 조회할 땐 q.answer_set 을 사용
    >>> q.answer_set.all()
    <QuerySet [<Answer: Answer object (1)>]>
  • Answer 테이블로 Question 테이블 데이터를 조회할 땐 a.question 을 사용
    >>> a.question
    <Question: Django Model Question>

django Admin

관리자 계정 생성

python manage.py createsuperuser

**models.py 로 테이블 생성 후 데이터를 넣는 방법 2가지**

  • django shell
  • admin 페이지 ui
    1. admin.py 에 테이블 등록

      from django.contrib import admin
      from .models import Question
      
      # Register your models here.
      admin.site.register(Question)

    2. admin 페이지에서 데이터 직접 추가

  1. Admin 에 데이터 검색 기능 추가

    class QuestionAdmin(admin.ModelAdmin):
        search_fields = ['subject']
    admin.site.register(Question, QuestionAdmin)

요청 처리 흐름

[/pybo/~ url 요청] |-> settings.py -> ROOT_URLCONF
									 |-> config/urls.py
									 |-> pybo/urls.py
									 |-> pybo/views.py -> index()

views.py

from django.shortcuts import render
from .models import Question

def index(request):
		# create_date 역순으로 순서 정렬
    question_list = Question.objects.order_by("-create_date")
    # 포장
    context = {"question_list" : question_list}
    # render 로 화면 출력
    return render(request, 'pybo/question_list.html', context)

render(request, 'pybo/question_list.html', context)

  • context 에 있는 Question 모델 데이터 question_list 를 pybo/question_list.html 파일에 적용하여 HTML 코드로 변환한다
  • pybo/question_list.html → 장고에서 템플릿이라 부름

템플릿을 저장할 디렉터리 생성

C:\Users\DS 14\projects\mysite\templates

템플릿 디렉터리 위치 등록

config/settings.py

TEMPLATES = [
    {
        ...
        'DIRS': [BASE_DIR / 'templates'],
        ...

템플릿 파일 생성

C:\Users\DS 14\projects\mysite\templates\pybo\question_list.html

...
<body>
    {% if question_list %}
    <ul>
        {% for question in question_list %}
            <li><a href="/pybo/{{ question.id }}">{{ question.subject }}</a></li>
        {% endfor %}
    </ul>    
    {% else %}
        <p>질문이 없습니다.</p>
    {% endif %}
</body>
...

템플릿 태그 {% %}

태그설명
{% if question_list %}question_list가 존재하면 실행
{% for question in question_list %}question_list를 순회하며 순차적으로 하나씩 question에 대입
{{ question.id }}for문에 의해 대입된 question 객체의 id 번호를 출력
{{ question.subject }}for문에 의해 대입된 question 객체의 제목을 출력

질문 상세 기능 구현

pybo/urls.py

path('<int:question_id>/', views.detail),

pybo/views.py

def detail(request, question_id):
    question = Question.objects.get(id=question_id)
    context = {'question' : question}
    print(context)
    return render(request, 'pybo/question_detail.html', context)

question_detail.html

<body>
    <h1>{{ question.subject 
        }}</h1>
    <div>
        {{ question.content }}
    </div>
</body>

결과

에러 처리(오류 화면 구현)

  • 200 Success : ok. 성공
  • 300 : 리다이렉트(직접x → 넘겨줌)
  • 400 : 클라이언트의 잘못
    • 403 Forbidden : 권한이 없다
    • 404 Not Found : 페이지 존재하지 않음
  • 500 : 서버의 잘못. 서버 오류.

데이터베이스에 없는 데이터 아이디를 집어넣으면

당연히 오류가 남

500 error 가 뜨는데 이건 서버 에러가 아니라 존재하지 않는 페이지이므로 404로 바꿔준다

from django.shortcuts import render, get_object_or_404
...
def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
...

이제 존재하지 않는 아이디로 조회하면 404 에러가 뜨게 됨

url 더 똑똑하게 사용하기

이전까지는 템플릿에서 url 을 사용할 때 하드코딩을 함

<li><a href="/pybo/{{ question.id }}">{{ question.subject }}</a></li>

그러나 url 규칙이 변경된다면 하드코딩해준 부분을 일일이 찾아 수정해줘야 한다

url 별칭

pybo/urls.py

urlpatterns = [
    path('', views.index, name='index'),
    path('<int:question_id>/', views.detail, name='detail'),
]

templates\pybo\question_list.html

<li><a href="{% url 'detail' question.id %}">{{ question.subject }}</a></li>

하드코딩된 /pybo/{{ question.id }} 링크를 {% url 'detail' question.id %}로 변경

url 네임스페이스

pybo/urls.py

app_name = "pybo"

templates\pybo\question_list.html

<li><a href="{% url 'pybo:detail' question.id %}">{{ question.subject }}</a></li>

render vs. redirect

  • render : 새로운 페이지로 이동 : html 필요
  • redirect : 기존 페이지로 이동 : html 필요 x

답변 등록 기능

답변 저장하고 표시하기

<h1>{{ question.subject }}</h1>
<div>
    {{ question.content }}
</div>
<form action="#" method="post">
{% csrf_token %}
<textarea name="content" id="content" rows="15"></textarea>
<input type="submit" value="답변등록">
</form>

{% csrf_token %}

: 보안과 관련

: form을 통해 전송된 데이터가 실제 웹 페이지에서 작성된 것인지 확인하는 역할

→ 만약 해커가 비정상적인 방법으로 데이터를 전송한다면, 서버에서 발행한 csrf_token 값과 해커가 보낸 csrf_token 값이 일치하지 않아 요청이 차단될 것임

action="#"

: url과 요청 처리 로직이 따로 필요한 부분은 아직 만들어지지 않았으므로 만들어진 페이지 확인을 위해 우선 #으로 설정해서 비워놓음

→ 설계할 땐 비워놓고 만들어놓은 부분 제대로 동작하는지 확인한 후에 action 에 해당하는 부분을 채우고 거기서 필요한 부분을 채우는 흐름으로 하는 게 좋음

action="#" 결과

텍스트 입력 후 답변등록 버튼을 눌러 제출하면 url 뒤에 # 이 붙는 걸 확인 가능

action="{% url 'pybo:answer_create' [question.id](http://question.id/) %}" 넣었을 때 결과

답변 등록을 위한 url 매핑 등록하기

pybo/urls.py

path('answer/create/<int:question_id>/', views.answer_create, name='answer_create'),

answer_create 함수 추가하기

pybo\views.py

...
from django.utils import timezone

...
def answer_create(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    question.answer_set.create(content=request.POST.get('content'),
                               create_date=timezone.now())
                                                  
    # 답변 데이터 추가 후에 상세 페이지로 리다이렉트(다시 이동) 
    return redirect('pybo:detail', question_id=question.id)

answer 객체 생성 방식

  • question_id 로 Answer 테이블에 간접적으로 접근
    question.answer_set.create(content=request.POST.get('content'),
                               create_date=timezone.now())
  • answer 객체를 Answer 모델에 직접 접근해 생성
    answer = Answer(question=question, content=request.POST.get('content'), 
                    create_date=timezone.now())
    answer.save()

request.POST

: 폼 POST 데이터(QueryDict)

: 폼 방식으로 보낸 ‘텍스트 필드’만 QueryDict(request.POST)에 들어감 (json x)

profile
새싹 개발자

0개의 댓글