[django] 모델
장고 쉘 사용 방법
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 속성
- 모델 생성 후 해야할 일
- python manage.py makemigrations 앱이름
- 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을 통한 모델 확인법
- python manage.py shell
- from 앱이름.models import 모델명
- 모델명.objects.all()
Media 파일 처리 순서
- HttpRequest.FILES를 통해 파일이 전달
- 뷰 로직이나 폼 로직을 통해, 유효성 검증을 수행하고,
- FileField/ImageField 필드에 ”경로(문자열)”를 저장하고,
- settings.MEDIA_ROOT 경로에 파일을 저장합니다.
Media 파일, 관련 setiings 예시
- 각 설정의 디폴트 값
- MEDIA_URL = “”
- 각 media 파일에 대한 URL Prefix
- 필드명.url 속성에 의해서 참조되는 설정
- 각 media 파일에 대한 URL Prefix
- MEDIA_ROOT = “”
- 파일필드를 통한 저장 시에, 실제 파일을 저장할 ROOT 경로
- MEDIA_URL = “”
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
FileFiled와 ImageField
- FileField
- File Storage API를 통해 파일을 저장
- 장고에서는 File System Storage만 지원. django-storages를 통해 확장 지원.
- 해당 필드를 옵션 필드로 두고자 할 경우, blank=True 옵션 적용
- File Storage API를 통해 파일을 저장
- ImageField (FileField 상속)
- Pillow (이미지 처리 라이브러리)를 통해 이미지 width/height 획득
- Pillow 미설치 시에, ImageField를 추가한 makemigrations 수행에 실패합니다.
- Pillow (이미지 처리 라이브러리)를 통해 이미지 width/height 획득
- 위 필드를 상속받은 커스텀 필드를 만드실 수도 있습니다.
- 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 회원 관리에서 이미지 파일을 바로 보고 싶은 경우
- admin 파일에 list_display 항목에 photo와 관련된 이름 등록
- 예를들어 photo_tag라는 이름을 등록했다면
def photo_tag(self, post): if post.photo: return mark_safe(f'<img src="{post.photo.url}" style="width: 72" />') return None
- 이렇게 설정을 하면 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와 조합
- 파일 시스템 상의 절대경로가 필요하다면, .path 속성을 활용하세요.
댓글남기기