-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ocelots Anna Du #20
base: main
Are you sure you want to change the base?
Ocelots Anna Du #20
Changes from all commits
a7f93f7
970b865
f3c0a44
92ba167
21c1412
6cbed0b
5ef2b92
de7c76b
fe44a9c
2675462
3ac152d
3d2bc1d
e218a73
2b86314
eafc8c2
f3edbcf
ef22036
1c45fe8
b46fe90
27e7097
f76d903
503c5cb
4d3a93e
1d596ad
be161ba
9809f3e
f06397c
23c9a3c
ec8615b
77a328c
5cdaa45
352ab04
b0b45a8
20dae48
a4f462d
fbdfff3
f275f01
9596ea2
60881e0
b420483
ad7cecb
6a75a34
f7ad568
29c2641
4d247cf
3815b0d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,29 @@ | ||
import datetime | ||
from app import db | ||
|
||
class Customer(db.Model): | ||
id = db.Column(db.Integer, primary_key=True) | ||
id = db.Column(db.Integer, primary_key=True, autoincrement=True) | ||
name = db.Column(db.String,nullable = False) | ||
registered_at = db.Column(db.DateTime,default=(datetime.date.today())) | ||
postal_code = db.Column(db.String) | ||
phone = db.Column(db.String,nullable = False) | ||
videos_checked_out_count = db.Column(db.Integer, default=0) | ||
rentals = db.relationship("Rental", back_populates="customer") | ||
|
||
|
||
def to_dict(self): | ||
customer_dict = {} | ||
customer_dict["id"] = self.id | ||
customer_dict["name"] = self.name | ||
customer_dict["registered_at"] = self.registered_at | ||
customer_dict["phone"] = self.phone | ||
customer_dict["postal_code"] = self.postal_code | ||
return customer_dict | ||
|
||
@classmethod | ||
def from_dict(cls, customer_data): | ||
new_customer = Customer(name=customer_data["name"], | ||
phone=customer_data["phone"], | ||
postal_code = customer_data["postal_code"] | ||
) | ||
return new_customer |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,30 @@ | ||
import datetime | ||
from app import db | ||
|
||
class Rental(db.Model): | ||
id = db.Column(db.Integer, primary_key=True) | ||
id = db.Column(db.Integer, primary_key=True) | ||
customer_id = db.Column(db.Integer, db.ForeignKey("customer.id"),nullable = True) | ||
video_id = db.Column(db.Integer, db.ForeignKey("video.id"),nullable = True) | ||
due_date = db.Column(db.DateTime, default=(datetime.date.today()+datetime.timedelta(days=7))) | ||
check_out_status = db.Column(db.Boolean,default = True) | ||
available_inventory = db.Column(db.Integer) | ||
customer = db.relationship("Customer", back_populates="rentals") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice job setting up the rental relationships! |
||
video = db.relationship("Video", back_populates="rentals") | ||
|
||
def to_dict(self): | ||
rental_dict = {} | ||
rental_dict["id"] = self.id | ||
rental_dict["customer_id"] = self.customer_id | ||
rental_dict["video_id"] = self.video_id | ||
rental_dict["due_date"] = self.due_date | ||
rental_dict["check_out_status"] = self.check_out_status | ||
|
||
return rental_dict | ||
|
||
@classmethod | ||
def from_dict(cls, rental_data): | ||
new_rental = Rental( | ||
customer_id = rental_data["customer_id"], | ||
video_id = rental_data["video_id"] | ||
) | ||
return new_rental |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,27 @@ | ||
from app import db | ||
|
||
class Video(db.Model): | ||
id = db.Column(db.Integer, primary_key=True) | ||
id = db.Column(db.Integer, primary_key=True,autoincrement=True) | ||
title = db.Column(db.String,nullable = False) | ||
release_date = db.Column(db.String) | ||
total_inventory = db.Column(db.Integer) | ||
rentals = db.relationship("Rental", back_populates="video") | ||
|
||
|
||
def to_dict(self): | ||
video_dict = {} | ||
video_dict["id"] = self.id | ||
video_dict["title"] = self.title | ||
video_dict["release_date"] = self.release_date | ||
video_dict["total_inventory"] = self.total_inventory | ||
|
||
return video_dict | ||
|
||
@classmethod | ||
def from_dict(cls, video_data): | ||
new_video = Video(title=video_data["title"], | ||
release_date=video_data["release_date"], | ||
total_inventory = video_data["total_inventory"] | ||
) | ||
|
||
return new_video |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
from app import db | ||
from app.models.customer import Customer | ||
from app.models.video import Video | ||
from app.models.rental import Rental | ||
from flask import Blueprint, jsonify, abort, make_response, request | ||
from datetime import datetime | ||
|
||
|
||
customers_bp = Blueprint("customers_bp",__name__, url_prefix="/customers") | ||
|
||
def validate_model(cls, model_id): | ||
try: | ||
model_id = int(model_id) | ||
except: | ||
abort(make_response({"message":f"{cls.__name__} {model_id} invalid"}, 400)) | ||
|
||
model = cls.query.get(model_id) | ||
|
||
if not model: | ||
abort(make_response({"message":f"{cls.__name__} {model_id} was not found"}, 404)) | ||
|
||
return model | ||
|
||
def validate_num_queries(query_param): | ||
try: | ||
query_int = int(query_param) | ||
except: | ||
return False | ||
return True | ||
|
||
#============================== customers_bp.route ============================= | ||
#============================================================================ | ||
#GET /customers | ||
@customers_bp.route("", methods=["GET"]) | ||
def get_customers(): | ||
sort_query = request.args.get("sort") | ||
if sort_query == "name": | ||
customer_query = Customer.query.order_by(Customer.name) | ||
elif sort_query == "registered_at": | ||
customer_query = Customer.query.order_by(Customer.registered_at) | ||
elif sort_query == "postal_code": | ||
customer_query = Customer.query.order_by(Customer.postal_code) | ||
else: | ||
customer_query = Customer.query.order_by(Customer.id) | ||
|
||
count_query = request.args.get("count") | ||
page_num_query = request.args.get("page_num") | ||
if validate_num_queries(count_query) and validate_num_queries(page_num_query): | ||
page = customer_query.paginate(page=int(page_num_query), per_page=int(count_query), error_out=False) | ||
customers_response = [] | ||
|
||
for items in page.items: | ||
customers_response.append(items.to_dict()) | ||
return jsonify(customers_response), 200 | ||
|
||
if validate_num_queries(count_query) and not validate_num_queries(page_num_query): | ||
page = customer_query.paginate(per_page=int(count_query), error_out=False) | ||
customers = customer_query.all() | ||
customers_response = [] | ||
|
||
for items in page.items: | ||
customers_response.append(items.to_dict()) | ||
return jsonify(customers_response), 200 | ||
|
||
|
||
response_body = [] | ||
|
||
for customer in customer_query: | ||
response_body.append(customer.to_dict()) | ||
return jsonify(response_body) | ||
|
||
# POST /customers | ||
@customers_bp.route("", methods=["POST"]) | ||
def create_customer(): | ||
try: | ||
request_body = request.get_json() | ||
new_customer = Customer.from_dict(request_body) | ||
except: | ||
abort(make_response({"details":"Request body must include name.,Request body must include phone.,Request body must include postal_code."}, 400)) | ||
|
||
db.session.add(new_customer) | ||
db.session.commit() | ||
|
||
response_body = new_customer.to_dict() | ||
return make_response(response_body, 201) | ||
# GET /customers/<id> | ||
@customers_bp.route("/<id>", methods=["GET"]) | ||
def get_customers_by_id(id): | ||
customer = validate_model(Customer, id) | ||
|
||
return jsonify(customer.to_dict()) | ||
|
||
|
||
|
||
# DELETE /customers/<id> | ||
@customers_bp.route("/<id>", methods=["DELETE"]) | ||
def put_customers_by_id(id): | ||
customer = validate_model(Customer, id) | ||
|
||
db.session.delete(customer) | ||
db.session.commit() | ||
|
||
return jsonify(customer.to_dict()),200 | ||
|
||
# PUT /customers/<id> | ||
@customers_bp.route("/<id>", methods=["PUT"]) | ||
def delete_customers_by_id(id): | ||
customer = validate_model(Customer, id) | ||
try: | ||
request_body = request.get_json() | ||
customer.name = request_body["name"] | ||
customer.postal_code = request_body["postal_code"] | ||
customer.phone = request_body["phone"] | ||
except: | ||
abort(make_response(jsonify("Bad Request"), 400)) | ||
|
||
db.session.commit() | ||
|
||
return jsonify(customer.to_dict()),200 | ||
|
||
|
||
# `GET /customers/<id>/rentals` | ||
@customers_bp.route("/<id>/rentals", methods=["GET"]) | ||
def get_rentals_by_customer_id(id): | ||
customer = validate_model(Customer, id) | ||
|
||
video_query = Rental.query.filter_by(customer_id=customer.id).join(Video) | ||
sort_query = request.args.get("sort") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good use of joining tables! I will add that thanks to the relationships you've set up, you could use the OOP-style SQLAlchemy to get some of this information. Such as |
||
if sort_query == "title": | ||
rental_query = video_query.order_by(Video.title) | ||
else: | ||
rental_query = video_query.order_by(Video.id) | ||
count_query = request.args.get("count") | ||
page_num_query = request.args.get("page_num") | ||
|
||
if validate_num_queries(count_query) and validate_num_queries(page_num_query): | ||
|
||
page = video_query.paginate(page=int(page_num_query), per_page=int(count_query), error_out=False) | ||
video_result = [] | ||
|
||
for items in page.items: | ||
video_result.append(items.video.to_dict()) | ||
return jsonify(video_result), 200 | ||
if validate_num_queries(count_query) and not validate_num_queries(page_num_query): | ||
page = video_query.paginate(per_page=int(count_query), error_out=False) | ||
video_result = [] | ||
|
||
for items in page.items: | ||
video_result.append(items.video.to_dict()) | ||
return jsonify(video_result), 200 | ||
|
||
response_body = [] | ||
for rental in rental_query: | ||
response_body.append({"title":rental.video.title, | ||
"id":rental.video.id, | ||
"total_inventory":rental.video.total_inventory}) | ||
|
||
|
||
return jsonify(response_body) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
from app import db | ||
from app.models.rental import Rental | ||
from app.models.customer import Customer | ||
from app.models.video import Video | ||
from app.routes.customer_route import validate_model | ||
from flask import Blueprint, jsonify, abort, make_response, request | ||
from datetime import datetime | ||
|
||
rentals_bp = Blueprint("rentals_bp",__name__, url_prefix="/rentals") | ||
|
||
#============================== rentals_bp.route ============================= | ||
#============================================================================ | ||
|
||
## `POST /rentals/check-out` | ||
@rentals_bp.route("/check-out", methods=["POST"]) | ||
def create_rental(): | ||
request_body = request.get_json() | ||
try: | ||
new_rental = Rental.from_dict(request_body) | ||
except: | ||
abort(make_response({"message":f"Missing data"}, 400)) | ||
|
||
customer = validate_model(Customer, request_body["customer_id"]) | ||
video = validate_model(Video, request_body["video_id"]) | ||
|
||
if video.total_inventory == 0: | ||
abort(make_response({"message":f"Could not perform checkout"}, 400)) | ||
|
||
videos_checked_out = Rental.query.filter_by(video_id=video.id).count() # look into count method | ||
|
||
available_inventory = video.total_inventory - videos_checked_out | ||
if available_inventory == 0: | ||
abort(make_response({"message":f"Could not perform checkout"}, 400)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I see repeated code, I think about added cost of maintenance. In this case, I would wonder if there's a way to extract repeated code. Maybe at least defining the error string as a variable, so you only have to make changes in one location. :) |
||
|
||
# new_rental = Rental.from_dict(request_body) | ||
|
||
customer.videos_checked_out_count += 1 | ||
db.session.add(new_rental) | ||
db.session.add(customer) | ||
db.session.commit() | ||
|
||
rental_response = new_rental.to_dict() | ||
rental_response["videos_checked_out_count"] = customer.videos_checked_out_count | ||
available_inventory -= 1 | ||
rental_response["available_inventory"] = available_inventory | ||
|
||
return jsonify(rental_response), 200 | ||
|
||
|
||
|
||
|
||
## `POST /rentals/check-in` | ||
@rentals_bp.route("/check-in", methods=["POST"]) | ||
def check_in_rental(): | ||
request_body = request.get_json() | ||
try: | ||
rental = Rental.from_dict(request_body) | ||
except: | ||
abort(make_response({"message":f"Missing data"}, 400)) | ||
customer = validate_model(Customer, request_body["customer_id"]) | ||
video = validate_model(Video, request_body["video_id"]) | ||
|
||
rental = db.session.query(Rental).filter_by(video_id=video.id, customer_id=customer.id).first() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is another example where you might be able to make use of OOP-style SQLAlchemy interfaces, here :) |
||
|
||
if not rental: | ||
abort(make_response({"message": f"No outstanding rentals for customer {customer.id} and video {video.id}"}, 400)) | ||
|
||
if rental.check_out_status == False: | ||
abort(make_response({"message":f"Could not perform checkout bc already checked out"}, 400)) | ||
videos_checked_out = db.session.query(Rental).filter_by(video_id=video.id).all() # look into count method, refactor duplicate code | ||
available_inventory = video.total_inventory - len(videos_checked_out) | ||
|
||
customer.videos_checked_out_count -= 1 | ||
available_inventory += 1 | ||
rental.check_out_status = False | ||
|
||
|
||
db.session.add(rental) | ||
db.session.commit() | ||
|
||
rental_response = rental.to_dict() | ||
rental_response["videos_checked_out_count"] = customer.videos_checked_out_count | ||
rental_response["available_inventory"] = available_inventory | ||
|
||
return jsonify(rental_response), 200 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good