MVT

- MVC(Model, View, Controller)
- MVT(Model, View, Templete)
- database 관련
HTTP에서 url 요청URLS: url의 요청을 View의 메소드 연결View:URLS에서 받은Template연결, 이벤트 처리Model: DB 처리/설계
블로그 구조
| 내용 | html action | 주소(localhost:port 생략) | url 경로 및 랜더링 설정 파일 |
|---|---|---|---|
| home | GET | /blog | |
| 전체글 보기 | GET | / | views.index→index.html |
| 상세글 보기 | GET | /blog/{pk} | views.detail→detail.html |
| 글쓰기 | POST | /blog/create | views.create→postform.html |
| 글 삭제하기 | GET | /blog/{pk}/delete/ | views.delete → index.html(redirect) |
| 글 수정하기 | GET, POST | /blog/{pk}/update/ | views.update → postupdate.html → index.html(redirect, 정상)/return(redirect, 비정상) |
Project 생성&실행
django-admin startproject <project_name> <path>:<project_name>의 프로젝트 생성


python manage.py runserver: localhost에 웹 실행python manage.py createsuperuser: admin서버 생성localhost/admin: admin 싸이트 접속
migrate: 데이터베이스에 적용시켜야 하는 변화에 대한 기록python manage.py makemigrations: 모델을 수정했다고 알림, settings 적용python manage.py migrate: data 관련 table 생성,db.sqlite생성
C:\Users\user\Desktop\sessac\django_ws\django_practice (main -> origin)
(venv_django) λ python manage.py createsuperuser
Username (leave blank to use 'user'): admin
Email address: admin@admin.com
Password:
Password (again):
This password is too short. It must contain at least 8 characters.
This password is too common.
This password is entirely numeric.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

(venv_django) λ python manage.py makemigrations
Migrations for 'blog':
blog\migrations\0001_initial.py
+ Create model Post
django files
urls.py
project의urlpatternspath('<url>', <target_urls.py>):...(localhost/site)/<url>주소 호출 시<target_urls.py>실행
# project urls.py
from django.contrib import admin
from django.urls import path, include
# http://127.0.0.1:8000/
urlpatterns = [
path("admin/", admin.site.urls), # admin 계정 실행
path('', include('single_pages.urls')),
'''
localhost:8000/ -> single_pages 앱의 urls.py 실행
'''
path('blog/', include('blog.urls')),
'''
localhost:8000/blog -> blog앱의 urls.py 실행
'''
]
urlpatterns:apps.py에 명시된 app 경로 생성path("<url>/", <execute>),:...(localhost/site)/<url>의 주소 받을 시<execute>실행
# blog urls.py
# from django_project_practice.urls import urlpatterns
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'), # 127.0.0.1:8000/blog/
path('<int:pk>/', views.detail, name='pk'),
# 127.0.0.1:8000/blog/{pk}/, views.detail : 블로그 상세페이지
]
settings.py
- app 경로 표시
- 기타 환경 설정
...
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"single_pages",
"blog"
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
...
models.py
from django.db import models- django.db document
- db 설정(no SQL)
- db용 class 생성
- db생성이므로 db오류도 신경써야함
(django.db.models).objects: DB 쿼리 실행 클래스Post.objects.all(): SELECT * FROM POST
# blog/models.py
from django.contrib.auth.models import User
from django.db import models
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
create_date = models.DateTimeField()
def __str__(self):
return f'post title : {self.title}\ncontent : {self.content}'
...
| data : | title | content | create_date | author | … |
| — | — | — | — | — | — |
get_absolute_url: return 경로
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
create_date = models.DateTimeField()
def __str__(self):
return f'post title : {self.title}\ncontent : {self.content}'
def get_absolute_url(self):
return f'/blog/{self.pk}/' # return url 지정
# return reverse("model_detail", kwargs={"pk": self.pk})
<!-- blog/templates/blog/index.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Blog</title>
</head>
<body>
blog<br>
전체글 리스트<br>
posts - post 리스트
</body>
</html>
models DB
- 속성, 관계, 타입 메소드
- 타입
| 필드 타입 | 필수/주요 속성 |
| — | — |
| CharField | max_length |
| TextField | - |
| IntegerField | - |
| FloatField | - |
| DecimalField | max_digits, decimal_places |
| BooleanField | default=True/False |
| DateField | auto_now, auto_now_add |
| DateTimeField | auto_now, auto_now_add |
| FileField / ImageField | upload_to |
-
django.db.models.Field공통 속성 및 메서드 정리표구분 이름 설명 속성 nullTrue이면 DB에서NULL허용blankTrue이면 form 유효성 검사 시 빈값 허용choices선택지 목록 지정 (ex: [(1, '남자'), (2, '여자')])default기본값 설정 primary_key해당 필드를 기본 키로 설정 unique고유값 여부 설정 db_index데이터베이스 인덱스 생성 여부 editableAdmin 등에서 수정 가능 여부 ( False면 읽기 전용)help_textAdmin 등에서 도움말로 표시되는 텍스트 verbose_name필드의 사람이 읽을 수 있는 이름 auto_nowDateTimeField전용. 매 저장 시 현재 시간 자동 저장auto_now_addDateTimeField전용. 생성 시 한 번만 현재 시간 저장max_length문자열 필드에서 최대 길이 지정 upload_toFileField,ImageField의 업로드 경로validators유효성 검사 함수 목록 지정 db_column실제 DB 컬럼명 명시 (기본은 필드명) related_name관계 모델에서 역참조 시 사용하는 이름 on_deleteForeignKey,OneToOneField등에서 삭제 시 동작 정의메서드 get_internal_type()필드의 내부 타입 문자열 반환 (ex: CharField)value_from_object(obj)객체에서 이 필드의 값을 가져옴 deconstruct()마이그레이션 시스템을 위한 정보 반환 -
관계 필드 (
ForeignKey,OneToOneField,ManyToManyField) 추가 속성필드 타입 속성 설명 ForeignKeyOneToOneFieldto연결 대상 모델 ( User,Category등)on_delete참조된 객체 삭제 시 동작 ( CASCADE,SET_NULL, 등)related_name역참조 시 사용될 이름 limit_choices_toAdmin 등에서 선택 가능 항목 제한 조건 ManyToManyFieldthrough중개 모델 지정 symmetrical자기 자신을 참조할 때 관계 대칭 여부 설정 related_query_name쿼리셋에서 역참조 시 사용하는 이름 지정
App
생성
python manage.py startapp <app_name>:<app_name>이름의 app 생성model.py: 기능 설정 파일view.py: url에서 받은 메소드 실행template.py: controll에 해당, 생성 예정

