카테고리 없음

스파르타 AI-8기 TIL(12/11)-Django

kimjunki-8 2024. 12. 11. 21:01
Django Model
저장할 데이터에 대한 필드와 동작들을 포함한 데이터 베이스 구조.
Model
Model은 Django에서 데이터베이스와 상호작용하기 위한 설계도와 같은 역할을 합니다.
각 Model은 데이터베이스 테이블에 매핑되며, 데이터를 저장할 필드(컬럼)와 관련 동작(메서드)을 정의합니다.

데이터베이스 (Database)
데이터베이스는 데이터를 체계적으로 저장하고 관리하기 위한 시스템입니다.
데이터베이스는 정보를 저장하는 테이블, 테이블 간의 관계, 제약 조건 등을 포함하며, 대량의 데이터를 효율적으로 처리할 수 있도록 설계됩니다.
Django는 데이터베이스에 직접 연결하여 데이터를 삽입, 수정, 삭제, 검색 등의 작업을 처리합니다.

쿼리 (Query)
쿼리는 데이터베이스를 조작하거나 필요한 데이터를 검색하기 위해 사용하는 명령어입니다.

스키마 (Schema)
스키마는 데이터베이스 구조와 데이터 간의 관계를 정의한 설계도입니다.
스키마는 테이블, 컬럼, 데이터 타입, 제약 조건(Primary Key, Foreign Key, Unique, Not Null 등), 인덱스 등을 포함합니다.

테이블(Table)
열(Column) - 속성 / 필드(Field)
행(Row) - 데이터 / 레코드(Record) / 튜플(Tuple)
조직화된 데이터 요소들의 집합입니다.

모델은 클래스?
장고의 모델은 클래스로 정의한다. 
먼저, first_app에 있는 models.py로 갑니다.

이것이 기본적인 class의 형태이며, first_app은 하나의 테이블이라고 보면 됩니다.

그리고 그 안에 데이터를 넣어줍니다.
아, 지금부터 스피드런 들어가겠습니다.

데이터의 기본구조. 즉, model은 이러한 정보들을 쉽게 다루도록 하게 해주고, queryset은 이러한 것을 Python에서도 실행할 수 있게 해주는 것

class first_app(models.Model):
    title = models.CharField(max_length=50) #CharField는 max_length를 무조건 필요
    content = models.TextField()
    created_at= models.DateTimeField(auto_now_add = True) # add는 생성때 추가
    updated_at = models.DateTimeField(auto_now = True) # 없는건 수정될 때​

 

모델은 클래스이다. 이렇게 대부분 적고, model.Model을 상속 받는다.
CharField는 max_length를 무조건 필요로 하며,
auto_now_add는 생성할 때, 수정할 때는 _add가 안 붙는다.

참고로 서버 실행할 때, 이러한 오류를 본 적이 있습니다.
이것은 마이그레이션라는 개념으로 사실 장고에서는 우리가 기본적으로 처음 만들 때 마이그레이션을 세이브해서 해야하지만, 안 했기에 이런 오류가 뜬다(사실 경고)

마이그래이션 생성
python manage.py makemigrations​

 

자, 이렇게 될 경우, 파일이 생기는데, 약간 깃허브 느낌으로 버전을 분산해서 생성한다고 생각하면 된다. 
그리고 만약 클래스 안에 새로운 변경 사항이 생기면 무조건 저장을 해야한다.
python manage.py migrate​
고)
마이그레이션 목록과 적용여부를 보여주는 명령어
python manage.py showmigration
​
해당 마이그레이션이 어떤 sql문을 작성했는지 보여주는 명령어
python manage.py sqlmigrate <app_name> <migration_no>​
control + shift + p (맥은 command)를 눌러서 ‘SQLite: Open Database’ 선택

그러면 왼쪽 하단에 새로운것이 나타나며 SQL과 비슷한 형식으로 쓸 수 있다.


모델을 수정했으니 마이그레이션 생성하고(다시 생성!), 반영해야한다.
그러면 
기존에 생성한 데이터들은 어떻게 하겠냐고 묻습니다.
1. 값하나를 주면 그 값을 다 넣는 방식
2. 일단 종료하고 model로 돌아가서 기본값 설정하는 방식
1번 선택
→ 값을 따로 입력하지 않아도 Enter만 치면 지금 시간을 계산해서 넣어주거나 아니면 값을 따로 입력하라고 합니다.
enter

