ππ Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Π°Π½Π°Π»ΠΎΠ³ LiveLib.ru Π½Π° Flask. Π§Π°ΡΡΡ 1: ΠΎΡΠ½ΠΎΠ²Ρ ΡΠ°Π±ΠΎΡΡ Ρ SQLAlchemy
ΠΠ·ΡΡΠ°Π΅ΠΌ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ Flask Ρ SQLAlchemy ΠΈ WTForms, ΡΠΎΠ·Π΄Π°Π²Π°Ρ Π²Π΅Π±-ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ β Π»Π°ΠΉΡ-Π²Π΅ΡΡΠΈΡ ΡΠ΅ΡΠ²ΠΈΡΠ° LiveLib.ru β Π΄Π»Ρ Ρ ΡΠ°Π½Π΅Π½ΠΈΡ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ ΠΎ ΠΏΡΠΎΡΠΈΡΠ°Π½Π½ΡΡ ΠΊΠ½ΠΈΠ³Π°Ρ . Π Π΅Π°Π»ΠΈΠ·ΡΠ΅ΠΌ CRUD, ΠΏΠ°Π³ΠΈΠ½Π°ΡΠΈΡ, ΡΠΈΠ»ΡΡΡΡ ΠΈ ΡΠΊΡΠΏΠΎΡΡ Π΄Π°Π½Π½ΡΡ .
ΠΡΠ±ΠΎΠ΅ Π±ΠΎΠ»Π΅Π΅-ΠΌΠ΅Π½Π΅Π΅ ΡΠ΅ΡΡΠ΅Π·Π½ΠΎΠ΅ Π²Π΅Π±-ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ Π±Π°Π·Ρ Π΄Π°Π½Π½ΡΡ Π΄Π»Ρ Ρ ΡΠ°Π½Π΅Π½ΠΈΡ ΠΏΠΎΠ»ΡΡΠ΅Π½Π½ΠΎΠΉ ΠΎΡ ΡΡΠΎΠ½ΡΠ΅Π½Π΄Π° ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ. ΠΠ»Ρ ΡΠΏΡΠΎΡΠ΅Π½ΠΈΡ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ Flask-ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Ρ Π±Π°Π·ΠΎΠΉ ΡΠ°ΡΠ΅ Π²ΡΠ΅Π³ΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΡ SQLAlchemy, Π° Π΄Π»Ρ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΡ ΠΈ Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΠΈ Π΄Π°Π½Π½ΡΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ β ΡΠΎΡΠΌΡ WTForms.
ΠΠ±Π·ΠΎΡ ΠΏΡΠΎΠ΅ΠΊΡΠ°
ΠΡΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄Π»Ρ Π²Π΅Π΄Π΅Π½ΠΈΡ ΡΠΏΠΈΡΠΊΠ° ΠΏΡΠΎΡΠΈΡΠ°Π½Π½ΡΡ ΠΊΠ½ΠΈΠ³. ΠΠ»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΊΠ½ΠΈΠ³ΠΈ ΡΠΎΠ·Π΄Π°Π΅ΡΡΡ ΠΎΡΠ΄Π΅Π»ΡΠ½Π°Ρ ΠΊΠ°ΡΡΠΎΡΠΊΠ° Ρ ΠΏΠΎΡΡΠ΅ΡΠΎΠΌ, ΠΈΠΌΠ΅Π½Π΅ΠΌ Π°Π²ΡΠΎΡΠ°, Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ ΠΆΠ°Π½ΡΠ°, ΠΎΠΏΠΈΡΠ°Π½ΠΈΠ΅ΠΌ ΡΡΠΆΠ΅ΡΠ°, ΠΎΡΠ΅Π½ΠΊΠΎΠΉ ΠΈ ΠΏΡΠΈΠΌΠ΅ΡΠ°Π½ΠΈΡΠΌΠΈ. ΠΠ°ΡΡΠΎΡΠΊΠΈ ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΅Π΄Π°ΠΊΡΠΈΡΠΎΠ²Π°ΡΡ ΠΈ ΡΠ΄Π°Π»ΡΡΡ. ΠΠ΅ΡΡ ΠΊΠΎΠ΄ ΠΏΡΠΎΠ΅ΠΊΡΠ° Π½Π°Ρ ΠΎΠ΄ΠΈΡΡΡ Π·Π΄Π΅ΡΡ.
Π§ΡΠΎ ΠΌΡ ΠΈΠ·ΡΡΠΈΠΌ Π² ΠΏΡΠΎΡΠ΅ΡΡΠ΅ ΡΠ°Π±ΠΎΡΡ
- Π£Π·Π½Π°Π΅ΠΌ, ΠΊΠ°ΠΊ ΡΠΎΠ·Π΄Π°ΡΡ Π±Π°Π·Ρ Π΄Π°Π½Π½ΡΡ ΠΈ Π·Π°ΠΏΠΎΠ»Π½ΠΈΡΡ Π΅Π΅ ΡΠ΅ΡΡΠΎΠ²ΡΠΌΠΈ Π΄Π°Π½Π½ΡΠΌΠΈ ΠΈΠ· json-ΡΠ°ΠΉΠ»Π°.
- Π Π΅Π°Π»ΠΈΠ·ΡΠ΅ΠΌ ΠΏΠ°Π³ΠΈΠ½Π°ΡΠΈΡ ΠΈ Π½Π°Π±ΠΎΡ CRUD-ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ Π΄Π»Ρ ΡΠ°Π±ΠΎΡΡ Ρ ΠΊΠ°ΡΡΠΎΡΠΊΠ°ΠΌΠΈ ΠΊΠ½ΠΈΠ³.
- ΠΠ°ΠΏΠΈΡΠ΅ΠΌ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΠΉ Π²Π°Π»ΠΈΠ΄Π°ΡΠΎΡ ΠΈ ΠΎΠ±ΡΠ°Π±ΠΎΡΠ°Π΅ΠΌ ΠΎΡΠΈΠ±ΠΊΡ IntegrityError.
- Π‘Π΄Π΅Π»Π°Π΅ΠΌ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΡΠΈΠ»ΡΡΡΠΎΠ² Π΄Π»Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π½ΡΡ ΠΊΠ°ΡΠ΅Π³ΠΎΡΠΈΠΉ Π΄Π°Π½Π½ΡΡ .
- ΠΠΎΠ±Π°Π²ΠΈΠΌ Π² ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΡΠΎΡΡΡΡ (Π±Π΅Π· JS) ΡΠΈΡΡΠ΅ΠΌΡ ΠΎΡΠ΅Π½ΠΊΠΈ ΠΊΠ½ΠΈΠ³.
- Π Π°ΡΡΠΌΠΎΡΡΠΈΠΌ ΡΠΏΠΎΡΠΎΠ±Ρ ΡΠ°Π±ΠΎΡΡ Ρ ΠΎΠ±ΡΠ΅ΠΊΡΠ°ΠΌΠΈ Π΄Π°Π½Π½ΡΡ Π² ΡΠ°Π±Π»ΠΎΠ½ΠΈΠ·Π°ΡΠΎΡΠ΅ Jinja2.
ΠΠ΅ΡΠ²ΡΠΉ ΡΡΠ°ΠΏ
ΠΡΠ΅ΠΆΠ΄Π΅ Π²ΡΠ΅Π³ΠΎ ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΡ Π΄Π»Ρ ΠΏΡΠΎΠ΅ΠΊΡΠ°, Π°ΠΊΡΠΈΠ²ΠΈΡΡΠ΅ΠΌ Π²ΠΈΡΡΡΠ°Π»ΡΠ½ΠΎΠ΅ ΠΎΠΊΡΡΠΆΠ΅Π½ΠΈΠ΅ ΠΈ ΡΡΡΠ°Π½ΠΎΠ²ΠΈΠΌ Π²ΡΠ΅ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΡΠ΅ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ Ρ ΠΏΠΎΠΌΠΎΡΡΡ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅ΡΠ° pipenv:
mkdir reader cd reader mkdir .venv pipenv shell pipenv install -r requirements.txt
Π‘ΡΡΡΠΊΡΡΡΠ° Π³ΠΎΡΠΎΠ²ΠΎΠ³ΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ Π²ΡΠ³Π»ΡΠ΄ΠΈΡ ΡΠ°ΠΊ:
| run.py | \---reader | database.db | forms.py | models.py | routes.py | __init__.py | +---static | \---css | style.css | +---templates | base.html | best.html | book.html | create.html | edit.html | index.html | thrillers.html | _formhelpers.html | \---uploads
ΠΡΠΈΡΡΡΠΏΠ°Π΅ΠΌ ΠΊ ΡΠ°Π±ΠΎΡΠ΅
ΠΡΠΈΠ²Π΅Π΄Π΅Π½Π½ΡΠΉ Π½ΠΈΠΆΠ΅ ΠΊΠΎΠ΄ ΠΎΡΠ²Π΅ΡΠ°Π΅Ρ Π·Π° ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΡΠΊΠ·Π΅ΠΌΠΏΠ»ΡΡΠ° Flask-ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ ΠΈ ΠΎΠ±ΡΠ΅ΠΊΡΠ° Π±Π°Π·Ρ Π΄Π°Π½Π½ΡΡ . Π‘ΠΎΡ ΡΠ°Π½ΠΈΡΠ΅ Π΅Π³ΠΎ Π² ΡΠ°ΠΉΠ»Π΅ /reader/__init__.py:
from flask import Flask from flask_sqlalchemy import SQLAlchemy import os app = Flask(__name__) basedir = os.path.abspath(os.path.dirname(__file__)) app.config['SQLALCHEMY_DATABASE_URI'] =\ 'sqlite:///' + os.path.join(basedir, 'database.db') app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SECRET_KEY'] = 'hard to guess' db = SQLAlchemy(app)
ΠΡΠΈΠΌΠ΅ΡΠ°Π½ΠΈΠ΅: Π΅ΡΠ»ΠΈ Π²Ρ ΠΏΠ»Π°Π½ΠΈΡΡΠ΅ΡΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Π΄ΡΡΠ³ΠΎΠΉ ΡΠΈΠΏ Π±Π°Π·Ρ Π΄Π°Π½Π½ΡΡ β MySQL ΠΈΠ»ΠΈ PostgreSQL β URI Π΄ΠΎΠ»ΠΆΠ΅Π½ Π²ΡΠ³Π»ΡΠ΄Π΅ΡΡ ΡΠ°ΠΊ:
mysql://username:password@host:port/database_name postgresql://username:password@host:port/database_name
ΠΠΎΠ΄Π΅Π»Ρ Π±Π°Π·Ρ Π΄Π°Π½Π½ΡΡ
Π’Π΅ΠΏΠ΅ΡΡ Π½ΡΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°ΡΡ ΠΌΠΎΠ΄Π΅Π»Ρ (ΡΠ°Π±Π»ΠΈΡΡ) Π² Π±Π°Π·Π΅ Π΄Π°Π½Π½ΡΡ Π΄Π»Ρ Ρ ΡΠ°Π½Π΅Π½ΠΈΡ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ ΠΎ ΠΊΠ½ΠΈΠ³Π°Ρ . ΠΠ»Ρ ΡΡΠΎΠ³ΠΎ ΡΠΎΡ ΡΠ°Π½ΠΈΡΠ΅ ΠΏΡΠΈΠ²Π΅Π΄Π΅Π½Π½ΡΠΉ Π½ΠΈΠΆΠ΅ ΠΊΠΎΠ΄ Π² ΡΠ°ΠΉΠ»Π΅ /reader/models.py:
from reader import app, db from sqlalchemy.sql import func class Book(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(100), unique=True, nullable=False) author = db.Column(db.String(100), nullable=False) genre = db.Column(db.String(20), nullable=False) rating = db.Column(db.Integer) cover = db.Column(db.String(50), nullable=False, default='default.jpg') description = db.Column(db.Text) notes = db.Column(db.Text) created_at = db.Column(db.DateTime(timezone=True), server_default=func.now()) def __repr__(self): return f'<Book {self.title}>'
ΠΠ½Π°ΡΠ΅Π½ΠΈΠ΅ cover ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ ΡΠ°Π²Π½ΠΎ default.jpg
β ΡΡΠΎ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ Π½Π°Π΄ΠΎ Π·Π°ΡΠ°Π½Π΅Π΅ ΠΏΠΎΠΌΠ΅ΡΡΠΈΡΡ Π² ΠΏΠ°ΠΏΠΊΡ /reader/uploads/. ΠΠ±ΡΠ°ΡΠΈΡΠ΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ Π½Π° ΠΎΠ΄ΠΈΠ½ ΠΈΠ· Π°ΡΡΠΈΠ±ΡΡΠΎΠ² ΠΏΠΎΠ»Ρ title, unique=True
: ΡΡΠΎ ΠΎΠ·Π½Π°ΡΠ°Π΅Ρ, ΡΡΠΎ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΊΠ½ΠΈΠ³ΠΈ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±ΡΡΡ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½ΡΠΌ. ΠΡΠ»ΠΈ Π½Π΅ ΠΏΡΠ΅Π΄ΠΎΡΠ²ΡΠ°ΡΠΈΡΡ Π²Π²ΠΎΠ΄ Π΄ΡΠ±Π»ΠΈΠΊΠ°ΡΠ° (ΠΌΡ ΡΠ΄Π΅Π»Π°Π΅ΠΌ ΡΡΠΎ ΠΏΠΎΠ·ΠΆΠ΅ Π²ΠΎ Π²ΡΠ΅ΠΌΡ Π²Π°Π»ΠΈΠ΄Π°ΡΠΈΠΈ ΡΠΎΡΠΌΡ), ΡΠ°Π±ΠΎΡΠ° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ Π±ΡΠ΄Π΅Ρ ΠΏΡΠ΅ΡΠ²Π°Π½Π° ΠΎΡΠΈΠ±ΠΊΠΎΠΉ IntegrityError UNIQUE constraint failed
.
ΠΠ»Ρ Π·Π°ΠΏΡΡΠΊΠ° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ ΡΠΎΠ·Π΄Π°ΠΉΡΠ΅ ΡΠ°ΠΉΠ» run.py:
from reader import app if __name__ == '__main__': app.run(host='127.0.0.1', port=8000, debug=True)
ΠΡΠ΅ Π³ΠΎΡΠΎΠ²ΠΎ Π΄Π»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ Π±Π°Π·Ρ Π΄Π°Π½Π½ΡΡ β ΠΌΡ ΡΠ΄Π΅Π»Π°Π΅ΠΌ ΡΡΠΎ Π² ΠΈΠ½ΡΠ΅ΡΠ°ΠΊΡΠΈΠ²Π½ΠΎΠΉ ΠΊΠΎΠ½ΡΠΎΠ»ΠΈ Flask:
(.venv) D:\reader>set FLASK_APP=run (.venv) D:\reader>flask shell >>> from app import db >>> from reader import db >>> from reader.models import Book >>> db.create_all()
ΠΠ°Π³Π»ΡΠ½ΠΈΡΠ΅ Π² ΠΏΠ°ΠΏΠΊΡ /reader β ΡΠ°ΠΌ ΠΏΠΎΡΠ²ΠΈΠ»ΡΡ ΡΠ°ΠΉΠ» Π±Π°Π·Ρ, database.
ΠΡΠΈΠΌΠ΅ΡΠ°Π½ΠΈΠ΅: ΠΏΠΎΡΠ»Π΅ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΡΠ°Π±Π»ΠΈΡΡ Π΅Π΅ ΡΡΡΡΠΊΡΡΡΡ Π½Π΅Π»ΡΠ·Ρ ΠΏΡΠΎΡΡΠΎ ΡΠ°ΠΊ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡΡ (Π΄ΠΎΠ±Π°Π²ΠΈΡΡ Π½ΠΎΠ²ΡΠΉ ΡΡΠΎΠ»Π±Π΅Ρ, ΠΊ ΠΏΡΠΈΠΌΠ΅ΡΡ). ΠΡΡ ΠΎΠ΄ β Π²ΠΎΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡΡΡ ΡΠ°ΡΡΠΈΡΠ΅Π½ΠΈΠ΅ΠΌ Flask-Migrate, Π»ΠΈΠ±ΠΎ, Π΅ΡΠ»ΠΈ Π΄Π°Π½Π½ΡΡ Π² Π±Π°Π·Π΅ ΡΠΎΠ²ΡΠ΅ΠΌ ΠΌΠ°Π»ΠΎ ΠΈ ΠΏΠΎΡΠ΅ΡΡΡΡ ΠΈΡ Π½Π΅ ΠΆΠ°Π»Ρ, Π²ΡΠΏΠΎΠ»Π½ΠΈΡΡ:
>>> db.drop_all() >>> db.create_all()
ΠΠ°ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π±Π°Π·Ρ ΡΠ΅ΡΡΠΎΠ²ΡΠΌΠΈ Π΄Π°Π½Π½ΡΠΌΠΈ
ΠΠ½ΡΠ΅ΡΠ°ΠΊΡΠΈΠ²Π½Π°Ρ ΠΊΠΎΠ½ΡΠΎΠ»Ρ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ Π΄ΠΎΠ±Π°Π²Π»ΡΡΡ Π·Π°ΠΏΠΈΡΠΈ Π² Π±Π°Π·Ρ ΠΏΠΎ ΠΎΠ΄Π½ΠΎΠΉ:
>>> book1 = Book(title = 'ΠΡΠ΅ΡΡΡΠΏΠ»Π΅Π½ΠΈΠ΅ ΠΈ Π½Π°ΠΊΠ°Π·Π°Π½ΠΈΠ΅', ... author = 'Π€Π΅Π΄ΠΎΡ ΠΠΎΡΡΠΎΠ΅Π²ΡΠΊΠΈΠΉ', ... genre = 'Π΄ΡΠ°ΠΌΠ°', ... rating = '4', ... description = 'ΠΡΡΠΎΡΠΈΡ Π ΠΎΠ΄ΠΈΠΎΠ½Π° Π Π°ΡΠΊΠΎΠ»ΡΠ½ΠΈΠΊΠΎΠ²Π°.', ... notes = 'ΠΠ΅Π²Π΅ΠΆΠ΅ΡΡΠ²ΠΎ - ΠΌΠ°ΡΡ Π²ΡΠ΅Ρ ΠΏΡΠ΅ΡΡΡΠΏΠ»Π΅Π½ΠΈΠΉ.') >>> db.session.add(book1) >>> db.session.commit()
ΠΠ»ΠΈ ΠΏΠΎ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΡ ΡΡΠ°Π·Ρ:
>>> book2 = Book(title = 'ΠΠΎΡ', ... author = 'ΠΠΈΠΊΠΎΠ»Π°ΠΉ ΠΠΎΠ³ΠΎΠ»Ρ', ... genre = 'ΡΡΠ½ΡΠ΅Π·ΠΈ', ... rating = '5', ... description = 'ΠΡΡΠΎΡΠΈΡ ΡΠ±Π΅ΠΆΠ°Π²ΡΠ΅Π³ΠΎ Π½ΠΎΡΠ°.', ... notes = 'ΠΠ΅Π· Π½ΠΎΡΠ° ΡΠ΅Π»ΠΎΠ²Π΅ΠΊ - ΡΠ΅ΡΡ Π·Π½Π°Π΅Ρ ΡΡΠΎ: ΠΏΡΠΈΡΠ° Π½Π΅ ΠΏΡΠΈΡΠ°, Π³ΡΠ°ΠΆΠ΄Π°Π½ΠΈΠ½ Π½Π΅ Π³ΡΠ°ΠΆΠ΄Π°Π½ΠΈΠ½, - ΠΏΡΠΎΡΡΠΎ Π²ΠΎΠ·ΡΠΌΠΈ, Π΄Π° ΠΈ Π²ΡΡΠ²ΡΡΠ½ΠΈ Π² ΠΎΠΊΠΎΡΠΊΠΎ!') >>> >>> book3 = Book(title = 'ΠΠ°ΡΡΠ΅Ρ ΠΈ ΠΠ°ΡΠ³Π°ΡΠΈΡΠ°', ... author = 'ΠΠΈΡ Π°ΠΈΠ» ΠΡΠ»Π³Π°ΠΊΠΎΠ²', ... genre = 'ΡΡΠ½ΡΠ΅Π·ΠΈ', ... rating = '5', ... description = 'ΠΡΡΠΎΡΠΈΡ ΠΎ ΠΡΡΠ²ΠΎΠ»Π΅, ΠΈΡΠΊΡΠΏΠ»Π΅Π½ΠΈΠΈ ΠΈ ΠΊΠΎΡΠ΅ ΠΠ΅Π³Π΅ΠΌΠΎΡΠ΅.', ... notes = 'ΠΠ·Π΄ΠΎΡ! ΠΠ΅Ρ ΡΠ΅ΡΠ΅Π· ΡΡΠΈΡΡΠ° ΡΡΠΎ ΠΏΡΠΎΠΉΠ΄Π΅Ρ.') >>> db.session.add(book2) >>> db.session.add(book3) >>> db.session.commit()
ΠΡΠ»ΠΈ ΡΠ΅ΠΉΡΠ°Ρ Π²ΡΠΏΠΎΠ»Π½ΠΈΡΡ Π·Π°ΠΏΡΠΎΡ ΠΊ Π±Π°Π·Π΅, ΠΌΠΎΠΆΠ½ΠΎ ΡΠ²ΠΈΠ΄Π΅ΡΡ, ΡΡΠΎ Π²ΡΠ΅ ΡΡΠΈ Π·Π°ΠΏΠΈΡΠΈ Π±Π»Π°Π³ΠΎΠΏΠΎΠ»ΡΡΠ½ΠΎ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Ρ:
>>> Book.query.all() [<Book ΠΡΠ΅ΡΡΡΠΏΠ»Π΅Π½ΠΈΠ΅ ΠΈ Π½Π°ΠΊΠ°Π·Π°Π½ΠΈΠ΅>, <Book ΠΠΎΡ>, <Book ΠΠ°ΡΡΠ΅Ρ ΠΈ ΠΠ°ΡΠ³Π°ΡΠΈΡΠ°>]
Π ΠΏΠ΅ΡΠ²ΡΠΉ, ΠΈ Π²ΡΠΎΡΠΎΠΉ ΡΠΏΠΎΡΠΎΠ±Ρ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΡ Π·Π°ΠΏΠΈΡΠ΅ΠΉ Π² Π±Π°Π·Ρ, ΠΎΡΠ΅Π²ΠΈΠ΄Π½ΠΎ, Π·Π°Π½ΠΈΠΌΠ°ΡΡ ΡΠ»ΠΈΡΠΊΠΎΠΌ ΠΌΠ½ΠΎΠ³ΠΎ Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ. ΠΠΎΡΡΠΎΠΌΡ ΠΏΡΠΎΡΠ΅ Π½Π°ΠΏΠΎΠ»Π½ΠΈΡΡ Π±Π°Π·Ρ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠ΅ΠΉ ΠΈΠ· ΡΠ°ΠΉΠ»Π° books.json:
>>> from reader.models import Book >>> from reader import db >>> import json >>> with open('books.json', encoding="utf8") as f: ... books_json = json.load(f) ... for book in books_json: ... book = Book(author=book['author'], description=book['description'], genr e=book['genre'], rating=book['rating'], title=book['title'], notes=book['notes'] ) ... db.session.add(book) ... db.session.commit()
Π ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ΅ Π² Π±Π°Π·Ρ Π±ΡΠ»ΠΎ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΎ 7 Π½ΠΎΠ²ΡΡ Π·Π°ΠΏΠΈΡΠ΅ΠΉ:
>>> Book.query.all() [<Book ΠΡΠ΅ΡΡΡΠΏΠ»Π΅Π½ΠΈΠ΅ ΠΈ Π½Π°ΠΊΠ°Π·Π°Π½ΠΈΠ΅>, <Book ΠΠΎΡ>, <Book ΠΠ°ΡΡΠ΅Ρ ΠΈ ΠΠ°ΡΠ³Π°ΡΠΈΡΠ°>, <Book Π ΠΈΠ·Π΅ΡΠΈ>, <Book ΠΠ°ΠΌΠΎΠΊ ΠΡΠΎΡΠ΄ΠΈ>, <Book ΠΠ±Π»Π°ΡΠ½ΡΠΉ Π°ΡΠ»Π°Ρ>, <Book ΠΠ°ΡΡΠ°ΠΆΠΈΡ>, <Book ΠΠΎΠ»ΠΎΠ² ΠΎΠΊΡΡΠΆΠ΅Π½ΠΈΠ΅>, <Book Π’Π΅ΡΡΠΎΡ>, <Book ΠΠΈΠ·Π΅ΡΠ΅ΡΠ΅>] >>> exit()
ΠΡΠ½ΠΎΠ²Π½ΡΠ΅ ΠΌΠ°ΡΡΡΡΡΡ ΠΈ ΡΠ°Π±Π»ΠΎΠ½Ρ
ΠΠΎΡΠ»Π΅ Π½Π°ΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ Π±Π°Π·Ρ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡΠΈΡΡΡΠΏΠ°ΡΡ ΠΊ ΡΡΠ½ΠΊΡΠΈΡΠΌ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΈ ΡΠ°Π±Π»ΠΎΠ½Π°ΠΌ Π΄Π»Ρ Π²ΡΠ²ΠΎΠ΄Π° ΠΊΠ°ΡΡΠΎΡΠ΅ΠΊ. Π‘Π½Π°ΡΠ°Π»Π° Π·Π°ΠΉΠΌΠ΅ΠΌΡΡ ΠΌΠ°ΡΡΡΡΡΠΎΠΌ Π΄Π»Ρ Π³Π»Π°Π²Π½ΠΎΠΉ ΡΡΡΠ°Π½ΠΈΡΡ. Π‘ΠΎΡ ΡΠ°Π½ΠΈΡΠ΅ ΡΡΠΎΡ ΠΊΠΎΠ΄ Π² ΡΠ°ΠΉΠ»Π΅ /reader/routes.py:
from reader import app from reader.models import Book @app.route('/') def index(): books = Book.query.all() return render_template('index.html', books=books) @app.route('/uploads/<filename>') def send_file(filename): return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
ΠΡΠΎΡΠ°Ρ ΡΡΠ½ΠΊΡΠΈΡ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΠ²Π°Π΅Ρ ΠΎΡΠΏΡΠ°Π²ΠΊΡ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠΉ (ΠΎΠ±Π»ΠΎΠΆΠ΅ΠΊ ΠΊΠ½ΠΈΠ³) ΠΈΠ· Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΠΈ /reader/uploads. ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ ΡΡΠΎΠΉ ΡΡΠ½ΠΊΡΠΈΠΈ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΠΎΡΠΎΠΌΡ, ΡΡΠΎ ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ Flask ΠΈΡΠ΅Ρ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ ΡΠΎΠ»ΡΠΊΠΎ Π² Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΠΈ static (ΠΈ Π²Π»ΠΎΠΆΠ΅Π½Π½ΡΡ Π² Π½Π΅Π΅ ΠΏΠ°ΠΏΠΊΠ°Ρ ). Π£ΠΊΠ°Π·Π°Π½ΠΈΠ΅ Π½Π° ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΡΡ ΠΏΠ°ΠΏΠΊΡ Π΄Π»Ρ Π·Π°Π³ΡΡΠ·ΠΊΠΈ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠΉ Π½ΡΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ Π² __init__.py:
UPLOAD_FOLDER = 'uploads' app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
Π’Π°ΠΊΠΆΠ΅ Π² __init__.py Π½Π°Π΄ΠΎ ΡΠ΄Π΅Π»Π°ΡΡ ΠΈΠΌΠΏΠΎΡΡ ΠΌΠΎΠ΄Π΅Π»ΠΈ ΠΈ ΠΌΠ°ΡΡΡΡΡΠΎΠ²:
from reader import routes, models
ΠΡΠΎΠΌΠ΅ ΡΠΎΠ³ΠΎ, Π΄Π»Ρ Π²ΡΠ²ΠΎΠ΄Π° Π·Π°ΠΏΠΈΡΠ΅ΠΉ Π½ΡΠΆΠ½Ρ Π΄Π²Π° ΡΠ°Π±Π»ΠΎΠ½Π° β base.html ΠΈ index.html, Π° ΡΠ°ΠΊΠΆΠ΅ ΡΠ°ΠΉΠ» ΡΠΎ ΡΡΠΈΠ»ΡΠΌΠΈ CSS. ΠΠΎΠΌΠ΅ΡΡΠΈΡΠ΅ ΠΈΡ , ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²Π΅Π½Π½ΠΎ, Π² ΠΏΠ°ΠΏΠΊΠΈ /reader/templates/ ΠΈ /reader/static/css. ΠΡΠ΅ Π³ΠΎΡΠΎΠ²ΠΎ β ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΏΡΡΠΊΠ°ΡΡ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅:
python run.py
ΠΠΎΠΊΠ° ΡΡΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π²ΡΠ³Π»ΡΠ΄ΠΈΡ ΡΠ°ΠΊ:
ΠΡΠ΅Π½ΠΊΠ° ΠΊΠ½ΠΈΠ³ΠΈ
ΠΠ»Ρ Π²ΡΠ²ΠΎΠ΄Π° ΠΎΡΠ΅Π½ΠΊΠΈ ΠΊΠ½ΠΈΠ³ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ ΠΏΡΠΎΡΡΠ΅ΠΉΡΠΈΠΉ ΠΊΠΎΠ΄ Π² ΡΠ°Π±Π»ΠΎΠ½Π΅, ΠΊΠΎΡΠΎΡΡΠΉ ΠΏΠ΅ΡΠ°ΡΠ°Π΅Ρ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ Π·Π²Π΅Π·Π΄ΠΎΡΠ΅ΠΊ, ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΠ΅Π΅ ΠΎΡΠ΅Π½ΠΊΠ΅ Π² Π±Π°Π·Π΅:
{% set stars = book.rating | int %} {% for n in range(stars) %} <span class="fa fa-star checked" style="color:orange"></span> {% endfor %}
ΠΠ΅ΡΡ ΠΊΠΎΠ΄, ΡΠΎΠ·Π΄Π°Π½Π½ΡΠΉ Π½Π° ΡΡΠΎΠΌ ΡΡΠ°ΠΏΠ΅ β Π·Π΄Π΅ΡΡ.
ΠΡΠΎΡΠΎΠΉ ΡΡΠ°ΠΏ
Π§ΡΠΎΠ±Ρ ΠΏΡΠΎΡΠΌΠ°ΡΡΠΈΠ²Π°ΡΡ ΠΊΠ°ΡΡΠΎΡΠΊΠΈ ΠΊΠ½ΠΈΠ³, Π½ΡΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°ΡΡ Π½ΠΎΠ²ΡΠΉ ΡΠ°Π±Π»ΠΎΠ½ book.html, ΠΏΠΎΠΌΠ΅ΡΡΠΈΡΡ ΡΠ°ΠΉΠ» illustration.jpg Π² /reader/uploads/ ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΡΠΉ ΠΌΠ°ΡΡΡΡΡ Π² routes.py:
@app.route('/<int:book_id>/') def book(book_id): book = Book.query.get_or_404(book_id) return render_template('book.html', book=book)
ΠΡΠΎΠΌΠ΅ ΡΠΎΠ³ΠΎ, Π½ΡΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΡΡ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΡΡ ΡΡΡΠ»ΠΊΡ Π² ΡΠ°Π±Π»ΠΎΠ½ index.html:
<a href="{{ url_for('book', book_id=book.id)}}">ΠΠΎΠ΄ΡΠΎΠ±Π½Π΅Π΅</a>
ΠΠ°ΡΡΠΎΡΠΊΠ° ΠΊΠ½ΠΈΠ³ΠΈ Π²ΡΠ³Π»ΡΠ΄ΠΈΡ ΡΠ°ΠΊ:
Π€ΠΈΠ»ΡΡΡΡ ΠΈ ΡΠ°Π±ΠΎΡΠ° Ρ ΠΎΠ±ΡΠ΅ΠΊΡΠ°ΠΌΠΈ Π΄Π°Π½Π½ΡΡ
SQLAlchemy Π΄Π΅Π»Π°Π΅Ρ ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΡ Π΄Π°Π½Π½ΡΡ ΠΏΡΠΎΡΡΠ΅ΠΉΡΠΈΠΌ Π΄Π΅Π»ΠΎΠΌ. Π ΠΏΡΠΈΠΌΠ΅ΡΡ, Π²ΠΎΡ ΡΠ°ΠΊ ΠΌΠΎΠΆΠ½ΠΎ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΡΡ Π²ΡΠ²ΠΎΠ΄ ΠΊΠ°ΡΡΠΎΡΠ΅ΠΊ ΠΊΠ½ΠΈΠ³ Π² ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΠΈΠΈ Ρ Π΄Π°ΡΠΎΠΉ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΡ:
books = Book.query.order_by(Book.created_at.desc()).all()
Π’Π°ΠΊ ΠΆΠ΅ ΠΏΡΠΎΡΡΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡΠΎΠ±ΡΠ°ΡΡ ΠΊΠ½ΠΈΠ³ΠΈ ΠΏΠΎ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠΌΡ Π°Π²ΡΠΎΡΡ ΠΈΠ»ΠΈ ΠΆΠ°Π½ΡΡ. Π‘Π΄Π΅Π»Π°Π΅ΠΌ Π²ΡΠ±ΠΎΡΠΊΡ ΠΏΠΎ ΠΆΠ°Π½ΡΡ Β«ΡΡΠΈΠ»Π»Π΅ΡΒ»:
@app.route('/thrillers/') def thrillers(): books = Book.query.filter(Book.genre == 'ΡΡΠΈΠ»Π»Π΅Ρ').all() return render_template('thrillers.html', books=books)
Π ΠΏΠΎ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΠΎΠΉ ΠΎΡΠ΅Π½ΠΊΠ΅ 5:
@app.route('/best/') def best(): books = Book.query.filter(Book.rating > 4).all() return render_template('best.html', books=books)
ΠΡΡΠ°Π²ΡΡΠ΅ ΡΡΠΈ ΡΡΠ½ΠΊΡΠΈΠΈ Π² /readers/routes.py ΠΈ Π΄ΠΎΠ±Π°Π²ΡΡΠ΅ Π² ΠΏΠ°ΠΏΠΊΡ templates ΡΠ°Π±Π»ΠΎΠ½Ρ Π΄Π»Ρ Π²ΡΠ²ΠΎΠ΄Π° ΡΡΠΈΠ»Π»Π΅ΡΠΎΠ² ΠΈ Π»ΡΡΡΠΈΡ ΡΠΈΠ»ΡΠΌΠΎΠ². Π ΡΠ°Π±Π»ΠΎΠ½ base.html Π½ΡΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ ΡΡΡΠ»ΠΊΠΈ Π΄Π»Ρ ΠΊΠ½ΠΎΠΏΠΎΠΊ Π² Π²Π΅ΡΡ Π½Π΅ΠΌ ΠΌΠ΅Π½Ρ:
<a class="btn btn-info mr-2" href="{{ url_for('thrillers') }}" role="button">Π’ΡΠΈΠ»Π»Π΅ΡΡ</a> <a class="btn btn-info mr-2" href="{{ url_for('best') }}" role="button">ΠΡΡΡΠΈΠ΅</a>
Π’Π΅ΠΏΠ΅ΡΡ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡΡΠ΅ΡΡ Π½Π° Π²ΡΠ±ΠΎΡΠΊΡ ΠΏΠΎ ΡΡΠΈΠ»Π»Π΅ΡΠ°ΠΌ:
Π ΠΏΠΎ Π»ΡΡΡΠΈΠΌ ΠΊΠ½ΠΈΠ³Π°ΠΌ:
ΠΠ±ΡΠ°ΡΠΈΡΠ΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅: ΡΠ°Π±Π»ΠΎΠ½ΠΈΠ·Π°ΡΠΎΡΡ Jinja2 Π½Π΅ ΡΡΠ΅Π±ΡΡΡΡΡ Π½ΠΈΠΊΠ°ΠΊΠΈΠ΅ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½ΡΠ΅ ΡΡ ΠΈΡΡΠ΅Π½ΠΈΡ Π΄Π»Ρ ΡΠ°Π±ΠΎΡΡ Ρ ΠΎΠ±ΡΠ΅ΠΊΡΠΎΠΌ Π΄Π°Π½Π½ΡΡ , ΡΠΎΠ·Π΄Π°Π½Π½ΡΠΌ Π² ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ΅ ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΠΈ: Π·Π°Π³ΡΡΠ·ΠΊΠ° ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠΉ ΠΈ ΠΏΠ΅ΡΠ΅Π½Π°ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ Π½Π° ΠΊΠ°ΡΡΠΎΡΠΊΡ ΠΊΠ½ΠΈΠ³ΠΈ Π½Π΅ Π²ΡΠ·ΡΠ²Π°ΡΡ Π½ΠΈΠΊΠ°ΠΊΠΈΡ ΠΏΡΠΎΠ±Π»Π΅ΠΌ:
{{ url_for('send_file', filename=book.cover) }} {{ url_for('book', book_id=book.id)}}
ΠΡΠΎΠΌΠ΅ ΡΠΎΠ³ΠΎ, ΠΊ Π°ΡΡΠΈΠ±ΡΡΠ°ΠΌ ΠΎΠ±ΡΠ΅ΠΊΡΠ° Π΄Π°Π½Π½ΡΡ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡΠΈΠΌΠ΅Π½ΡΡΡ ΡΠΈΠ»ΡΡΡΡ Jinja2. ΠΡΠΎΡ ΡΠΈΠ»ΡΡΡ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΠ²Π°Π΅Ρ Π²ΡΠ²ΠΎΠ΄ Π΄Π°ΡΡ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΡ ΠΊΠ½ΠΈΠ³ΠΈ Π² ΡΠΎΡΠΌΠ°ΡΠ΅ Π΄Π΅Π½Ρ-ΠΌΠ΅ΡΡΡ-Π³ΠΎΠ΄:
{{ book.created_at.strftime('%d-%m-%Y') }}
ΠΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ ΠΆΠ΅ (Π±Π΅Π· ΡΠΈΠ»ΡΡΡΠ°) Π΄Π°ΡΠ° Π±ΡΠ΄Π΅Ρ Π²ΡΠ³Π»ΡΠ΄Π΅ΡΡ ΡΠ°ΠΊ:
2022-06-25 14:17:53
ΠΠ°Π³ΠΈΠ½Π°ΡΠΈΡ
ΠΠΎΡΠ»Π΅Π΄Π½Π΅Π΅, ΡΡΠΎ ΠΌΡ ΡΠ΄Π΅Π»Π°Π΅ΠΌ Π½Π° ΡΡΠΎΠΌ ΡΡΠ°ΠΏΠ΅ β ΠΏΠΎΡΡΡΠ°Π½ΠΈΡΠ½ΡΠΉ Π²ΡΠ²ΠΎΠ΄ ΠΊΠ°ΡΡΠΎΡΠ΅ΠΊ. Π Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°ΡΡ ΠΏΠ°Π³ΠΈΠ½Π°ΡΠΈΡ Ρ ΠΏΠΎΠΌΠΎΡΡΡ SQLAlchemy Π΄Π΅ΠΉΡΡΠ²ΠΈΡΠ΅Π»ΡΠ½ΠΎ ΠΏΡΠΎΡΡΠΎ. Π Π½Π°ΡΠ°Π»Π΅ ΡΠ°ΠΉΠ»Π° /reader/routes.py Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ ΠΈΠΌΠΏΠΎΡΡ request
, Π° Π·Π°ΡΠ΅ΠΌ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡΡ ΡΡΠ½ΠΊΡΠΈΡ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»Π΅Π½ΠΈΡ Π΄Π»Ρ index
ΡΠ°ΠΊΠΈΠΌ ΠΎΠ±ΡΠ°Π·ΠΎΠΌ:
@app.route('/') def index(): page = request.args.get('page', 1, type=int) books = Book.query.order_by(Book.created_at.desc()).paginate(page=page, per_page=4) return render_template('index.html', books=books)
Π ΡΠ°Π±Π»ΠΎΠ½ index.html Π½ΡΠΆΠ½ΠΎ Π²Π½Π΅ΡΡΠΈ Π²ΡΠ΅Π³ΠΎ 2 Π΄ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ β ΠΈΠ·ΠΌΠ΅Π½ΠΈΡΡ books
Π½Π° books.items
:
{% for book in books.items %}
Π Π΄ΠΎΠ±Π°Π²ΠΈΡΡ Π²ΡΠ²ΠΎΠ΄ Π½ΠΎΠΌΠ΅ΡΠΎΠ² ΡΡΡΠ°Π½ΠΈΡ Π² ΡΠ°ΠΌΠΎΠΌ Π½ΠΈΠ·Ρ:
{% for page_num in books.iter_pages(left_edge=1, right_edge=1, left_current=1, right_current=2) %} {% if page_num %} {% if books.page == page_num %} <a class="btn btn-info mb-4" href="{{ url_for('index', page=page_num) }}">{{ page_num }}</a> {% else %} <a class="btn btn-outline-info mb-4" href="{{ url_for('index', page=page_num) }}">{{ page_num }}</a> {% endif %} {% else %} ... {% endif %} {% endfor %}
ΠΡΠ΅ Π³ΠΎΡΠΎΠ²ΠΎ:
Π ΡΠ°Π±Π»ΠΎΠ½Ρ best.html ΠΈ thrillers.html ΡΠΎΠΆΠ΅ Π½ΡΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ ΠΏΠ°Π³ΠΈΠ½Π°ΡΠΈΡ. ΠΠ»Ρ ΡΡΠΎΠ³ΠΎ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ Π²Π½Π΅ΡΡΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ ΡΠ½Π°ΡΠ°Π»Π° Π² ΠΈΡ ΡΡΠ½ΠΊΡΠΈΠΈ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»Π΅Π½ΠΈΡ, Π° ΠΏΠΎΡΠΎΠΌ ΠΈ Π² ΡΠ°ΠΌΠΈ ΡΠ°Π±Π»ΠΎΠ½Ρ.
Π€ΡΠ½ΠΊΡΠΈΡ Π΄Π»Ρ best.html Π²ΡΠ³Π»ΡΠ΄ΠΈΡ ΡΠ°ΠΊ:
@app.route('/best/') def best(): page = request.args.get('page', 1, type=int) books = Book.query.filter(Book.rating > 4).paginate(page=page, per_page=4) return render_template('best.html', books=books)
Π Π΄Π»Ρ thrillers.html β ΡΠ°ΠΊ:
@app.route('/thrillers/') def thrillers(): page = request.args.get('page', 1, type=int) books = Book.query.filter(Book.genre == 'ΡΡΠΈΠ»Π»Π΅Ρ').paginate(page=page, per_page=4) return render_template('thrillers.html', books=books)
ΠΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ Π² ΡΠ°ΠΌΠΈΡ
ΡΠ°Π±Π»ΠΎΠ½Π°Ρ
Π°Π½Π°Π»ΠΎΠ³ΠΈΡΠ½Ρ ΡΠ΅ΠΌ, ΡΡΠΎ ΠΌΡ ΡΠΆΠ΅ ΡΠ΄Π΅Π»Π°Π»ΠΈ Π² index.html β Π½ΡΠΆΠ½ΠΎ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡΡ books
Π½Π° books.items
ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΡΡ Π±Π»ΠΎΠΊ Π²ΡΠ²ΠΎΠ΄Π° ΠΏΠ°Π³ΠΈΠ½Π°ΡΠΈΠΈ:
{% for page_num in books.iter_pages(left_edge=1, right_edge=1, left_current=1, right_current=2) %} {% if page_num %} {% if books.page == page_num %} <a class="btn btn-info mb-4" href="{{ url_for('thrillers', page=page_num) }}">{{ page_num }}</a> {% else %} <a class="btn btn-outline-info mb-4" href="{{ url_for('thrillers', page=page_num) }}">{{ page_num }}</a> {% endif %} {% else %} ... {% endif %} {% endfor %}
ΠΠ΅ΡΡ ΠΊΠΎΠ΄ ΠΈ ΡΠ΅ΡΡΠΎΠ²ΡΠΉ ΠΊΠΎΠ½ΡΠ΅Π½Ρ, ΡΠΎΠ·Π΄Π°Π½Π½ΡΠ΅ Π½Π° ΡΡΠΎΠΌ ΡΡΠ°ΠΏΠ΅, ΠΌΠΎΠΆΠ½ΠΎ Π²Π·ΡΡΡ Π·Π΄Π΅ΡΡ. Π ΡΠ»Π΅Π΄ΡΡΡΠ΅ΠΉ, Π·Π°ΠΊΠ»ΡΡΠΈΡΠ΅Π»ΡΠ½ΠΎΠΉ ΡΠ°ΡΡΠΈ ΠΌΡ ΡΠ΅Π°Π»ΠΈΠ·ΡΠ΅ΠΌ Π·Π°Π³ΡΡΠ·ΠΊΡ ΠΈ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠ΅ ΡΠΆΠ°ΡΠΈΠ΅ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠΉ, ΡΠ΄Π΅Π»Π°Π΅ΠΌ CRUD-ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡ ΡΠΊΡΠΏΠΎΡΡΠ° ΠΊΠΎΠ½ΡΠ΅Π½ΡΠ° Π² json-ΡΠΎΡΠΌΠ°ΡΠ΅.
ΠΠ°ΡΠ΅ΡΠΈΠ°Π»Ρ ΠΏΠΎ ΡΠ΅ΠΌΠ΅
- ππ₯€ Flask Π·Π° ΡΠ°Ρ. Π§Π°ΡΡΡ 1: ΡΠΎΠ·Π΄Π°Π΅ΠΌ Π°Π΄Π°ΠΏΡΠΈΠ²Π½ΡΠΉ ΡΠ°ΠΉΡ Π΄Π»Ρ GitHub Pages
- ππ₯€ Flask Π·Π° ΡΠ°Ρ. Π§Π°ΡΡΡ 2: Π·Π°Π²Π΅ΡΡΠ°Π΅ΠΌ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΡ ΠΈ ΡΠ°Π·ΠΌΠ΅ΡΠ°Π΅ΠΌ ΡΠ°ΠΉΡ Π½Π° GitHub Pages
- πποΈ Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ Π΄Π°Π½Π½ΡΠΌΠΈ Ρ ΠΏΠΎΠΌΠΎΡΡΡ Python, SQLite ΠΈ SQLAlchemy