장고 모델과 모델
모델 필드 choices옵션
class Review(models.Model):
RATING_CHOICES = [
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
]
rating = models.IntegerField(choices=RATING_CHOICES)
튜플에서 첫 번째 값은 모델 필드에 실제로 들어가는 값이고 두 번째 값은 디스플레이에 사용되는 값이다.
즉 모델에는 첫 번째 값이 저장되고 화면에 출력되는 값은 두 번째 값이다.
정적파일
settings.py에서 STAITC_URL은 기본적으로 “/static/”으로 되어있고 이 경우엔
localhost:8000/static/파일 경로…
가 정적파일의 url경로가 된다.
localhost:8000/static/coplate/styles/style.css 이런식으로 접근할 수 있다.
“/static/”은 url주소에 사용되는 이름이고 프로젝트 내에서의 디렉토리 경로와는 상관이 없다.
장고가 정적파일의 주소를 보고 알맞은 정적파일을 찾아 돌려준다.
템플릿에서 {% static ‘’ %} 이렇게 스태틱 태그와 스태틱 폴더 내에서의 파일 경로를 작성하면 정적파일의 경로를 참조해서 url로 돌려준다.
static file, media file
스태틱 파일은 css같이 정해져 있는 정적 파일을 말한다.
STATIC_URL과 스태틱 태그를 사용한다.
폴더를 [앱이름]/static/[앱이름] 이런식으로 정해진 이름과 샌드위치 구조로 만들기 때문에 장고가 알아서 스태틱 파일들을 찾을 수 있다.
미디어 파일은 유저가 업로드한 정적 파일을 말한다.
MEDIA_URL을 사용한다.
미디어 파일은 폴더를 만들 때 정해진 이름이나 구조가 없기 때문에 장고에게 알려줘야 한다. 이 때 사용하는게 MEDIA_ROOT 이다.
미디어 파일을 설정하려면
프로젝트 앱 폴더 밖에 미디어 파일을 담을 폴더를 생성한다.
폴더를 media/review_pics이렇게 생성했다고 하면
setting.py에 MEDIA_URL = ‘/uploads/’ 이런식으로 사용할 url을 작성하고
MEDIA_ROOT = os.path.join(BASE_DIR, “media”) 이렇게 방금 만들어둔 폴더의 이름을 지정한다.
그리고 프로젝트 앱의 urls에서
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)
이렇게 작성한다.
(settings.MEDIA_URL)미디어 파일에 대한 요청이 들어오면 (document_root=settings.MEDIA_ROOT)MEDIA_ROOT안에 있는 미디어 파일을 돌려준다는 뜻이다.
저장한 사진에 접근하려면
127.0.0.1:8000/uploads/review_pics/다운로드.jpg
이렇게 하면 된다.
웹 페이지에서 사진을 업로드 하려면 모델에 이렇게 작성한다.
class Review(models.Model):
image1 = models.ImageField(upload_to="review_pics")
image2 = models.ImageField(upload_to="review_pics", blank=True)
지정한 폴더에 사진이 저장된다.
사진 업로드가 필수가 아니게 하려면 blank옵션을 준다.
ImageField를 사용하려면 pip install Pillow 를 설치해야 한다.
업로드한 사진의 url을 확인하려면 장고 쉘에서 모델을 임포트 하고
변수 = [모델이름].objects.all().first()
변수.[필드이름].url
이런식으로 확인할 수 있다.
null, blank
null과 blank의 기본값은 False이다.
null은 필드의 데이터베이스 컬럼에 NULL값을 허용한다.
blank는 폼에서 필드에 대한 값을 입력하지 않아도 된다.
문자열 기반 필드에서는 필드에 값이 없으면 NULL대신 빈 문자열을 기본적으로 저장한다.
name = models.CharField(max_length=10, blank=True)
그래서 빈값을 허용할 때 null=True를 작성하지 않는다.
하지만 unique=True옵션을 줄 때 빈 문자열로 저장하게 되면 여러개의 빈 문자열이 저장 되었을 때 중복이 되어 에러가 발생하기 때문에 이 때는 NULL을 사용해야 한다.
NULL은 어떤 값이 아니기 때문에 중복이 되어도 상관없다.
name = models.CharField(max_length=10, blank=True, null=True, unique=True)
문자열 기반이 아닌 필드에서는 빈 문자열이 없기 때문에 NULL을 저장하는 방법밖에 없다.
age = models.IntegerField(blank=True, null=True)
age = models.IntegerField(blank=True, null=True, unique=True)
그래서 blank=True와 null=True를 같이 사용한다.
모델과 모델
유저가 리뷰를 작성하려면 유저모델과 리뷰모델을 연결해야 한다.
모델과 모델사이의 관계를 설계하는 것을 데이터 모델링이라 한다.
일대다(1:N)관계에서는 다(N)쪽에 Foreign Key를 주고 그안에 관계를 맺을 모델(User)을 넣는다.
class Review(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
on_delete는 참조하는 오브젝트가 삭제되었을 때 이 오브젝트롤 어떻게 할지 정하는 설정이다.
CASCADE는 참조하는 오브젝트가 삭제될 때 Foreign Key를 갖는 오브젝트도 함께 삭제된다.
on_delete
이 상태에서 migration을 할 때 기존의 데이터가 있다면 기존 데이터의 author 필드를 어떻게 할지 물어본다.
1번 옵션을 주고 ID값을 주면 기존에 있던 데이터의 author필드를 해당 ID의 User로 등록한다.
장고 쉘에서 확인 하려면
import coplate.models import Review, User
r = Review.objects.all().first()
먼저 이런식으로 가져온다.
r.author
유저의 인스턴스를 보여준다.
r.author.nickname
유저의 nickname필드를 보여준다.
Review.objects.filter(author__id=1)
Review.objects.filter(author__nickname=’유저1’)
이렇게 필터를 걸어 확인할 수 도 있다.
ljust
{% for i in ""|ljust:review.rating %}
★
{% endfor %}
장고 템플릿 랭귀지에서는 range같은 함수가 없기 때문에 ljust를 사용한다.
ljust
review.rating이 3이라면 길이가 3인 공백이 만들어진다.
그럼 for문을 3번 돌게 됨으로 별이 3번 출력된다.
humanize
숫자에 1000단위마다 쉼표를 찍을 때 사용한다.
INSTALLED_APPS에 django.contrib.humanize를 작성하고
템플릿에서 {% load humanize %} 상단에 작성 후
{{숫자데이터|intcomma}} 로 사용
choices 라디오 버튼
class ReviewForm(forms.ModelForm):
class Meta:
model = Review
fields = [
'rating',
]
widgets = {
"rating": forms.RadioSelect,
}
RATING_CHOICES = [
(1, "★"),
(2, "★★"),
(3, "★★★"),
(4, "★★★★"),
(5, "★★★★★"),
]
rating = models.IntegerField(choices=RATING_CHOICES, default=None)
choices는 기본적으로 select위젯이 사용된다.
이것을 변경하려면 widgets속성을 오버라이드 하면 된다.
default=None으로 하면 —가 사라지고 체크된 채로 시작하지 않는다.
이렇게 했을 때 기본적으론 리스트 형태로 출력되니 한줄로 정렬을 하려면 템플릿에서
{% for radio in form.rating %}
{{radio}}
{% endfor %}
{% for error in form.rating.errors %}
<div class="error-message">{{error}}</div>
{% endfor %}
이런식으로 하나씩 출력을 하게 만든다.
필드가 오류 메시지를 낼 수 없는 타입이라도 에러를 처리해주는게 좋다.
enctype
폼에 파일 업로드 기능이 있으면 이 옵션을 반드시 준다
enctype=”multipart/form-data”
enctype은 폼 데이터를 어떻게 인코딩 할지 정한다.
없으면 제대로 전송돼지 않는다.
form_valid
Create뷰에서 게시글의 작성자 필드를 자동으로 설정하려면 form_valid를 오버라이딩 하면 된다.
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
form_valid는 입력 받은 데이터가 유효할 때 데이터로 채워진 모델 오브젝트를 만들고 저장한다.
form.instance에 author속성을 추가하고 self.request.user를 넣는다.
그 후에 super().form_valid(form)으로 기존의 form_valid를 호출하도록 오버라이드한다. 호출을 하지 않으면 저장되지 않는다.
super()는 상속대상을 뜻한다. 위의 경우에서는 CreateView를 말한다. 기존 메소드의 동작을 완전히 바꾸는게 아니라 중간에 어떤 로직을 추가할 때는 super()를 사용해 기존 메소드를 호출하면 된다.
Leave a comment