[엘리스 AI 트랙] 9주차 - 5
- Rent 테이블 스키마 구상 및 생성 (mysql, python 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을 빼주는 작업도 처리했다.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()
이렇게 해결했다.datetime
라이브러리의 date.today()
이용) 아무리 db에서 확인해도 null값이길래 왜 그런지 헤매다가 이유를 찾았다. db.session.commit()
을 안했던 것.. ㅋㅋㅋ 바보같은 실수였지만 발생할 수 있는 실수이므로 앞으로 주의해야겠다.