9-5 : 도서관 대여 서비스 (개인 프로젝트)

Sue·2021년 11월 20일
0

엘리스 AI 트랙

목록 보기
5/10

[엘리스 AI 트랙] 9주차 - 5

  • Rent 테이블 스키마 구상 및 생성 (mysql, python sqlalchemy)
  • 대여하기 기능 구현
  • 반납하기 페이지 구현
  • 반납하기 기능 구현

  • Rent 테이블 스키마 구상 및 생성 (mysql, Flask sqlalchemy)
    mysql> create table `rent_tb`(
        -> _id int primary key auto_increment not null,
        -> user_id int not null,
        -> book_id int not null,
        -> rent_date date,
        -> due_date date,
        -> foreign key(user_id) references user_tb(_id) on update cascade,
        -> foreign key(book_id) references books_tb(_id) on update cascade);
    Query OK, 0 rows affected (0.30 sec)
    • maria db에서는rent_date date default current_date 의 형태로 지정하면 된다는 글을 보고 시도해 보았지만 에러가 났다.
      (https://stackoverflow.com/questions/20461030/current-date-curdate-not-working-as-default-date-value)
      mysql에서는 date를 데이터 삽입하는 당일로 default를 설정하는 방법을 구글링해도 잘 모르겠어서 default 값 설정을 따로 하지 않았다. 일단 데이터 삽입은 mysql cli로 바로 하는 것이 아닌 Flask 에서 할 것이기 때문에 가능한 일이었다.

      # models.py
      
      class User(db.Model):
          __tablename__ = 'user_tb'
          _id = db.Column(db.Integer,  primary_key=True,
                         nullable=False, autoincrement=True)
          name = db.Column(db.String(20), nullable=False)
          email = db.Column(db.String(30), nullable=False, unique=True)
          pw = db.Column(db.String(200), nullable=False)
      
          renter = db.relationship("Rent", backref='user_tb')
      
          def __init__(self, user_name, user_email, user_pw):
              self.name = user_name
              self.email = user_email
              self.pw = user_pw
      
      class Rent(db.Model):
          __tablename__='rent_tb'
          _id = db.Column(db.Integer, primary_key=True, nullable=False, autoincrement=True)
          user_id = db.Column(db.Integer, db.ForeignKey('user_tb._id'), nullable=False)
          book_id = db.Column(db.Integer, db.ForeignKey('books_tb._id'), nullable=False)
          rent_date = db.Column(db.Date, default=date.today)
          due_date = db.Column(db.Date, default=date.today()+timedelta(days=14))
          return_date = db.Column(db.Date)
      
          def __init__(self, user_id, book_id):
              self.user_id = user_id
              self.book_id = book_id
    • 이 코드를 짜기까지 수많은 에러와 구글링을 겪었다. sqlalchemy로 foreign key 설정하는 방법을 잘 몰라서 조금 오래 걸렸다. 찾아볼 때 db.ForeignKey, ForeignKey, foreign_key 등 여러 비슷한 코드가 나왔는데 저것만 설정하는 것이 아닌 참조 받는 테이블에서도 relationship이라는 걸 설정해줘야 했다. renter = db.relationship("Rent", backref='user_tb') 이런 식으로!! 괄호 안에는 참조하는 테이블, 참조받는 테이블의 실제 db상 이름을 넣어주었다. → 엘리스 11/11일 실시간 강의 코드를 많이 참고했다. 또, Rent 테이블에서 foreign key 설정할 때 nullable=False를 제일 뒤로 빼줘야 오류가 없었다. (그 전에 났던 오류 : https://stackoverflow.com/questions/59626077/positional-argument-after-keyword-argument-and-regular-parameter-after-paramet)

    • due date를 14일 뒤로 설정해주고 싶었다. 이는 date와 timedelta의 덧셈으로 해결할 수 있었다. (참고한 글 : https://wangin9.tistory.com/entry/datetime)


  • 대여하기 기능 구현
    function rentBook(bookId){
    
            let renter = `{{g.user._id}}`
    
            $.ajax({
                url: '/rent',
                type: 'patch',
                data: {
                    'book_id': bookId,
                    'renter': renter,
                },
                success: function (res){
                    let result = res['result']
                    if (result == "success") {
                        alert("대여 완료!")
                        window.location.reload()
                    } else if (result == "disable") {
                        alert("현재 대여가 불가능한 책입니다.")
                    } else {
                        alert("문제가 생겼어요. 다시 시도해 주세요.")
                    }
                }
            });
    @board.route("/rent", methods=["PATCH"])
    def rent():
        book_id = request.form['book_id']
        book = Books.query.filter(Books._id==book_id).first()
        if book.stock > 0:
            book.stock -= 1
            db.session.commit()
    
            user_id = request.form['renter']
            rent = Rent(user_id, book._id)
            db.session.add(rent)
            db.session.commit()
            return jsonify({"result": "success"})
        return jsonify({"result": "disable"})
    • <a href="#" class="btn btn-primary">대여하기</a> 를 통해 대여하기 버튼을 누르면 rentBook 함수가 실행된다. return false;를 붙여 href로 연결된 링크로 이동하지 않게 했다. (참고 : https://ggmouse.tistory.com/418) rentBook 함수에서 책 id와 빌리는 사람을 전달해주어 Rent 테이블에 새로운 값으로 넣어주었다. 책의 재고를 확인해서 1을 빼주는 작업도 처리했다.


  • 반납하기 페이지 구현 반납하기 페이지도 메인 페이지와 거의 유사한 형태이다. 하지만 여기서 까다로웠던 부분은 user가 빌린 책의 이미지, 책 이름, 빌린 날짜를 보여주어야 하는데 이는 여러개의 테이블에 나눠져 있는 정보이다. 따라서 orm 쿼리를 짜는 게 조금 어려웠다. 하지만 records = db.session.query(Books.img_path, Books.book_name, Books._id, Rent.rent_date).filter(Books._id==Rent.book_id, Rent.user_id==g.user._id, Rent.return_date==None).all() 이렇게 해결했다.
    (sqlalchemy 관련 참고하기 좋은 글 : https://lowelllll.github.io/til/2019/04/19/TIL-flask-sqlalchemy-orm/)


  • 반납하기 기능 구현 반납하기 버튼을 누르면 Rent 테이블에 저장되어 있던 데이터 중에 해당 user가 빌린 그 책의 return_date를 오늘로 업데이트 해야 한다. 분명 Flask에서 처리를 했는데 (datetime 라이브러리의 date.today() 이용) 아무리 db에서 확인해도 null값이길래 왜 그런지 헤매다가 이유를 찾았다. db.session.commit()을 안했던 것.. ㅋㅋㅋ 바보같은 실수였지만 발생할 수 있는 실수이므로 앞으로 주의해야겠다.

0개의 댓글