Skip to content

Commit 4ad51b0

Browse files
committedMay 17, 2020
Implement Article Model, CRUD Routes, Decorators and Schemas - Issue #7
1 parent e13da42 commit 4ad51b0

File tree

6 files changed

+182
-0
lines changed

6 files changed

+182
-0
lines changed
 

‎api/backend/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@
2727
from ..backend.home.routes import home_bp
2828
from ..backend.meta.routes import meta_bp
2929
from ..backend.users.routes import user_bp
30+
from ..backend.articles.routes import articles_bp
3031

3132
app.register_blueprint(authentication_bp)
3233
app.register_blueprint(home_bp)
3334
app.register_blueprint(meta_bp)
3435
app.register_blueprint(user_bp)
36+
app.register_blueprint(articles_bp)

‎api/backend/articles/decorators.py

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from ..articles.schemas import article_form_schema
2+
from functools import wraps
3+
from flask import request
4+
from ..models import Article
5+
6+
7+
# Decorator to check if the article exists
8+
def article_exists(f):
9+
@wraps(f)
10+
def wrap(*args, **kwargs):
11+
article = Article.query.get(kwargs["article_id"])
12+
13+
if article:
14+
return f(*args, **kwargs)
15+
else:
16+
return {
17+
"message": "Article does not exist"
18+
}, 404
19+
20+
return wrap
21+
22+
23+
# Decorator to check if a article form data is valid
24+
def valid_article_form(f):
25+
@wraps(f)
26+
def wrap(*args, **kwargs):
27+
form_data = request.get_json()
28+
errors = article_form_schema.validate(form_data)
29+
30+
# If form data is not validated by the article_form_schema, then return a 500 error
31+
# else create the article and add it to the database
32+
if errors:
33+
return {
34+
"message": "Missing or sending incorrect data to create a article. Double check the JSON data that it has everything needed to create a classroom."
35+
}, 422
36+
else:
37+
return f(*args, **kwargs)
38+
39+
return wrap
40+
41+
42+
# Decorator to check if the Article table has articles before printing upto 15 articles
43+
def article_table_empty(f):
44+
@wraps(f)
45+
def wrap(*args, **kwargs):
46+
if Article.query.first():
47+
return f(*args, **kwargs)
48+
else:
49+
return {
50+
"message": "No articles present"
51+
}, 404
52+
53+
return wrap

‎api/backend/articles/routes.py

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from .. import api, db
2+
from ..articles.decorators import article_exists, valid_article_form, article_table_empty
3+
from ..articles.utils import create_article, update_article
4+
from ..articles.schemas import article_schema, articles_schema
5+
from flask import Blueprint, request
6+
from flask_restful import Resource
7+
from ..models import Article
8+
9+
# Blueprint for articles
10+
articles_bp = Blueprint("articles", __name__)
11+
12+
13+
# Class to handle information regarding the Article model
14+
class Articles(Resource):
15+
16+
# Function to create an article
17+
@valid_article_form
18+
def post(self):
19+
form_data = request.get_json()
20+
article = create_article(form_data)
21+
22+
db.session.add(article)
23+
db.session.commit()
24+
25+
return {"message": "Successfully created Article"}, 201
26+
27+
# Function to display all the articles up to a limit of 15
28+
@article_table_empty
29+
def get(self):
30+
article = Article.query.limit(15)
31+
return articles_schema.dump(article, default=str)
32+
33+
34+
class ArticleCRUD(Resource):
35+
36+
# Function to edit an article
37+
@valid_article_form
38+
@article_exists
39+
def put(self, article_id):
40+
article = Article.query.get(article_id)
41+
form_data = request.get_json()
42+
update_article(article, form_data)
43+
44+
db.session.commit()
45+
46+
return {"message": "Article successfully updated"}, 200
47+
48+
# Function to delete an article
49+
@article_exists
50+
def delete(self, article_id):
51+
article = Article.query.get(article_id)
52+
53+
db.session.delete(article)
54+
db.session.commit()
55+
56+
return {"message": "Article successfully deleted"}, 200
57+
58+
# Function to display an article
59+
@article_exists
60+
def get(self, article_id):
61+
article = Article.query.get(article_id)
62+
63+
return article_schema.dump(article)
64+
65+
# Creates the routes for the classes
66+
api.add_resource(Articles, "/api/articles")
67+
api.add_resource(ArticleCRUD, "/api/articles/<int:article_id>")

‎api/backend/articles/schemas.py

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from marshmallow import Schema, fields
2+
import toastedmarshmallow
3+
4+
# This schema is used to display article data
5+
class ArticleFormSchema(Schema):
6+
title = fields.Str(required=True)
7+
cover_image = fields.Str(required=False)
8+
content = fields.Str(required=False)
9+
10+
11+
# This schema is used to display article data
12+
class ArticleSchema(Schema):
13+
id = fields.Int(required=True)
14+
15+
class Meta:
16+
# Fields to show when sending data
17+
fields = ("id",)
18+
ordered = True
19+
20+
21+
article_form_schema = ArticleFormSchema()
22+
article_schema = ArticleSchema()
23+
articles_schema = ArticleSchema(many=True)
24+
article_form_schema.jit = toastedmarshmallow.Jit
25+
article_schema.jit = toastedmarshmallow.Jit
26+
articles_schema.jit = toastedmarshmallow.Jit

‎api/backend/articles/utils.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from ..models import Article
2+
3+
4+
# Function to create an article
5+
def create_article(form_data):
6+
article = Article(title=form_data["title"],
7+
cover_image=form_data["cover_image"],
8+
content=form_data["content"]
9+
)
10+
11+
return article
12+
13+
14+
# Function to update an article
15+
def update_article(article, form_data):
16+
article.title = form_data["title"]
17+
article.cover_image = form_data["cover_image"]
18+
article.content = form_data["content"]
19+
20+
return

‎api/backend/models.py

+14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from api.backend import db
2+
import datetime
23

34

45
class Meta(db.Model):
@@ -54,3 +55,16 @@ class Teacher(db.Model):
5455

5556
def __repr__(self):
5657
return f"Teacher('{self.id}')"
58+
59+
60+
class Article(db.Model):
61+
id = db.Column(db.Integer, primary_key=True)
62+
title = db.Column(db.Text, nullable=False)
63+
cover_image = db.Column(db.Text, nullable=True)
64+
content = db.Column(db.Text, nullable=False)
65+
date_published = db.Column(db.DateTime, nullable=False, default=datetime.date.today)
66+
likes = db.Column(db.Integer, nullable=False, default=0)
67+
is_published = db.Column(db.Boolean, nullable=False, default=True)
68+
69+
def __repr__(self):
70+
return f"Article('{self.id}')"

0 commit comments

Comments
 (0)
Please sign in to comment.