장고 첫번째 팀프로젝트 :: 게시판 CRUD관련 코드 리뷰 - 모델링편

권수민·2023년 9월 19일
1

먼저 나의 담당 중 하나는 모델링이었다.

post관련 모델링은

from django.db import models

먼저 디비에 모델을 연결해주는 모듈 임포트

포스트 모델

class Post(models.Model):
    class Meta:
        db_table = "post_list"

    author = models.ForeignKey(
        "users.User",
        verbose_name="글쓴이",
        null=True,  # on_delete해주기위해
        related_name="author",
        on_delete=models.SET_NULL,
    )
    title = models.CharField("제목", max_length=50)
    content = models.TextField("내용", max_length=8000)
    comment = models.ManyToManyField(
        "users.User", related_name="comment", through="Comments"
    )
    liked_post = models.ManyToManyField(
        "users.User", through="PostLike", related_name="liked_posts"
    )
    # image = models.ImageField(upload_to = 'posts/images/',null=True,blank=True)
    # file = models.FileField(upload_to = 'posts/files/',null=True,blank=True)
    # 여러 파일을 넣으려면 파일 이미지 모델 따로 분리해서 폼 생성.
    created_at = models.DateTimeField("생성일", auto_now_add=True)
    updated_at = models.DateTimeField("수정일", auto_now=True)
    
    # 여기서 User모델이 참조되는 인스턴스들이 많아서 => post_set으로 다 지정되다보니 혼동이 온다
    # 그래서 related_name꼭 넣어주기
    def __str__(
        self,
    ):  # admin 페이지에 content를 대표로 보여주는것 , 그리고 실제 페이지애서 반영은 좀더 크기가 키워져 나온다.
        return self.content

이미지 / 파일 모델을 따로 모델링 해준이유는 따로따로 여러개를 저장해주고 싶어서이다.

class Image(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="images")
    image = models.ImageField(upload_to="posts/images/", null=True, blank=True)


class File(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="files")
    file = models.FileField(upload_to="posts/files/", null=True, blank=True)

피드의 좋아요 모델 : 좋아요 count를 설정해주지 않은것은 장고 내 자체기능으로 알아서 .COUNT해주면 id 가 count 되기 때문에 해주지 않았습니다. 즉, Postlike.count하면 Postlike의 모든id를 다 세어준다.

class PostLike(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, verbose_name="좋아요한 포스트")
    user = models.ForeignKey(
        "users.User", on_delete=models.CASCADE, verbose_name="포스트 좋아요한 유저"
    )
    # likes_count = models.IntegerField("좋아요 수",default=0)


> #  좋아요 수는 해당 포스트 또는 댓글과 연결된 PostLike 또는 CommentLike 객체의 수로 계산가능

comment를 위한 모델 생성 :: 다 원래 있는 모델 참조해준것이고 댓글 내용을 담아주기 위해서 through옵션으로 따로 이름 생성하여 추가해준것.

class Comments(models.Model):
    author = models.ForeignKey(
        "users.User",
        related_name="comment_author",
        verbose_name="댓글 쓴 유저",
        on_delete=models.CASCADE,
    )
    post = models.ForeignKey(
        "Post",
        related_name="comment_post",
        verbose_name="댓글달린 포스트",
        on_delete=models.CASCADE,
    )
    comment = models.TextField("댓글", max_length=1500, null=True, blank=True)

    # textfield는 말그대로 문자열만 나타내주기때문에 다른 모델과의 관계를 정의하지 않는다, 고로 on_delete옵션이 없음
    # 그리고 이미 author나 post가 지워지면 코멘트도 사라지게되어있다. on_delete지워주기
    # 모든 참조한 데이터들 on_delete로 사라지는 기능
    
    
    liked_comments = models.ManyToManyField(
        "users.User",
        verbose_name="댓글좋아요",
        related_name="liked_comments",
        through="CommentLike",
    )


class CommentLike(models.Model):
    comment = models.ForeignKey(
        Comments, on_delete=models.CASCADE, verbose_name="좋아요한 댓글"
    )
    user = models.ForeignKey(
        "users.User", on_delete=models.CASCADE, verbose_name="댓글 좋아요한 유저"
    )
    # likes_count = models.IntegerField("좋아요 수",default=0)
    
   

이렇게 모델링을 다로 해주고 나면 어드민 페이지에 보여주고 설정하려면
admin.py에 들어가서

from django.contrib import admin
from post.models import Post, Image, File, Comments

# Register your models here.


class ImageInline(admin.TabularInline):
    model = Image


class FileInline(admin.TabularInline):
    model = File

class CommentsInline(admin.TabularInline):
    model = Comments
    
class PostLikeInline(admin.TabularInline):
    model = PostLike

class PostAdmin(admin.ModelAdmin):
    inlines = [
        ImageInline,
        FileInline,
        CommentsInline,
        PostLikeInline
    ]

