Skip to content

Kimchanyang524/ChatGPT-DRF-Project

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ChatGPT-DRF-Project

FE: https://github.com/Kimchanyang524/ChatGPT-DRF-FE

목차

1. 목표와 기능

  • 하루 5개 영단어 퀴즈를 꾸준히 하는것
  • 랜덤한 단어 추출을 위해 ai기술을 이용할 예정
  • 역대 단어 퀴즈를 풀었던 기록을 통해 복습할 수 잇게하기

2. 개발 기술 및 환경

2.1 개발 기술

FE

Static Badge

BE

2.2 개발 환경

3. 프로젝트 구조와 개발 일정

3.1 프로젝트 Directory 구조

FE

📦ChatGPT-DRF-FE
 ┣ 📂.git
 ┣ 📂CSS
 ┃ ┣ 📜footer.css
 ┃ ┗ 📜quiz.css
 ┣ 📂HTML
 ┃ ┣ 📂include
 ┃ ┃ ┣ 📜footer.html
 ┃ ┃ ┗ 📜header.html
 ┃ ┣ 📜404.html
 ┃ ┣ 📜login.html
 ┃ ┣ 📜main.html
 ┃ ┣ 📜quiz.html
 ┃ ┣ 📜quizlist.html
 ┃ ┗ 📜register.html
 ┣ 📂Image
 ┣ 📂JavaScript
 ┃ ┣ 📜base.js
 ┃ ┣ 📜header.js
 ┃ ┣ 📜include.js
 ┃ ┣ 📜login.js
 ┃ ┣ 📜logout.js
 ┃ ┣ 📜main.js
 ┃ ┣ 📜quiz.js
 ┃ ┣ 📜quizlist.js
 ┃ ┣ 📜register.js
 ┃ ┗ 📜token.js
 ┗ 📜README.md

BE

📦ChatGPT
 ┣ 📂accounts
 ┃ ┣ 📂__pycache__
 ┃ ┣ 📂migrations
 ┃ ┣ 📜__init__.py
 ┃ ┣ 📜admin.py
 ┃ ┣ 📜apps.py
 ┃ ┣ 📜models.py
 ┃ ┣ 📜permissions.py
 ┃ ┣ 📜serializers.py
 ┃ ┣ 📜tests.py
 ┃ ┣ 📜urls.py
 ┃ ┗ 📜views.py
 ┣ 📂main
 ┃ ┣ 📂__pycache__
 ┃ ┣ 📂migrations
 ┃ ┣ 📜__init__.py
 ┃ ┣ 📜admin.py
 ┃ ┣ 📜apps.py
 ┃ ┣ 📜models.py
 ┃ ┣ 📜tests.py
 ┃ ┗ 📜views.py
 ┣ 📂project
 ┃ ┣ 📂__pycache__
 ┃ ┣ 📜__init__.py
 ┃ ┣ 📜asgi.py
 ┃ ┣ 📜settings.py
 ┃ ┣ 📜urls.py
 ┃ ┗ 📜wsgi.py
 ┣ 📂quiz
 ┃ ┣ 📂__pycache__
 ┃ ┣ 📂migrations
 ┃ ┣ 📜__init__.py
 ┃ ┣ 📜admin.py
 ┃ ┣ 📜apps.py
 ┃ ┣ 📜models.py
 ┃ ┣ 📜permissions.py
 ┃ ┣ 📜serializers.py
 ┃ ┣ 📜tests.py
 ┃ ┣ 📜urls.py
 ┃ ┗ 📜views.py
 ┣ 📂static
 ┣ 📜.env
 ┣ 📜db.sqlite3
 ┗ 📜manage.py

3.2 프로젝트 URL 구조

FE

url 주소 html 파일이름
'' main.html
'404/' 404.html
'accounts/login/' login.html
'accounts/register/' register.html
'quiz/' quiz.html
'quiz/list/' quizlist.html

BE

app: accounts View Method
'auth/' AuthAPIView POST
'auth/' AuthAPIView DELETE
'register/' UserCreateAPIView CREATE
'refresh_token/' token_refresh POST
'verify/' token_verify POST
app: quiz View Method
'quiz/' ChatBotAPIView GET
'quiz/' ChatBotAPIView POST
'quiz/list' QuizAPIView GET

3.3 와이어프레임

3.4 개발 일정(WBS)

3.5 ERD

4. UI

5. 기능

  • 회원가입 및 로그인 기능
  • 하루 5회 랜덤한 영어퀴즈
  • 자신의 역대 기록
    sequenceDiagram
    actor A as client
    participant B as Web
    participant C as server
    A->>+B: 로그인을 하고싶어
    B->>+A: 로그인 정보 요구
    A->>+C: id pw 전달
    alt 로그인 정보 있을시
    C->>+B: access token 전달
    B->>+A: 로그인 성공
    else 정보 없을시
    C->>+B: False
    B->>+A: 로그인 실패
    end
Loading
    sequenceDiagram
    actor A as client
    participant B as Web
    participant C as server
    A->>+B: 퀴즈를 풀고 싶어
    B->>+C: access token 전달
    alt 퀴즈 횟수 5회 이상
    C->>+B: False
    B->>+A: 메인화면으로
    else 퀴즈 횟수 5회 미만
    C->>+B: 챗봇 답변 전달
    B->>+A: 퀴즈 문제 전달
    A->>+B: 퀴즈 답변 전달
    B->>+A: 정답여부 전달
    B->>+C: 문제와 답변, 정답 여부 전송
    end
Loading

6. 개발 이슈

  • DRF를 처음하면서 가장 필요해진부분이 block 템플릿이었다. 헤더나 푸터같은부분은 과도하게 중복되는부분이 많았다. 그래서 html을 include하거나 자주쓰는 자바스크립트를 한데 묶어서 사용하는 방법을 찾아보았다.
