4 분 소요

장고 쉘 사용 방법

python manage.py shell

from django.db import connection
cursor = connection.cursor()
connection.close()
exit()
  • python manage.py dbshell 명령 시에 sqlite3 명령을 못 찾는다는 에러가 출력되시는 분은 https://www.inflearn.com/chats/483009 포스팅을 참고해주세요.

모델명과 DB 테이블명

DB 테이블명 : 디폴트 “앱이름_모델명”

예)

blog앱
    Post 모델 -> "blog_post"
    comment 모델 -> "blog_comment"

Shop앱
    Item 모델 -> "shop_item"
    Review 모델 -> "shop_review"

커스텀 지정
    모델 Meta 클래스의 db_table 속성
  • 모델 생성 후 해야할 일
  1. python manage.py makemigrations 앱이름
  2. python manage.py migrate 앱이름
    • 모델 생성 확인
    • python manage.py sqlmigrate 앱이름 0001_initial

기본 지원되는 모델필드 타입(1)

  • Primary Key: AutoField, BigAutoField
  • 문자열: CharField, TextField, SlugField
  • 날짜/시간: DateField, TimeField, DateTimeField, DurationField
  • 참/거짓: BooleanField, NullBooleanField
  • 숫자: IntegerField, SmallIntegerField, PositiveIntegerField,
  • PositiveSmallIntegerfield, BigIntegerField, DecimalField, FloatField
  • 파일: BinaryField, FileField, ImageField, FilePathField

기본 지원되는 모델필드 타입(2)

  • 이메일: EmailField
  • URL: URLField
  • UUID: UUIDField
  • 아이피: GenericIPAddressField
  • Relationship Types
  • ForeignKey
  • ManyToManyField
  • OneToOneField

  • AutoField -> int
  • BinaryField -> bytes
  • BooleanField -> bool
  • CharField/SlugField/URLField/EmailField -> str -> 디폴트 적용된 유효성 검사 등의 차이

자주 쓰는 필드 공통 옵션

  • blank : 장고 단에서 validation시에 empty 허용 여부 (디폴트: False)
  • null (DB 옵션) : null 허용 여부 (디폴트: False)
  • db_index (DB 옵션) : 인덱스 필드 여부 (디폴트: False)
  • default : 디폴트 값 지정, 혹은 값을 리턴해줄 함수 지정. 사용자에게 디폴트값을 제공코자 할 때
  • unique (DB 옵션) : 현재 테이블 내에서 유일성 여부 (디폴트: False)
  • choices : select 박스 소스로 사용
  • validators : validators를 수행할 함수를 다수 지정 모델 필드에 따라 고유한 validators들이 등록 (ex- 이메일만 받기)
  • verbose_name : 필드 레이블, 미지정시 필드명이 사용
  • help_text : 필드 입력 도움말

모델 선언 예시

from django.conf import settings
from django.db import models
class Profile(models.Model):
    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    blog_url = models.URLField(blank=True)

class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    title = models.CharField(max_length=100, db_index=True)
    slug = models.SlugField(allow_unicode=True, db_index=True) # ModelAdmin.prepopulated_fields 편리
    desc = models.TextField(blank=True)
    image = models.ImageField(blank=True) # Pillow 설치가 필요
    comment_count = models.PositiveIntegerField(default=0)
    tag_set = models.ManyToManyField('Tag', blank=True)
    is_publish = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

class Comment(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    message = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

class Tag(models.Model):
    name = models.CharField(max_length=50, unique=True)

모델 클래스를 admin에 등록하기

from django.contrib import admin
from .models import Item

# 등록법 #1
admin.site.register(Item) # 기본 ModelAdmin으로 동작

# 등록법 #2
class ItemAdmin(admin.ModelAdmin):
    pass
admin.site.register(Item, ItemAdmin) # 지정한 ModelAdmin으로 동작

# 등록법 #3
@admin.register(Item)
class ItemAdmin(admin.ModelAdmin):
    pass

모델 클래스에 str 구현

객체를 출력할 때, 객체.str()의 리턴값을 활용

from django.db import models

class Item(models.Model):
    name = models.CharField(max_length=100)
    desc = models.TextField(blank=True)
    price = models.PositiveIntegerField()
    is_publish = models.BooleanField(default=False)

    def __str__(self):
        return f'<{self.pk}> {self.name}'

admin 페이지에서 __str__의 return 값이 제목으로 보여지게 됨.

list_display 속성 정의

from django.contrib import admin
from .models import Item

@admin.register(Item)
class ItemAdmin(admin.ModelAdmin):
    list_display = ['pk', 'name', 'short_desc', 'price', 'is_publish']
    def short_desc(self, item):
        return item.desc[:20]

admin 페이지의 제목칸에 list_display로 설정해 놓은 값들이 보임

shell을 통한 모델 확인법

  1. python manage.py shell
  2. from 앱이름.models import 모델명
  3. 모델명.objects.all()

Media 파일 처리 순서

  1. HttpRequest.FILES를 통해 파일이 전달
  2. 뷰 로직이나 폼 로직을 통해, 유효성 검증을 수행하고,
  3. FileField/ImageField 필드에 ”경로(문자열)”를 저장하고,
  4. settings.MEDIA_ROOT 경로에 파일을 저장합니다.

Media 파일, 관련 setiings 예시

  • 각 설정의 디폴트 값
    • MEDIA_URL = “”
      • 각 media 파일에 대한 URL Prefix
        • 필드명.url 속성에 의해서 참조되는 설정
    • MEDIA_ROOT = “”
      • 파일필드를 통한 저장 시에, 실제 파일을 저장할 ROOT 경로
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

FileFiled와 ImageField

  • FileField
    • File Storage API를 통해 파일을 저장
      • 장고에서는 File System Storage만 지원. django-storages를 통해 확장 지원.
    • 해당 필드를 옵션 필드로 두고자 할 경우, blank=True 옵션 적용
  • ImageField (FileField 상속)
    • Pillow (이미지 처리 라이브러리)를 통해 이미지 width/height 획득
      • Pillow 미설치 시에, ImageField를 추가한 makemigrations 수행에 실패합니다.
  • 위 필드를 상속받은 커스텀 필드를 만드실 수도 있습니다.
    • ex) PDFField, ExcelField 등
  • 프로젝트를 할 때에 패키지를 다운받을때마다 manage.py 가 있는 경로에 requirements.txt 라는 파일을 생성해서 어떤 버전의 무슨 파일을 받았는지 기입.
