목차
1. ERD 설계 참조하여 review 앱에 models.py 작성
3) DateField와 DateTimeField 속성
2. review 모델 admin 페이지 커스텀
1) 어드민 페이지 설정
2) url로 저장된 이미지 필드를 이미지로 보여주기
3) search_fields 에서 관계된 모델 필드로 검색하기
4) def get_readonly_fields(self, request, obj): 사용했을때
5) Review 어드민 상세 페이지에서 ReviewImage 필드 넣기
1. ERD 설계 참조하여 review 앱에 models.py 작성
review/models.py
# 리뷰 모델
class Review(models.Model):
user = models.ForeignKey(User, verbose_name='작성자', on_delete=models.CASCADE)
trip = models.ForeignKey(Trip, verbose_name='여행 일정', on_delete=models.CASCADE)
title = models.CharField('제목', max_length=50)
content = models.TextField('내용')
created_at = models.DateTimeField('작성일', auto_now_add=True)
def __str__(self):
return f"{self.title} - {self.user.username}"
# 리뷰 이미지 모델
class ReviewImage(models.Model):
review = models.ForeignKey(Review, verbose_name='리뷰', on_delete=models.CASCADE)
image = models.ImageField('이미지', upload_to='static/images/review/%Y%m%d')
order = models.IntegerField("이미지 순서")
def __str__(self):
return f"{self.review.title}'s image - {self.order}"
1) 모델 관계
* User - Review : One To Many
* Trip - Review : One To Many
* Review - ReviewImage : One To Many
2) on_delete 속성
- CASCADE : FK로 참조하는 레코드가 삭제 될 경우 해당 레코드를 삭제한다.
- SET_NULL : FK 필드의 값을 Null로 변경해준다. null=True가 정의되어 있어야 사용 가능하다.
- PROTECT : 해당 레코드가 삭제되지 않도록 보호해준다.
- SET_DEFAULT : FK 필드의 값을 default로 변경해준다. default=””가 정의되어 있어야 사용 가능하다.
- SET() : FK 필드의 값을 SET에 설정된 함수를 통해 원하는 값으로 변경할 수 있다.
- DO_NOTHING : 아무런 동작을 하지 않는다. 참조 관계의 무결성이 손상될 수 있기 때문에 권장하지 않는다.
3) DateField와 DateTimeField 속성
- default = $date : 지정한 값을 기본 값으로 설정한다.
- auto_now_add = True : 레코드가 생성될 때의 date를 기준으로 값을 지정한다.
- auto_now = True : 레코드가 save()될 때마다 갱신된다.
4) ImageField
ImageField ( upload_to = None , height_field = None , width_field = None , max_length = 100 , ** options )
- upload_to : {MEDIA_ROOT}/{upload_to}/{업로드 하는 파일명}. datetime 모듈을 import하지 않고 %Y%m%d의 형태로 날짜 또는 시간을 입력할 수 있다.
- ImageField.height_field : 모델 인스턴스가 저장될 때마다 이미지 높이가 자동으로 채워지는 모델 필드의 이름이다.
- ImageField.width_field : 모델 인스턴스가 저장될 때마다 이미지 너비가 자동으로 채워지는 모델 필드의 이름이다.
- ImageField인스턴스는 varchar 기본 최대 길이가 100자인 열로 데이터베이스에 생성됩니다. max_length다른 필드와 마찬가지로 인수 를 사용하여 최대 길이를 변경할 수 있습니다
upload_to 참조 : http://johnnykims.blogspot.com/2016/05/django-imagefield-uploadto.html
django ImageField upload_to 설정하기
django에서 파일 또는 이미지 업로드 기능을 사용하려면 장고 모델의 ImageField, FileField에서 사용하는 upload_to argument를 설정해야 합니다. upload_to 에 설정한 값은 DEFAULT_FILE_STORAGE...
johnnykims.blogspot.com
2. review 모델 admin 페이지 커스텀
reviews/admin.py
from django.contrib import admin
from .models import ReviewImage, Review
from django.utils.html import mark_safe
class ReviewImageInline(admin.StackedInline):
model = ReviewImage
extra = 0
fieldsets = (
('image', {'fields': ('order','image','image_tag',)}),
)
def get_readonly_fields(self, request, obj):
if obj:
return ('image_tag',)
else:
return ('image_tag',)
def image_tag(self, obj):
if obj.image:
return mark_safe('<img src="{}" width="100" height="100"/>'.format(obj.image.url))
class ReviewAdmin(admin.ModelAdmin):
list_display = ('id', 'user', 'title', 'image_preview',)
list_display_links = ('id', 'user', 'title', 'image_preview',)
list_filter = ('user',)
search_fields = ('user__username', 'title')
readonly_fields = ('created_at',)
fieldsets = (
('info', {'fields': ('created_at', 'user', 'trip')}),
('content', {'fields': ('title', 'content')}),
)
def image_preview(self, obj):
images = obj.reviewimage_set.all().first()
if obj.reviewimage_set:
return mark_safe(f'<img src="{images.image.url}" width="100" height="100"/>')
inlines = (
ReviewImageInline,
)
class ReviewImageAdmin(admin.ModelAdmin):
list_display = ('id', 'review', 'image_tag',)
list_display_links = ('id', 'review', 'image_tag',)
list_filter = ('review',)
search_fields = ('review__title',)
fieldsets = (
('info', {'fields': ('review', 'order',)}),
('image', {'fields': ('image', 'image_tag')}),
)
def get_readonly_fields(self, request, obj=None):
if obj:
return ('image_tag',)
else:
return ('image_tag',)
def image_tag(self, obj):
if obj.image:
return mark_safe(f'<img src="{obj.image.url}" width="100" height="100"/>')
return None
admin.site.register(Review, ReviewAdmin)
admin.site.register(ReviewImage, ReviewImageAdmin)
1) 어드민 페이지 설정
- list_display : 모델 오브젝트들을 간략히 보여줄때 보여줄 필드
- list_display_links : 오브젝트를 수정하거나 상세히 보기위한 페이지로 넘어가기 위해 링크를 달아줄 필드
- list_filter : 설정한 필드별로 볼 수 있다.
- search_fields : 검색할 수 있는 필드
- readonly_fields : 읽기 전용 필드
- fieldsets : 오브젝트 상세 페이지에서 그룹을 만들 수 있다.
- get_readonly_fields :
- ModelAdmin.get_readonly_fields(request, obj=None)
- The get_readonly_fields method is given the HttpRequest and the obj being edited (or None on an add form) and is expected to return a list or tuple of field names that will be displayed as read-only, as described above in the ModelAdmin.readonly_fields section.
참조 : https://docs.djangoproject.com/en/4.0/ref/contrib/admin/
The Django admin site | Django documentation | Django
Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate
docs.djangoproject.com
2) url로 저장된 이미지 필드를 이미지로 보여주기
프로젝트폴더/settings.py
import os
...
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
프로젝트폴더/urls.py
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)
review/admin.py
from django.utils.html import mark_safe
...
def image_preview(self, obj):
images = obj.reviewimage_set.all().first()
if obj.reviewimage_set:
return mark_safe(f'<img src="{images.image.url}" width="100" height="100"/>')
mark_safe : 출력 목적으로 문자열을 안전한 것으로 명시적으로 표시합니다. 반환된 개체는 문자열 또는 유니코드 개체가 적절한 모든 곳에서 사용할 수 있습니다. 문자열을 파이썬으로부터 안전한 것으로 표시해야 합니다.
- 참조 : https://stackoverflow.com/questions/32799615/why-and-when-to-use-django-mark-safe-function
Why and When to use Django mark_safe() function
After reading the document, the function of mark_safe() is still unclear. I guess it is related to CSRF stuff. But why and when shall the mark_safe() be used? Here is the documentation mark_safe(s)
stackoverflow.com
static 파일 다루기 참조 : https://velog.io/@duo22088/Django-Media-file-%EB%8B%A4%EB%A3%A8%EA%B8%B0
(Django) Media file 다루기
장고에서 어떻게 static 파일을 서빙하는지 알아봅시다.
velog.io
3) search_fields 에서 관계된 모델 필드로 검색하기
Review 모델과 ReviewImage 모델이 One To Many 인 관계에서
ReviewImage 어드민 페이지의 search_fields 를 Review 모델의 title 필드로 정하기
search_fields = ('review__title',)
4) def get_readonly_fields(self, request, obj): 사용했을때
Review 모델에 created_at 필드를 쓰기에 사용하지 않고 읽기에만 사용하기 위해
def get_readonly_fields(self, request, obj):
if obj:
return ('created_at',)
else:
return ()
위 처럼 작성 하였으나, 어드민페이지에서 새로 오브젝트를 생성할 때
'created_at' cannot be specified for Review model form as it is a non-editable field.
라는 오류가 발생한다.
수정할 수 없는 필드인데 fieldsets 안에 들어가있기 때문인것 같다.
공식문서를 참조하여 readonly_fileds 를 사용하니 해결되었다.
readonly_fields = ('created_at',)
참조 : https://docs.djangoproject.com/en/4.0/ref/contrib/admin/
The Django admin site | Django documentation | Django
Django The web framework for perfectionists with deadlines. Overview Download Documentation News Community Code Issues About ♥ Donate
docs.djangoproject.com
5) Review 어드민 상세 페이지에서 ReviewImage 필드 넣기
review/admin.py
class ReviewAdmin(admin.ModelAdmin):
...
inlines = (
ReviewImageInline,
)
ReviewAdmin 위에 ReviewImageInline 추가
class ReviewImageInline(admin.StackedInline):
model = ReviewImage
extra = 0
fieldsets = (
('image', {'fields': ('order','image','image_tag',)}),
)
def get_readonly_fields(self, request, obj):
if obj:
return ('image_tag',)
else:
return ('image_tag',)
def image_tag(self, obj):
if obj.image:
return mark_safe('<img src="{}" width="100" height="100"/>'.format(obj.image.url))
inline : admin page에서 다른 model을 edit할 수 있는 ability를 부여한다.
StackedInline : 다른 모델에 대한 내용을 세로로 쌓아서 보여줌
TabularInline : 다른 모델에 대한 내용을 가로로 늘려서 보여줌
model에 가져올 모델 정하고 extra 는 숫자만큼 빈 오브젝트를 만든다.
이후에는 모델 어드민 작성할때와 동일하게 작성하면 된다.
참조 : https://clownhacker.tistory.com/145
Django TabularInline and StackedInline
TabularInline TabularInline은 django.contrib.admin이 제공하는 같은 admin page에서 다른 model을 edit할 수 있는 ability를 부여한다. 예를 들어, photos/models.py에 Photo model이 있다고 하자. 그리고 room..
clownhacker.tistory.com
'AI 웹 개발 과정 > 팀 프로젝트' 카테고리의 다른 글
testcode 작성 (1) | 2022.07.28 |
---|---|
최종 프로젝트 - API 구현 (리뷰 리스트 조회, 리뷰 상세 조회) (0) | 2022.07.14 |
최종 프로젝트 - 기획 (0) | 2022.07.11 |
유화제작프로젝트 - KPT 회고 (0) | 2022.07.06 |
유화제작프로젝트 - 기능구현 (0) | 2022.07.06 |