<header data-include-file="./include/header.html" class="header-wrap includeJs"></header>
<footer data-include-file="./include/footer.html" class="footer-wrap includeJs"></footer>
<script src="/JavaScript/base.js"></script>
// include.js
(function () {
    function includeHtml() {
        const includeTarget = document.querySelectorAll(".includeJs");
        includeTarget.forEach(function (el, idx) {
            const targetFile = el.dataset.includeFile;
            if (targetFile) {
                let xhttp = new XMLHttpRequest();

                xhttp.onreadystatechange = function () {
                    if (this.readyState === XMLHttpRequest.DONE) {
                        this.status === 200 ? (el.innerHTML = this.responseText) : null;
                        this.status === 404 ? (el.innerHTML = "include not found.") : null;
                    }
                };
                xhttp.open("GET", targetFile, true);
                xhttp.send();
                return;
            }
        });
    }

    includeHtml();
})();
// base.js
const script1 = document.createElement('script');
script1.src = '/JavaScript/include.js';
document.head.appendChild(script1);

const script2 = document.createElement('script');
script2.src = '/JavaScript/header.js';
document.head.appendChild(script2);

const script3 = document.createElement('script');
script3.src = '/JavaScript/logout.js';
document.head.appendChild(script3);

const script4 = document.createElement('script');
script4.src = '/JavaScript/token.js';
document.head.appendChild(script4);
  • include로 자바스크립트와 html을 받다보니, 로드되기 전에 html을 읽어오면 헤더의 login logout을 동적으로 조정하지 못하게 되었다. 그래서 settimeout을 이용해서, 실패할떄마다 일정시간 뒤 반복해서 실행하게 하였다.
(function updateHeader() {
    const sign = document.querySelector('#sign');
    const register = document.querySelector('#register');
    const access = sessionStorage.getItem('access');
    let temp = 0

    if (sign) {
        if (access) {
            sign.innerHTML = `<button class="nav-link" onclick="logout()"><i class="fa-solid fa-right-from-bracket"></i></button>`;
        } else {
            register.innerHTML = `<a class="nav-link" href="/accounts/register"><i class="fa-solid fa-user-plus"></i></a>`;
            sign.innerHTML = `<a class="nav-link" href="/accounts/login"><i class="fa-solid fa-right-to-bracket"></i></a>`;
        }
    } else {
        temp++
        console.log(temp + '회 실패')
        setTimeout(updateHeader, 100);
    }
})()
  • 이번에도 역시 비밀번호 해싱 오류가 있었고, 원래는 중간에 뺴와서 set_password를 하려고했었다. 그런데 직렬화 과정에서 해싱을 해주는 방법이 있음을 보고 그 방법으로 해결했다.
def create(self, validated_data):
    '''
    직렬화할떄 비밀번호를 해싱하는작업.
    '''
    user = super().create(validated_data)
    user.set_password(validated_data['password'])
    user.save()
    return user
  • User 커스텀 클래스에서 related_name을 요구하는 버그가 있었다.
ERRORS:
accounts.User.groups: (fields.E304) Reverse accessor 'Group.user_set' for 'accounts.User.groups' clashes with reverse accessor for 'auth.User.groups'.
        HINT: Add or change a related_name argument to the definition for 'accounts.User.groups' or 'auth.User.groups'.
accounts.User.user_permissions: (fields.E304) Reverse accessor 'Permission.user_set' for 'accounts.User.user_permissions' clashes with reverse accessor for 'auth.User.user_permissions'.
        HINT: Add or change a related_name argument to the definition for 'accounts.User.user_permissions' or 'auth.User.user_permissions'.
auth.User.groups: (fields.E304) Reverse accessor 'Group.user_set' for 'auth.User.groups' clashes with reverse accessor for 'accounts.User.groups'.
        HINT: Add or change a related_name argument to the definition for 'auth.User.groups' or 'accounts.User.groups'.
auth.User.user_permissions: (fields.E304) Reverse accessor 'Permission.user_set' for 'auth.User.user_permissions' clashes with reverse accessor for 'accounts.User.user_permissions'.
        HINT: Add or change a related_name argument to the definition for 'auth.User.user_permissions' or 'accounts.User.user_permissions'.

해결은 유저 클래스를 기본을 사용해서 해결했지만 settings.py를 수정하지 않았기 떄문인듯싶다.

AUTH_USER_MODEL = 'app.User'

7. 개발하면서 느낀점

  • 처음엔 DRF라고 큰 차이는 없을거라 생각했는데, jwt 지식 부족으로 인증부분에서 며칠을 투자하기도 했고, nginx를 연동하는데도 꼬박 하루가 걸렸던것같다. 하지만 다시 처음부터하라고 하면 두개 합쳐 하루면 충분할거라는 자신감이 붙었다. 시간이 조금 더 있었더라면 공식문서도 파헤쳐보고 연구해볼 수 있었을텐데 조금 아쉬웠다.

  • 처음 기획했던건 chatGPT를 교사처럼 사용해서 문제를 받고, 답안을 주면 정답여부를 받고, 다음문제를 호명하면 또 다른 문제를 받고, 총 결과를 호명하면 총 결과를 받고 끝내는 방식으로 대화하듯이 풀어나가려고 기획했었다. 그러나 답변이 튀는건 둘쨰치고 앞부분에 대화햇던것을 기억하지 못하는 대답이 돌아와서 문제와 답을 한번에주고 자바스크립트로 모두 해결해버리는 방식으로 전환하였다. 이 역시 시키는대로 오지않고 가끔 이상한 대답을 하는 것 떄문에 이부분은 조금 더 해결해야할듯한 숙제인 듯 하다.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors