Progress
This commit is contained in:
2
.idea/jsLibraryMappings.xml
generated
2
.idea/jsLibraryMappings.xml
generated
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="JavaScriptLibraryMappings">
|
<component name="JavaScriptLibraryMappings">
|
||||||
<file url="file://$PROJECT_DIR$" libraries="{jquery-3.3.1.slim, popper}" />
|
<file url="file://$PROJECT_DIR$" libraries="{jquery-3.3.1, popper}" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
2
.idea/mvl.iml
generated
2
.idea/mvl.iml
generated
@@ -4,8 +4,8 @@
|
|||||||
<content url="file://$MODULE_DIR$" />
|
<content url="file://$MODULE_DIR$" />
|
||||||
<orderEntry type="jdk" jdkName="Pipenv (mvl)" jdkType="Python SDK" />
|
<orderEntry type="jdk" jdkName="Pipenv (mvl)" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" name="jquery-3.3.1.slim" level="application" />
|
|
||||||
<orderEntry type="library" name="popper" level="application" />
|
<orderEntry type="library" name="popper" level="application" />
|
||||||
|
<orderEntry type="library" name="jquery-3.3.1" level="application" />
|
||||||
</component>
|
</component>
|
||||||
<component name="TemplatesService">
|
<component name="TemplatesService">
|
||||||
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
|
<option name="TEMPLATE_CONFIGURATION" value="Jinja2" />
|
||||||
|
|||||||
64
app.py
64
app.py
@@ -1,7 +1,9 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from flask import Flask, render_template, request, jsonify
|
from flask import Flask, render_template, jsonify, abort
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from sqlalchemy import func
|
||||||
|
|
||||||
|
from model import Post, Category, db
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
@@ -13,14 +15,24 @@ app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv("DATABASE_URL")
|
|||||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||||
app.config['JSON_SORT_KEYS'] = False
|
app.config['JSON_SORT_KEYS'] = False
|
||||||
|
|
||||||
db = SQLAlchemy(app)
|
db.init_app(app)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def index():
|
def index():
|
||||||
result = Post.query.order_by(Post.priority).all()
|
posts = Post.get_posts()
|
||||||
print(result)
|
return render_template("main/index.html", posts=posts)
|
||||||
return render_template("main/index.html", count=12)
|
|
||||||
|
|
||||||
|
@app.route('/<string:category_name>')
|
||||||
|
def category(category_name):
|
||||||
|
|
||||||
|
category_item = Category.query.filter(func.lower(Category.name) == category_name.replace('_', ' ')).first()
|
||||||
|
if not category_item:
|
||||||
|
return abort(404)
|
||||||
|
|
||||||
|
posts = Post.get_posts_with_category(category_item.id)
|
||||||
|
|
||||||
|
return render_template("main/index.html", posts=posts)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/post/<int:post_id>", methods=["POST"])
|
@app.route("/api/post/<int:post_id>", methods=["POST"])
|
||||||
@@ -37,41 +49,3 @@ def login():
|
|||||||
return render_template("adm/login.html")
|
return render_template("adm/login.html")
|
||||||
|
|
||||||
|
|
||||||
class Post(db.Model):
|
|
||||||
__tablename__ = "posts"
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
priority = db.Column(db.Integer, unique=True, nullable=False)
|
|
||||||
|
|
||||||
category_id = db.Column(db.Integer, db.ForeignKey("category.id"), nullable=True)
|
|
||||||
category = db.relationship("Category", lazy=True)
|
|
||||||
|
|
||||||
title = db.Column(db.String(80), nullable=False)
|
|
||||||
intro = db.Column(db.Text, nullable=False)
|
|
||||||
description = db.Column(db.Text, nullable=True)
|
|
||||||
|
|
||||||
images = db.relationship("Image", backref="post", lazy=True)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def serialize(self):
|
|
||||||
return {"id": self.id,
|
|
||||||
"priority": self.priority,
|
|
||||||
"category_id": self.category_id,
|
|
||||||
"category": self.category.name,
|
|
||||||
"title": self.title,
|
|
||||||
"intro": self.intro,
|
|
||||||
"description": self.description,
|
|
||||||
"images": self.images}
|
|
||||||
|
|
||||||
|
|
||||||
class Image(db.Model):
|
|
||||||
__tablename__ = "images"
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
uri = db.Column(db.String(80), nullable=False)
|
|
||||||
post_id = db.Column(db.Integer, db.ForeignKey("posts.id"), nullable=False)
|
|
||||||
|
|
||||||
|
|
||||||
class Category(db.Model):
|
|
||||||
__tablename__ = "category"
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
name = db.Column(db.String(80), nullable=False)
|
|
||||||
|
|
||||||
|
|||||||
50
model.py
Normal file
50
model.py
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
|
||||||
|
db = SQLAlchemy()
|
||||||
|
|
||||||
|
|
||||||
|
class Post(db.Model):
|
||||||
|
__tablename__ = "posts"
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
priority = db.Column(db.Integer, unique=True, nullable=False)
|
||||||
|
|
||||||
|
category_id = db.Column(db.Integer, db.ForeignKey("category.id"), nullable=True)
|
||||||
|
category = db.relationship("Category", lazy=True)
|
||||||
|
|
||||||
|
title = db.Column(db.String(80), nullable=False)
|
||||||
|
intro = db.Column(db.Text, nullable=False)
|
||||||
|
description = db.Column(db.Text, nullable=True)
|
||||||
|
|
||||||
|
images = db.relationship("Image", backref="post", lazy=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serialize(self):
|
||||||
|
return {"id": self.id,
|
||||||
|
"priority": self.priority,
|
||||||
|
"category_id": self.category_id,
|
||||||
|
"category": self.category.name,
|
||||||
|
"title": self.title,
|
||||||
|
"intro": self.intro,
|
||||||
|
"description": self.description,
|
||||||
|
"images": self.images}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_posts():
|
||||||
|
return Post.query.order_by(Post.priority).all()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_posts_with_category(category_id):
|
||||||
|
return Post.query.filter(Post.category_id == category_id).order_by(Post.priority).all()
|
||||||
|
|
||||||
|
|
||||||
|
class Image(db.Model):
|
||||||
|
__tablename__ = "images"
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
uri = db.Column(db.String(80), nullable=False)
|
||||||
|
post_id = db.Column(db.Integer, db.ForeignKey("posts.id"), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class Category(db.Model):
|
||||||
|
__tablename__ = "category"
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
name = db.Column(db.String(80), nullable=False)
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
-i https://pypi.org/simple
|
|
||||||
click==7.0
|
|
||||||
flask-sqlalchemy==2.3.2
|
|
||||||
flask==1.0.2
|
|
||||||
gunicorn==19.9.0
|
|
||||||
itsdangerous==1.1.0
|
|
||||||
jinja2==2.10
|
|
||||||
markupsafe==1.1.1
|
|
||||||
psycopg2-binary==2.7.7
|
|
||||||
sqlalchemy==1.3.1
|
|
||||||
werkzeug==0.14.1
|
|
||||||
@@ -12,8 +12,9 @@
|
|||||||
<title>{% block title %}{% endblock %}</title>
|
<title>{% block title %}{% endblock %}</title>
|
||||||
|
|
||||||
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
|
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
|
||||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
|
<script
|
||||||
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
|
src="https://code.jquery.com/jquery-3.3.1.min.js"
|
||||||
|
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
|
||||||
crossorigin="anonymous"></script>
|
crossorigin="anonymous"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js"
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js"
|
||||||
integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut"
|
integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut"
|
||||||
|
|||||||
@@ -5,15 +5,18 @@
|
|||||||
{% block main %}
|
{% block main %}
|
||||||
<main class="container">
|
<main class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% for i in range(count) %}
|
{% for post in posts %}
|
||||||
<div class="col-lg-3 col-md-4 col-6">
|
<div class="col-lg-3 col-md-4 col-6">
|
||||||
<a data-toggle="modal" data-target="#detailModal" data-name="{{ i }}">
|
<a data-toggle="modal"
|
||||||
|
data-target="#detailModal"
|
||||||
|
data-post_id="{{ post.id }}"
|
||||||
|
>
|
||||||
<div class="card border-light">
|
<div class="card border-light">
|
||||||
<img class="card-img" src="https://placeimg.com/400/400/any" alt="random image">
|
<img class="card-img" src="https://placeimg.com/400/400/any" alt="random image">
|
||||||
|
|
||||||
<div class="card-img-overlay d-flex align-items-center justify-content-center">
|
<div class="card-img-overlay d-flex align-items-center justify-content-center">
|
||||||
<div class="card-title-bg bg-dark w-100 d-flex align-items-center justify-content-center">
|
<div class="card-title-bg bg-dark w-100 d-flex align-items-center justify-content-center">
|
||||||
<h5 class="card-text text-light">{{ i }}</h5>
|
<h5 class="card-text text-light">{{ post.title }}</h5>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
<div class="modal fade" id="detailModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
|
<div class="modal fade" id="detailModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
|
||||||
aria-hidden="true">
|
aria-hidden="true">
|
||||||
<div class="modal-dialog modal-lg" role="document">
|
<div class="modal-dialog modal-lg modal-dialog-scrollable" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title text-center" id="exampleModalLabel">Modal title</h5>
|
<h5 class="modal-title text-center" id="details-title">Modal title</h5>
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
|
<div id="details-intro"></div>
|
||||||
</p>
|
<div id="details-description"></div>
|
||||||
<p>Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -21,11 +19,20 @@
|
|||||||
<script>
|
<script>
|
||||||
$('#detailModal').on('show.bs.modal', function (event) {
|
$('#detailModal').on('show.bs.modal', function (event) {
|
||||||
let card = $(event.relatedTarget); // Button that triggered the modal
|
let card = $(event.relatedTarget); // Button that triggered the modal
|
||||||
let name = card.data('name'); // Extract info from data-* attributes
|
{#let name = card.data('name'); // Extract info from data-* attributes#}
|
||||||
// If necessary, you could initiate an AJAX request here (and then do the updating in a callback).
|
let post_id = card.data('post_id');
|
||||||
// Update the modal's content. We'll use jQuery here, but you could use a data binding library or other methods instead.
|
|
||||||
|
$.post(`/api/post/${post_id}`, data => {
|
||||||
|
if (!data.success) {
|
||||||
|
console.error("No data for post");
|
||||||
|
return;
|
||||||
|
}
|
||||||
let modal = $(this);
|
let modal = $(this);
|
||||||
modal.find('.modal-title').text(name);
|
console.log(data);
|
||||||
{#modal.find('.modal-body input').val(recipient)#}
|
modal.find('#details-title').text(data.post.title);
|
||||||
|
modal.find('#details-intro').text(data.post.intro);
|
||||||
|
modal.find('#details-description').text(data.post.description);
|
||||||
|
|
||||||
|
});
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
Reference in New Issue
Block a user