admin.py
admin.site.register(<DB_class>):models에 정의된 DB 클래스를 admin 페이지에 랜더링
# blog\admin.py
from django.contrib import admin
from .models import Post, Category
# Register your models here.
admin.site.register(Post)
admin.site.register(Category)


templates
rendering할 html 파일 디렉토리
templates/<app_name>: app(<app_name>)의html상위 경로

View
- FBV(Function Based View)
- CBV(Class Based View)
def func(request):request(event) 발생 시 실행할 함수 정의from django.shortcuts import render: response → httprequest: HttpRequest를 받는 인자template_name: rendring할html파일 지정context={'<var>' : <data>}: html에 넘겨줄 데이터(<data>), 변수 이름(<var>)
(function) def render(
request: HttpRequest,
template_name: str | Sequence[str],
context: Mapping[str, Any] | None = ...,
content_type: str | None = ...,
status: int | None = ...,
using: str | None = ...
) -> HttpResponse
# blog/views.py
from django.shortcuts import render
from .models import Post
# Create your views here.
def index(request):
# posts_total_list = Post.objects.all() # db SELECT * FROM POST
posts_total_list = Post.objects.all().order_by('-pk') # db SELECT * FROM POST ... ASC
return render(request,
template_name='blog/index.html',
context={'posts':posts_total_list},
)
def detail(request, pk):
posts_page_list = Post.objects.get(pk=pk)
return render(request,
template_name='blog/detail.html',
context={'post_page' : posts_page_list})
<!-- templates/blog/index.html -->
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Blog</title>
</head>
<body>
blog<br>
전체글 리스트<br>
posts - post 리스트
</body>
</html>
Static
정적 파일 지정 directory
settings.py: static 경로 지정.html에 static 선언 필요
- header에
load static선언{% static "<app>/<image_path>" %}: 로 사용
# django_project_practice\settings.py
...
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.2/howto/static-files/
STATIC_URL = "static/"
# Default primary key field type
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
# blog\templates\blog\index.html
<!DOCTYPE html>
{% load static %}
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Blog</title>
...
# blog\templates\blog\index.html
...
{% for post in posts%}
<!-- Featured blog post-->
<div class="card mb-4">
<a href="{{ post.get_absolute_url }}"><img class="card-img-top" src={% "blog/images/image.png" %} alt="..." /></a>
<div class="card-body">
<div class="small text-muted">{{ post.create_date }}</div>
<h2 class="card-title">{{ post.title }}</h2>
<p class="card-text">{{ post.content }}</p>
<a class="btn btn-primary" href="{{ post.get_absolute_url }}">Read more →</a>
</div>
</div>
{% endfor %}
...

- 보통 트리 설정을 이렇게 한다고 한다

