- 목표 :
✔︎ Django를 이용한 AI Image 갤러리형 블로그 개발
✔︎ 유저들이 Stable Diffusion API를 통해 AI Image 생성후 업로드 및 공유하며 AI Image와 관련 정보 공유
- 배경:
✔︎ Stable Diffusion, Dalle 등 AI Image의 기술의 발달
✔︎ AI 이미지에 대한 관심과 AI이미지용 블로그 주제가 많이 없다고 생각되어 해당 주제로 블로그 개발
- CRUD, 로그인/회원가입, 댓글, 이미지 업로드, 조회수 기능 구현
- 블로그 포스팅
- 댓글 기능
- 태그 및 카테고리 분류
- UI 스타일링
- 클래스형 뷰 및 함수형 뷰 중 택 개발
- 데이터 베이스 구조 설계
- 모놀로그식 장고
- 0단계: Django Admin을 이용한 게시글 읽기 및 메인페이지 구현하기
- 1단계: 블로그 CRUD 기능 구현하기
- 2단계: 로그인/회원가입 기능을 이용하여 블로그 구현하기
- 3단계: 블로그 기능 외 추가 기능 작성 및 배포
-
4개의 앱(main, accounts, blog(메인 갤러리형 게시판), boardapp(보조형 자유게시판))으로 구성
-
클래스뷰 및 함수형뷰
- 클래스 뷰는 제너릭뷰, 믹스인뷰을 사용할 수 있는 '확장성'과 '재사용성'이라는 장점으로 주요 앱(main, accounts,blog) 는 클래스형으로 작성
- 함수형 뷰는 '간결'하고 '직관'적인 특징으로 간편하게 쓰일 수있는 보조형 자유게시판에서 작성
-
포스트 기능으로 좋아요, 태그, 대댓글, 카테고리 등을 사용 함
- 댓글은 메인 갤러리형 블로그는 대댓글형
- 보조 자유 게시판은 일반 댓글형 구현
[FE]:
[BE]:
[API]:
[ENV]:
- 부트스트랩은 Startbootstrap에서 테마를 따옴
- 특이사항으로는 tawk.to라는 실시간 채팅솔루션과 StableDiffusion API로 이미지 생성 가능하게 함(배포 버젼에서는 현재는 토큰수 소진으로 생성이 안되는 상황)
- Github에 업로드한 레파지토리를 AWS lightsail에 clone 하여 배포
3.2 배포 URL: http://54.180.146.126:8000/
- 프로젝트 구조는 아래와 같이 accounts, blog, boardapp, main 4개로 구성됨
📦mysite
┣ 📂accounts
┃ ┣ 📜models.py
┃ ┣ 📜urls.py
┃ ┣ 📜views.py
┣ 📂blog
┃ ┣ 📜models.py
┃ ┣ 📜urls.py
┃ ┣ 📜views.py
┣ 📂boardapp
┃ ┣ 📜models.py
┃ ┣ 📜urls.py
┃ ┣ 📜views.py
┣ 📂main
┃ ┣ 📜urls.py
┃ ┣ 📜views.py
┣ 📂templates
┃ ┣ 📂accounts
┃ ┣ 📂blog
┃ ┣ 📂boardapp
┃ ┣ 📂main
┣ 📂static
┃ ┣ 📂css
┃ ┣ 📂js
┃ ┃ ┗ 📜scripts.js
┣ 📂media
┃ ┣ 📂blog
┃ ┃ ┣ 📂images
┣ 📂tutorialdjango
┃ ┣ 📜settings.py
┃ ┣ 📜urls.py
┗ 📜manage.py
- main
| App | URL | Views Function | HTML File Name | Note |
|---|---|---|---|---|
| main | '/' | home | main/home.html | 홈화면 |
| main | '/about/' | about | main/about.html | 소개화면 |
| main | '/generator/' | generator | main/generator.html | AI이미지 생성게시판 |
- accounts
| App | URL | Views Function | HTML File Name | Note |
|---|---|---|---|---|
| accounts | 'register/' | register | accounts/register.html | 회원가입 |
| accounts | 'login/' | login | accounts/login.html | 로그인 |
| accounts | 'logout/' | logout | accounts/logout.html | 로그아웃 |
| accounts | 'profile/' | profile | accounts/profile.html | 비밀번호변경기능 / 프로필 수정/ 닉네임추가 |
- boardapp
| App | URL | Views Function | HTML File Name | Note |
|---|---|---|---|---|
| boardapp | 'board/' | board | boardapp/post_list.html | 게시판 목록 |
| boardapp | 'board/int:pk/' | post_detail | boardapp/post_detail.html | 게시글 상세보기 |
| boardapp | 'board/write/' | post_write | boardapp/post_write.html | 게시글 작성 |
| boardapp | 'board/edit/int:pk/' | post_edit | boardapp/post_edit.html | 게시글 수정 |
| boardapp | 'board/delete/int:pk/' | post_delete | boardapp/post_delete.html | 게시글 삭제 |
| boardapp | 'board/int:pk/comment/' | comment_create | boardapp/comment_form.html | 댓글 작성 |
| boardapp | 'board/int:pk/comment/ int:comment_pk/edit/' |
comment_edit | boardapp/comment_form.html | 댓글 수정 |
| boardapp | 'board/int:pk/comment/ int:comment_pk/delete/' |
comment_delete | boardapp/comment_ confirm_delete.html |
댓글 삭제 |
- blog
| App | URL | Views Function | HTML File Name | Note |
|---|---|---|---|---|
| blog | 'blog/' | blog | blog/blog.html | 갤러리형 게시판 메인 화면 |
| blog | 'blog/int:pk/' | post | blog/post.html | 상세 포스트 화면 |
| blog | 'blog/write/' | write | blog/write.html | 카테고리 지정, 사진업로드, 게시글 조회수 반영 |
| blog | 'blog/edit/int:pk/' | edit | blog/edit.html | 게시물목록보기 |
| blog | 'blog/delete/int:pk/' | delete | blog/delete.html | 삭제 화면 |
| blog | 'blog/search/' | search | blog/search.html | 주제와 카테고리에 따라 검색, 시간순에 따라 정렬 |
| blog | 'post/int:post_pk/comment/' | comment_new | blog/comment_form.html | 댓글 입력 폼 |
| blog | 'post/int:post_pk/comment/ int:parent_pk/' |
reply_new | blog/comment_form.html | 대댓글 폼 |
| blog | 'post/int:pk/like/' | like_post | blog/post.html | 좋아요를 누르면 blog/post로 Redirect됨 |
| blog | 'comment/int:pk/update/' | comment_update | blog/comment_form.html | 댓글 업데이터 경로 |
| blog | 'comment/int:pk/delete/' | comment_delete | blog/comment_ confirm_delete.html |
댓글 삭제 폼 |
- 메인 페이지
- 설명 페이지
- 이미지생성 페이지
- 게시판형 블로그 페이지
- 갤러리형 블로그 페이지
- 로그인/회원가입 페이지 등
- users, Post, Comment, Tag, PostLikes, PostTags, UserProfile, Board, BoardComment, Boardlikes(총 10개의 테이블)
- Post와 Board의 id 필드는 users 테이블의 id 필드와 연결
- 다대다 관계 : PostLikes ↔ (Post 와 User) / PostTags ↔ (Post 와 Tag)
- 다대일 관계 : BoardComment - Board / Boardlikes - User
📌 메인페이지 구현
- 페이지 제목과 블로그 입장하기 버튼
- 회원가입/로그인 버튼
- 회원가입 버튼을 클릭하면 회원가입 페이지로 이동
- 로그인 버튼을 클릭하면 로그인 페이지로 이동
📌 회원가입 / 로그인 기능 구현
- 회원가입을 할 수 있는 페이지
- 입력받는 값은 id, password
- 로그인을 할 수 있는 페이지
- 입력받는 값은 id, password
📌 게시글 작성 기능 구현
- 로그인을 한 유저만 해당 기능을 사용 할 수 있음
- 게시글 제목과 내용을 작성 할 수 있는 페이지가 있음
- 작성한 게시글이 저장되어 게시글 목록에 보여야 함
- 사진 업로드가 가능하도록 함
- 게시글 조회수가 올라갈 수 있도록 함
📌 게시글 목록 기능 구현
- 모든 사용자들이 게시한 블로그 게시글들의 제목을 확인 함
- 게시글의 제목/내용을 보는 기능
- 주제와 태그에 따라 검색이 가능
- 검색한 게시물은 최신순에 따라 정렬
📌 게시글 수정 기능 구현
- 로그인을 한 유저만 해당 기능 사용 가능
- 본인의 게시글이 아니라면 수정이 불가능
- 게시글의 제목 또는 내용을 수정 하는 기능
- 수정된 내용은 게시글 목록보기/상세보기에 반영
📌 게시글 삭제 기능 구현
- 로그인을 한 유저만 해당 기능을 사용 할 수 있음
- 본인의 게시글이 아니라면 수정이 불가
- 게시글을 삭제하는 기능
- 삭제를 완료한 이후에 게시글 목록 화면으로 돌아감
- 삭제된 게시글은 게시글 목록보기/상세보기에서 접근이 불가
📍 회원 관련 추가 기능(UI 직접 구현 필요)
- 비밀번호 변경기능
- 프로필 수정
- 닉네임(Username) 추가
📍 댓글 기능(UI 직접 구현 필요)
- 댓글 추가
- 댓글 편집/삭제
- 대댓글
📍 부가 기능
- 정적 파일 모으기 (collectstatic)
# settings.py
# 정적 파일 기본 URL
STATIC_URL = '/static/'
# 추가적인 정적 파일 디렉토리 (개발 환경에서 사용)
STATICFILES_DIRS = [
BASE_DIR / 'static',
]
#(운영환경에서 사용)
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
서버에서 python manage.py collectstatic 명령 입력
- 공지사항 기능
- 관리자만 관리자페이지에서 설정 가능
- 모델에서 is_notice 설정
- views.py에서 get_context_data 메서드를 사용하여 공지사항과 일반 게시글을 분리
# models.py
class Post(models.Model):
# <생략>
is_notice = models.BooleanField(default=False, verbose_name="공지사항 여부")
# views.py
class BlogListView(ListView):
# <생략>
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
notice_list = Post.objects.filter(is_notice=True).order_by('-created_at')
regular_post_list = Post.objects.filter(is_notice=False).order_by('-created_at')
# <생략>
- Tawk API를 활용한 실시간 채팅기능(About 페이지)
🎈 Link : https://www.tawk.to/
- Stable Diffusion을 활용한 AI 이미지 생성 화면(Generator 페이지)
🎈 Link : https://stablediffusionapi.com/docs/stable-diffusion-api/text2img
📍 (선택) AWS Lightsail로 배포
🎈 Link : https://aws.amazon.com/ko/lightsail/
Video.2.mp4
- RDBMS Postgre를 사용하여 Django와 연결후 post 쿼리 조회
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'tutorialdjango',
'USER': 'postgres',
'PASSWORD': '1234',
'HOST': 'localhost',
'PORT': '5432',
}
}
🛠IntegrityError
- 에러명: 'IntegrityError'
- 문제상황: 모델 필드가 null 값을 허용 안함
- 해결방안: 해당 필드에 'null=True' 옵션 추가
# models.py
summary = models.TextField(null=True)💡 클래스형 뷰 목록
-
제너릭뷰
- ListView: 게시목록을 보여 줌
- DetailView: 게시물 상세 정보 보여 줌
- CreateView: 새로운 객체를 생성
- UpdateView: 기존 객체를 수정
- DeleteView: 객체를 삭제할 때 사용
- TemplateView: 정적 페이지를 렌더링
-
믹스인(Mixins)
- LoginRequiredMixin: 사용자가 로그인 해야만 접근 할 수 있는 뷰
- UserPssesTextMixin: 사용자가 특정 텍스트를 통과해야만 뷰에 접근
💡 django-widget-tweaks
- Django의 폼 필드의 HTML을 보다 쉽게 제어할 수 있게 해주는 라이브러리 CSS 클래스 추가, 속성 변경 가능
{% load widget_tweaks %}
<form method="post">
{% csrf_token %}
</form>{% render_field form.field_name class="form-control" %} # 필드 특정 조건에 따라 렌더링하고 싶을 때 사용
{{ field|add_class:"form-control" }} # | 기호는 필터를 의미 이 필터는 지정된 필드에 클래스를 추가본 프로젝트에서는 두 번째 방식으로 클래스에 부트스트랩 클래스를 추가하여 디자인 하였음
💡 대댓글 구현 방식
- Comment 모델의 parent 필드를 통해 구현
- 사용자가 B라는 댓글을 달 때 A의 대댓글로 지정하려는 경우, A라는 대댓글 ID는 parent_pk 파라미터로 전달
- CommentCreateView 에서 이를 확인하여 B 댓글의 부모댓글 'parent' 댓글로 A를 설정
- 이렇듯 parent 필드를 통해 부모-자식간의 관계가 형성됨
- 템플릿에서는 주댓글에 대한 루프를 돌면서 replies 관계 형성
{% for reply in comment.replies.all %}
{% endfor %}- Django의 편리함과 Python의 강력함을 느낄 수 있었던 유익한 프로젝트였음
- 스프링부트 자바 강의를 조금씩 듣고 있는데 많은 경험이 있는건 아니지만 따른 프레임 워크에 비해 효율적이고 빠르게 게시판을 만들 수 있음을 느낌
- 함수형과 클래스형 뷰 코드를 모두 사용해보기 위해 앱 개수가 늘어나다 보니 URL이 복잡해졌지만, 둘의 차이점에 대해 알 수 있었음
- 장고의 다양한 기능과 코드 방식에 대해 깊이 연구 할 수 있는 기회가 됨
- AWS 배포를 통해 아마존 웹 서비스를 처음 활용 해볼 수 있는 좋은 기회가 됨
📖 Velog : https://han.gl/btewiM
❤️ EST soft : 대상 수상 프로젝트(https://url.kr/br6yg7)














