Search
castle

MVT

image.png

  • 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>의 프로젝트 생성

image.png

image.png

  • 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.

image.png


(venv_django) λ python manage.py makemigrations
Migrations for 'blog':
  blog\migrations\0001_initial.py
    + Create model Post

django files

urls.py

  • projecturlpatterns
    • path('<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 공통 속성 및 메서드 정리표

    구분 이름 설명
    속성 null True이면 DB에서 NULL 허용
      blank True이면 form 유효성 검사 시 빈값 허용
      choices 선택지 목록 지정 (ex: [(1, '남자'), (2, '여자')])
      default 기본값 설정
      primary_key 해당 필드를 기본 키로 설정
      unique 고유값 여부 설정
      db_index 데이터베이스 인덱스 생성 여부
      editable Admin 등에서 수정 가능 여부 (False면 읽기 전용)
      help_text Admin 등에서 도움말로 표시되는 텍스트
      verbose_name 필드의 사람이 읽을 수 있는 이름
      auto_now DateTimeField 전용. 매 저장 시 현재 시간 자동 저장
      auto_now_add DateTimeField 전용. 생성 시 한 번만 현재 시간 저장
      max_length 문자열 필드에서 최대 길이 지정
      upload_to FileField, ImageField의 업로드 경로
      validators 유효성 검사 함수 목록 지정
      db_column 실제 DB 컬럼명 명시 (기본은 필드명)
      related_name 관계 모델에서 역참조 시 사용하는 이름
      on_delete ForeignKey, OneToOneField 등에서 삭제 시 동작 정의
    메서드 get_internal_type() 필드의 내부 타입 문자열 반환 (ex: CharField)
      value_from_object(obj) 객체에서 이 필드의 값을 가져옴
      deconstruct() 마이그레이션 시스템을 위한 정보 반환
  • 관계 필드 (ForeignKey, OneToOneField, ManyToManyField) 추가 속성

    필드 타입 속성 설명
    ForeignKeyOneToOneField to 연결 대상 모델 (User, Category 등)
      on_delete 참조된 객체 삭제 시 동작 (CASCADE, SET_NULL, 등)
      related_name 역참조 시 사용될 이름
      limit_choices_to Admin 등에서 선택 가능 항목 제한 조건
    ManyToManyField through 중개 모델 지정
      symmetrical 자기 자신을 참조할 때 관계 대칭 여부 설정
      related_query_name 쿼리셋에서 역참조 시 사용하는 이름 지정

App

생성

  • python manage.py startapp <app_name> : <app_name>이름의 app 생성
    • model.py : 기능 설정 파일
    • view.py : url에서 받은 메소드 실행
    • template.py : controll에 해당, 생성 예정

image.png

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)

image.png


image.png

templates

rendering할 html 파일 디렉토리

  • templates/<app_name> : app(<app_name>)의 html 상위 경로

image.png

View

  • FBV(Function Based View)
  • CBV(Class Based View)
  • def func(request) : request(event) 발생 시 실행할 함수 정의
  • from django.shortcuts import render : responsehttp
    • request : 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 %}
...   
             

image.png

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

image.png

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을 설정해야 이미지가 나옴
  • 일반적으로 null data 존재 시 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 요청 → /create url→ 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 class
    • fields : 사용 혹은 입력받을 데이터 속성
# 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>]) : return ModelFrom instance
    • forms.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')

left
right

C

Contents