Django ORM
Object-Relational-Mapping
쉽게말해서 파이썬으로 데이터베이스를 조작할 수 있게 해줍니다. 즉, SQL 안쓰고 Python으로 데이터베이스 조작할 수 있습니다.
Database API

 

다른말로 database-abstraction API 라고도 합니다.
쉽게말해 Django ORM으로 Database API를 사용해서 데이터베이스를 조작하는 것입니다.
Manager
우리가 모델 클래스를 생성하면 Django는 자동적으로 CRUD(Create(생성), Read(읽기), Update(갱신), Delete(삭제))할 수 있는 Database API를 제공합니다.
기본형태
# MyModel.objects.all()
- Model Class . Manager . QuerysetAPI

python manage.py shell 
현재 Django 프로젝트 환경을 Shell로 접근할 수 있게 해줍니다.

 Django Shell
Django가 제공하는 여러가지 기능을 명령어로 입력해서 실행해볼 수 있는 Shell 환경을 말합니다.

settings.py 앱 등록
django_extensions, 처럼 중간에 하이픈(-)이 아닌 언더바(_)로 작성해야함


실행

python manage.py shell_plus

 

전체 Article 조회하기
Article.objects.all()

Article을 생성하는 다른 방법
1. article = Article(title='second_title', content='my_content')
article.save()

2. article = Article()
article.title = 'first_title'
article.content = 'my_content'

중요!
# 여기에서 전체 Article을 조회해보면
Article.objects.all() # 비어있다

# save()하기전에는 저장되지 않음
article.save()

# 다시 전체 Article을 조회해보면 하나의 아티클이 있음
Article.objects.all()


# 속성 하나씩 접근하기
# 제목 
article.title

# 내용
article.content

# 생성일시
article.create_at

# pk(id)
article.id

3. Article.objects.create(title='third title', content='마지막 방법임')
# save()가 필요하지 않음

이건 클래스에서 각각 변수를 지정해 줬기 때문에 쓸 수 있다.

__str__ 사용하기
class Article(models.Model):
    title = models.CharField(max_length=50)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.title
Article Object 보다 파악하기 쉽습니다.
Article Class를 문자열 취급했을 때 처리하는 로직을 작성할 수 있습니다.


추가

하나의 Article만 조회하기
Article.objects.get(id=1)
- 딱 1개의 조회가 필요할 때 사용합니다.
- 조건에 해당하는 객체가 없다면 DoesNotExist 예외를 발생시킴 (터진다는 소리)
- 한 개 이상의 객체가 리턴될 경우도 MulipleObjectReturned 예외를 발생시킴 (터진다는 소리)
즉, 하나의 변수에 여러개의 값이 있을 때 오류가 남

하나의 Article만 조회하기(예외발생)
Article.objects.get(content='my_content') # 두개 리턴되어 에러 

조건 주기
Article.objects.filter(id__gt=2) # 2보다 큰 id
Article.objects.filter(id__in=[1,2,3]) # 1,2,3에 속하는 id
Article.objects.filter(content__contains='my') # content에 'my'가 포함된

값 업데이트
article = Article.objects.get(id=1)
article.title = 'updated title'
article.save()

값 삭제
article = Article.objects.get(id=2)
article.delete()

전체적 흐름 파악(MVT)
먼저,
1. Views
/articles/ 로 들어오면 아래의 articles.html 템플릿이 랜더링되어 보이도록하기
path("", views.articles, name="articles"),

articles의 views.py에 추가
def articles(request):
		return render(request, "articles.html")

2. Templates
articles의 templates에 articles.html
{% extends 'base.html' %}

{% block content %}
<h1>Articles</h1>
		
{% endblock content %}​​

 

3. Models
from .models import Article
...

def articles(request):
    articles = Article.objects.all()
    context = {
        "articles": articles,
    }
    return render(request, "articles.html", context)

위에서 배운 방식으로 Article.objects.all()을 통해 값을 전부 가져와 context에 넣기

{% extends "base.html" %}