dynamic
- media : 서비스 사용자가 업로드하는 파일
settings.py: 저장 경로 및 root url 설정MEDIA_ROOT: media 저장 directory 설정MEDIA_URL: root url 설정
urls.py:settings.py의 설정을 가져와urlpatterns설정urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# django_project_practice\settings.py
...
MEDIA_ROOT = os.path.join(BASE_DIR, '_media')
MEDIA_URL = '/media/'
# django_project_practice\urls.py
from django.conf.urls.static import static
from django_project_practice import settings
...
urlpatterns = [
path("admin/", admin.site.urls),
path('', include('single_pages.urls')),
path('blog/', include('blog.urls')),
path('library/', include('library.urls')),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
ImageField타입의 이미지 DB 생성- 이미지 처리 패키지(pillow) 설치 필요
# blog\models.py
class Post(models.Model):
...
uploaded_image = models.ImageField(upload_to='images/', null=True)
...
<post>.<image_var>.url:<post>post 변수,<image_var>이미지 변수 +url을 설정해야 이미지가 나옴- 일반적으로
nulldata 존재 시 if문과 함께 사용
# blog\templates\blog\detail.html
...
<!-- Preview image figure-->
<figure class="mb-4"><img class="img-fluid rounded" src="https://i.namu.wiki/i/abZPxKt_L98I8ttqw56pLHtGiR5pAV4YYmpR3Ny3_n0yvff5IDoKEQFof7EbzJUSZ_-uzR5S7tzTzGQ346Qixw.webp" alt="..." /></figure>
...
create
- html
POST요청 →/createurl→view.create실행- 정상 작성 → DB저장 → 게시판 리스트(기존 경로 등)으로 redirect
- valid하지 않는 경우 → 다시 쓰라고 알림 → postform.html
html 요청 메소드
HTTP는 요청 메서드를 정의하여, 주어진 리소스에 수행하길 원하는 행동을 나타냅니다. 간혹 요청 메서드를 “HTTP 동사”라고 부르기도 합니다. 각각의 메서드는 서로 다른 의미를 구현하지만, 일부 기능은 메서드 집합 간에 서로 공유하기도 합니다. 이를테면 응답 메서드는 안전하거나, 캐시 가능하거나, 멱등성을 가질 수 있습니다.
| 메서드(Method) | 설명 | 사용 예시 |
|---|---|---|
| GET | 서버에서 리소스를 조회. 데이터를 가져오기 위한 요청. | 페이지 로딩, API 조회 등 |
| POST | 서버에 새 리소스를 생성. 주로 폼 데이터 전송 등에 사용. | 회원가입, 게시글 작성 등 |
| PUT | 서버의 기존 리소스를 전체 수정. 존재하지 않으면 생성될 수도 있음. | 게시글 전체 수정 |
| PATCH | 서버의 기존 리소스를 부분 수정. 일부 필드만 업데이트. | 게시글 제목만 수정 등 |
| DELETE | 서버의 리소스를 삭제. | 게시글 삭제, 계정 삭제 등 |
| HEAD | GET과 동일하되, 응답 본문 없음. 헤더 정보만 필요할 때 사용. | 리소스 존재 여부 확인 등 |
| OPTIONS | 해당 리소스에서 지원하는 메서드 목록 반환. | CORS 사전 요청 등 |
| CONNECT | 프록시 서버와 터널링을 위해 연결. 주로 HTTPS에 사용됨. | SSL 터널링 |
| TRACE | 요청을 따라가면서 루프백 테스트 수행. 보안상 거의 사용하지 않음. | 디버깅용 (실제로는 거의 안 씀) |
html 설정
<form action='' method='post'>action: event 발생 시 이동 url, 생략 시 현재 경로method: post, get 등 처리 방법- http 요청 메서드
get: 처음 form 입력 대기 상태post: 입력 완료 후action이동 및 기타 실행
{% csrf_token %}: token 발행, 낚시 서버 방지
# blog\templates\blog\postform.html
<html lang='ko'>
<body>
<form action='' method='post'>
{% csrf_token %}
{{ form }}
<input type='summit'>
</form>
</body>
forms.py
html에서 사용할 form(입력 형식) 설정- 고정된 형식 사용, 오타 조심
model: 사용할 DB classfields: 사용 혹은 입력받을 데이터 속성
# blog\forms.py
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta: # class 설명
model = Post
fields = ['title', 'content', 'uploaded_image', ...]
# 속성값 입력, template, 오타 조심
view.py: form request<forms.ModelForm>([request.<types>]): returnModelFrominstanceforms.py에서 선언한 class(<forms.ModelForm>)의__call__메소드- 인자로
request.POST,request.FILES등 event를 받음 - HTML 요청을 받아 ModelForm 형태의 객체 반환
<반환된 instance>.save(commit)commit=False: DB에 저장X(commit 미 실행), model instance 반환
# blog\views.py
...
def create(request):
if request.method == 'POST': # 제출 버튼
postform = PostForm(request.POST, request.FILES)
if postform.is_valid(): # 작성 도중 제출 버튼 누른경우
temp_post = postform.save(commit=False) # 저장 메소드를 가진 객체 반환
if '--' not in temp_post.title:
temp_post.save()
return redirect('/blog/')
temp_post.title += ' injection' # 제출 시 추가 동작 실행
# temp_post.author = request.user
temp_post.save() # 정상적인 경우 -> DB 저장
return redirect('/blog/') # blog로 돌아감
else : # GET 요청, 새글 작성(빈 객체 생성, 랜더링)
postform = PostForm()
return render(request,
template_name='blog/postform.html',
context={'postform' : postform},
)
def createfake(request):
post = Post()
post.title = ' fake post title'
post.content = 'fake post content'
post.save()
return redirect('/blog/')
# return redirect('index')
C
Contents