이렇게 해주어야 어드민에 생성되지만 어드민을 따로 사용하지 않을 것이라면 굳이 해줄 필요없다.

나는 폼을 사용하였는데 이미지와 파일을 위해서 사실 폼관련 기능을 별로 사용하지않아서 안써줘도 될법도 했지만 유효성 체크라도 하기 위해서 폼을 사용해 주었다.

Django에서 폼(forms)를 사용하는 것은 여러 가지 이유로 유용합니다. 아래는 폼을 사용하는 주요 이유들입니다:

데이터 검증 및 정제: 폼은 사용자로부터 입력받은 데이터의 유효성 검사와 정제를 자동화해 줍니다. 각 필드에 대한 규칙과 제약 조건을 설정하면, 데이터가 이러한 규칙에 맞게 제출되었는지 자동으로 확인합니다.

보안: 폼은 여러 보안 위협, 특히 SQL 인젝션 및 크로스 사이트 스크립팅(XSS)과 같은 공격을 방지하는 데 도움이 됩니다. 폼은 자동으로 입력을 이스케이프하여 이러한 공격을 방지합니다.

HTML 렌더링: Django 폼은 자동으로 HTML 필드를 렌더링할 수 있습니다. 이를 통해 입력 필드, 레이블, 유효성 검사 오류 메시지 등을 쉽게 출력할 수 있습니다.

DRY (Don't Repeat Yourself) 원칙: 폼은 데이터 처리 로직을 중앙화하여 코드의 중복을 최소화합니다. 예를 들어, 여러 뷰나 템플릿에서 동일한 입력 처리 및 유효성 검사 로직을 사용해야 하는 경우, 하나의 폼을 재사용하여 중복을 피할 수 있습니다.

모델 통합: ModelForm을 사용하면 Django 모델과 폼을 직접 연결할 수 있습니다. 이를 통해 데이터베이스 모델의 인스턴스를 쉽게 저장하고 업데이트 할 수 있습니다.

에러 메시지 관리: 폼은 각 필드에 대한 오류 메시지를 자동으로 처리합니다. 사용자가 잘못된 데이터를 입력하면, 해당 필드에 대한 에러 메시지를 쉽게 표시할 수 있습니다.

다국어 및 지역화: 폼은 다국어 및 지역화 지원과 통합되어 있어, 다양한 언어 및 지역 설정에 맞게 메시지와 데이터 포맷을 쉽게 처리할 수 있습니다.

요약하면, Django 폼은 웹 애플리케이션에서 데이터 처리, 유효성 검사, 보안 및 사용자 인터페이스와 관련된 많은 공통 작업을 간소화하고 표준화하는 데 도움을 줍니다.

라고 한다.

위에는 나중에 추후 배울 drf에서 사용하는 serializer와 같이 유효성검사 및 여러 다양한 기능을 가지고있는 모듈이라할수있다.

from django import forms
from .models import Post, Image, File, Comments, PostLike


class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        exclude = ("author",)
        fields = ("author", "title", "content")


class ImageForm(forms.ModelForm):
    image = forms.ImageField(widget=forms.ClearableFileInput())
	#이미지 삭제 버튼칸을 제공하기 위해서 추가해준 것
    
    class Meta:
        model = Image
        fields = ("image",)


class FileForm(forms.ModelForm):
    file = forms.FileField(widget=forms.ClearableFileInput())
	#파일 삭제 버튼칸을 제공하기 위해서 추가해준 것
    class Meta:
        model = File
        fields = ("file",)


class CommentForm(forms.ModelForm):
    class Meta:
        model = Comments
        fields = ["comment"]

이부분은 image = forms.ImageField(widget=forms.ClearableFileInput())

이미지 삭제 버튼칸을 제공하기 위해서 추가해준 것이기도 하지만 모델필드 커스트 마이징 한것 :: 특별한 위젯 설정을 적용하기위해

#widget:
#폼 필드를 HTML로 렌더링할 때 어떤 형태로 렌더링될 것인지를 결정하는 컴포넌트

#간단히 말해, 위젯은 데이터 입력을 위한 HTML 요소(예: <input>, <textarea>, <select> 등)를 생성
# widget=forms.ClearableFileInput: ImageField의 기본 위젯을 
#ClearableFileInput으로 변경 => 업로드된 파일 삭제하는 지우기옵션 제공
# attrs={'multiple': True} : 위젯의 속성을 설정하여, 사용자가 한 번에 여러 이미지 파일을 선택할 수 있게 해줌 
#=> html <input type="file" name="image" multiple> mutilple 속성과 같음
#하지만 애초에 그 속성이 가능한 위젯이 있기에 알아서 설정. 
#ClearableFileInput 여기서는 멀티플 속성이 가능하지않다.
#그렇기 때문에 templates에서 따로 번거럽게 옵션 설정을 해줘야한다.
profile
초보개발자

0개의 댓글