-
Couldn't load subscription status.
- Fork 44
QT_task-list-api #44
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
base: main
Are you sure you want to change the base?
QT_task-list-api #44
Conversation
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.
Nice work on your Task List API, Qiaoqiao!
| from .routes.task_routes import tasks_bp | ||
| from .routes.goal_routes import goals_bp |
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.
Don't forget that Flask convention is to name your Blueprints bp and then inside of our __init__.py file we can import with as.
| from dotenv import load_dotenv | ||
| load_dotenv() |
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.
Nice, using load_dotenv to ensure that your environmental variables are loaded before being accessed.
| app.register_blueprint(tasks_bp) | ||
| app.register_blueprint(goals_bp) |
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.
⭐️
|
|
||
| class Goal(db.Model): | ||
| id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) | ||
| title: Mapped[str] |
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.
Love this! This is the pattern that we showed you in class! Leveraging the Declarative Mapping Annotation to declare this column as a non-nullable string.
| class Goal(db.Model): | ||
| id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) | ||
| title: Mapped[str] | ||
| tasks: Mapped[list["Task"]] = relationship(back_populates="goal") |
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.
Perfect! You are making a relationship attribute on the Goal model. This attribute is going to be a list of Task models. You then use relationship with back_populates to tell SQLAlchemy to sync this attribute with relationship attribute called goal on the Task model.
| title_param = request.args.get("title") | ||
| if title_param: | ||
| query = query.where(Task.title.ilike(f"%{title_param}%")) | ||
|
|
||
| sort_param = request.args.get("sort") | ||
| if sort_param: | ||
| if sort_param.lower() == "asc": | ||
| query = query.order_by(asc(Task.title)) | ||
| elif sort_param.lower() == "desc": | ||
| query = query.order_by(desc(Task.title)) | ||
|
|
||
| query = query.order_by(Task.id) | ||
|
|
||
| tasks = db.session.scalars(query) | ||
|
|
||
| tasks_response = [] | ||
| for task in tasks: | ||
| tasks_response.append(task.to_dict()) | ||
| return tasks_response |
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.
We could D.R.Y. this up as well with get_model_with_filters
| def get_one_task(task_id): | ||
| task = validate_model(Task, task_id) | ||
|
|
||
| return {"task": task.to_dict()} |
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.
| return {"task": task.to_dict()} | |
| return { "task": task.to_dict() } |
| task.title = request_body["title"] | ||
| task.description = request_body["description"] |
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.
This is another opportunity to D.R.Y. up our code! Notice how in this route and the PUT route for goal_routes.py we follow the pattern of:
object.ATTRIBUTE = request_body["ATTRIBUTE"]We use hasattr and setattr to make a helper function to update our Task and Goal model. It would look like this:
def update_model(obj, data):
for attr, value in data.items():
if hasattr(obj, attr):
setattr(obj, attr, value)
db.session.commit()
return Response(status=204, mimetype="application/json")This refactor not only makes our code D.R.Y but shows that we recognize logic that has higher level usability while handling cases of keys not being found!
|
|
||
| # Assert | ||
| assert response.status_code == 404 | ||
| assert response_body == {'message': 'Task 1 not found'} |
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.
⭐️
| query = db.select(Goal).where(Goal.id == 1) | ||
| goal = db.session.scalar(query) |
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.
Nice work checking the database!
No description provided.