django~=3.0.0
pillow
  • 그리고 나서 pip install -r requirements.txt 하게 되면 한번에 패키지들이 설치가 된다.

모델 필드 예시

class Post(models.Model):
    author_name = models.CharField(max_length=20)
    title = models.CharField(max_length=100)
    content = models.TextField()
    photo = models.ImageField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
# settings.py
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
  • 포스트를 만들 때 photo 이미지 파일을 업로드 해주면 자동으로 media 디렉토리 생성 후 파일 저장됨.
    • 그 역할이 MEDIA_ROOT = os.path.join(BASE_DIR, ‘media’)이다.
  • 그 파일을 클릭하면 media/파일명 url을 타고 이동하게 되는데 앞에 기본 url인 media가 MEDIA_URL 이다.

URL에 Media 세팅 적용 및 admin 페이지에서 적용 방법

  • url로 이동
  • from django.conf import settings
  • from django.conf.urls.static import static

      if settings.DEBUG:
          urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)    
    
    • 이렇게 설정을 해주면 admin 페이지에서 업로드된 사진을 클릭했을때 해당 url로 이동해서 사진을 보여주게 됨.
  • admin 회원 관리에서 이미지 파일을 바로 보고 싶은 경우
    1. admin 파일에 list_display 항목에 photo와 관련된 이름 등록
    2. 예를들어 photo_tag라는 이름을 등록했다면
      def photo_tag(self, post):
          if post.photo:
              return mark_safe(f'<img src="{post.photo.url}" style="width: 72" />')
          return None
    
    1. 이렇게 설정을 하면 admin 페이지에서 img를 업로드한 회원의 img를 바로 볼 수 있음.

사용할 만한 필드 옵션

  • blank 옵션
    • 업로드 옵션처리 여부
    • 디폴트 : False
  • upload_to 옵션
    • settings.MEDIA_ROOT 하위에서 저장한 파일명/경로명 결정
    • 디폴트 : 파일명 그대로 settings.MEDIA_ROOT 에 저장
      • 추천) 성능을 위해, 한 디렉토리에 너무 많은 파일들이 저장되지 않도록 조정하기
    • 동일 파일명으로 저장 시에, 파일명에 더미 문자열을 붙여 파일 덮어쓰기 방지
      photo = models.ImageField(black=True, upload_to='instagram/post/%Y/%m/%d')
    
    • 이렇게 쓰면 위에서 적용했던 MEDIA_ROOT 인 media 파일에 instagram이라는 폴더를 만들고 post라는 폴더를 만들고 년/월/일 로 폴더를 더 만들어서 저장하게 됨.
    • 물론 파일을 클릭했을때의 url도 이와 같이 변함.
    • 이렇게 이용하면 파일이 쌓여도 유지 관리하기 편해짐.
    • 혹은 함수를 이용해서 파일 저장 경로를 설정해줄 수 있다.
      import os
      from uuid import uuid4
      from django.utils import timezone
        
      def uuid_name_upload_to(instance, filename):
          app_label = instance.__class__._meta.app_label # 앱 별로
          cls_name = instance.__class__.__name__.lower() # 모델 별로
          ymd_path = timezone.now().strftime('%Y/%m/%d') # 업로드하는 년/월/일 별로
          uuid_name = uuid4().hex
          extension = os.path.splitext(filename)[-1].lower() # 확장자 추출하고, 소문자로 변환
          return '/'.join([
              app_label,
              cls_name,
              ymd_path,
              uuid_name[:2],
              uuid_name + extension,
          ])
    

템프릿에서 media URL 처리 예시

  • 필드의 .url 속성을 활용하세요.
    • 내부적으로 settings.MEDIA_URL과 조합을 처리
      <img src="" %}" />
    
    • 필드에 저장된 경로에 없을 경우, .url 계산에 실패함에 유의. 그러니 안전하게 필드명 저장유무를 체크
        
    
  • 참고
    • 파일 시스템 상의 절대경로가 필요하다면, .path 속성을 활용하세요.
      • settings.MEDIA_ROOT와 조합

댓글남기기