{% block content %}
    <h1>Articles</h1>

    <ul>
        {% for article in articles %}
            <li>
                <div>글 번호 : {{ article.id }}</div>
                <div>글 제목 : {{ article.title }}</div>
                <div>글 내용 : {{ article.content }}</div>
                <br>
            </li>
        {% endfor %}
    </ul>

{% endblock content %}​

이건, 하나의 흐름이다 models에서 값을 가져와, templates에 넣고, views를 통해서 연결시키는 것이다.


값을 추가할 때,
클라이언트에서 서버에 데이터를 전송하여 저장하면 편하다.
form을 이용하면 됩니다!
먼저, /articles/new/로 들어오면 아래의 화면이 보이도록 작성, 그리고 작성된 form을 보내는곳은 /articles/create/

 


참고로 최신순으로 값을 올릴 수 있다.


혹은 created_at을 쓰면 된다.


원하면 id도 불러올 수 있다

id말고 pk도 가능(둘이 똑같음)


GET과 POST의 차이

1. 서버 처리 방식
GET: 데이터를 읽는 데 사용되며, 서버 상태를 바꾸지 않습니다.
예: 검색, 페이지 조회
POST: 서버 상태를 바꾸거나 데이터를 저장하는 데 사용됩니다.
예: 회원가입, 게시물 작성, 결제
2. 요청의 목적
GET은 데이터를 요청(조회)하기 위해,
POST는 데이터를 서버에 보내고 저장하거나, 작업을 실행하기 위해 사용됩니다.
3. 캐싱
GET 요청은 캐싱될 수 있습니다.
예를 들어 브라우저는 같은 GET 요청을 다시 할 때 서버에 가지 않고 저장된 결과를 보여줄 수 있습니다.
POST 요청은 캐싱되지 않습니다.
매번 새로운 데이터를 서버에 보내야 합니다.
4. 보안
GET은 데이터가 URL에 그대로 노출되므로, 보안에 취약합니다.
예: 비밀번호, 신용카드 정보를 GET 요청으로 보내면 위험.
POST는 데이터가 요청 본문에 숨겨져 있어 상대적으로 안전합니다.
하지만 SSL(HTTPS)을 사용하지 않으면 여전히 데이터가 노출될 수 있습니다.
5. 데이터 크기
GET 요청은 URL 길이에 제한이 있습니다. (보통 2048자 제한)
POST 요청은 본문(body)에 데이터를 담기 때문에 데이터 크기 제한이 없습니다.

403 Forbidden 해결
이렇게, 또 

이렇게 바꾸면 403 접근 금지를 보게된다. 왜? CSRF 토큰 때문에

POST 요청에서 403 Forbidden 해결하기
CSRF 토큰 확인
Django나 Flask 같은 서버는 보안상 CSRF 토큰을 요구할 수 있어요. 유저가 서버에 요청을 보낼 때 함께 제공되는 특별한 토큰 값으로, 이 토큰은 사용자의 세션과 연결되어 있습니다. 요청이 전송될 때, 함께 제출되며 서버는 요청을 받을 때 이 토큰을 검증하여 요청이 유효한지 확인하는 방식으로 CSRF을 방지합니다.
HTML 폼에 보안 토큰을 추가하세요:
일반적으로 GET을 제외한 데이터를 변경하는 Method에 적용합니다.
<input type="hidden" name="csrfmiddlewaretoken" value="your_csrf_token_here">
아니면 장고에서는 

이렇게 어디로 데이터를 보내야 한다면 보내는 쪽 코드에 저렇게 {% csrf_token %}이라고 넣어주면 장고가 알아서 넣어준다. 즉, <form>에다가 POST를 쓰면 csrf를 써야한다.

혹시 모르니 추가적으로
권한 확인
서버가 POST 요청을 처리할 권한이 있는지 확인하세요.
인증이 필요한 API라면, 로그인 상태여야 할 수도 있습니다.

HTTP 메소드 허용 확인
서버가 POST 요청을 지원하는지 확인하세요.
예: Django에서는 @require_http_methods(["POST"]) 같은 설정이 필요할 수 있습니다.
POST 요청 예시
<form action="/submit" method="POST">
  <input type="text" name="username" placeholder="Enter your username">
  <input type="password" name="password" placeholder="Enter your password">
  <input type="hidden" name="csrfmiddlewaretoken" value="your_csrf_token_here">
  <button type="submit">Submit</button>
</form>