πŸπŸ“š Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ Π°Π½Π°Π»ΠΎΠ³ LiveLib.ru Π½Π° Flask. Π§Π°ΡΡ‚ΡŒ 1: основы Ρ€Π°Π±ΠΎΡ‚Ρ‹ с SQLAlchemy

Π˜Π·ΡƒΡ‡Π°Π΅ΠΌ взаимодСйствиС Flask с SQLAlchemy ΠΈ WTForms, создавая Π²Π΅Π±-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ β€” Π»Π°ΠΉΡ‚-Π²Π΅Ρ€ΡΠΈΡŽ сСрвиса LiveLib.ru β€” для хранСния ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΎ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½Π½Ρ‹Ρ… ΠΊΠ½ΠΈΠ³Π°Ρ…. Π Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌ CRUD, ΠΏΠ°Π³ΠΈΠ½Π°Ρ†ΠΈΡŽ, Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Ρ‹ ΠΈ экспорт Π΄Π°Π½Π½Ρ‹Ρ….

Π›ΡŽΠ±ΠΎΠ΅ Π±ΠΎΠ»Π΅Π΅-ΠΌΠ΅Π½Π΅Π΅ ΡΠ΅Ρ€ΡŒΠ΅Π·Π½ΠΎΠ΅ Π²Π΅Π±-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ… для хранСния ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½ΠΎΠΉ ΠΎΡ‚ Ρ„Ρ€ΠΎΠ½Ρ‚Π΅Π½Π΄Π° ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ. Для упрощСния взаимодСйствия Flask-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ с Π±Π°Π·ΠΎΠΉ Ρ‡Π°Ρ‰Π΅ всСго ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ SQLAlchemy, Π° для получСния ΠΈ Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΠΈ Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ – Ρ„ΠΎΡ€ΠΌΡ‹ WTForms.

ΠžΠ±Π·ΠΎΡ€ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°

Π­Ρ‚ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ для вСдСния списка ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π½Π½Ρ‹Ρ… ΠΊΠ½ΠΈΠ³. Для ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΊΠ½ΠΈΠ³ΠΈ создаСтся ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Π°Ρ ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΠ° с постСром, ΠΈΠΌΠ΅Π½Π΅ΠΌ Π°Π²Ρ‚ΠΎΡ€Π°, Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ ΠΆΠ°Π½Ρ€Π°, описаниСм ΡΡŽΠΆΠ΅Ρ‚Π°, ΠΎΡ†Π΅Π½ΠΊΠΎΠΉ ΠΈ примСчаниями. ΠšΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΠΈ ΠΌΠΎΠΆΠ½ΠΎ Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΈ ΡƒΠ΄Π°Π»ΡΡ‚ΡŒ. Π’Π΅ΡΡŒ ΠΊΠΎΠ΄ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° находится здСсь.

Π“ΠΎΡ‚ΠΎΠ²ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ AvidReader

Π§Ρ‚ΠΎ ΠΌΡ‹ ΠΈΠ·ΡƒΡ‡ΠΈΠΌ Π² процСссС Ρ€Π°Π±ΠΎΡ‚Ρ‹

  1. Π£Π·Π½Π°Π΅ΠΌ, ΠΊΠ°ΠΊ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ Π·Π°ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ Π΅Π΅ тСстовыми Π΄Π°Π½Π½Ρ‹ΠΌΠΈ ΠΈΠ· json-Ρ„Π°ΠΉΠ»Π°.
  2. Π Π΅Π°Π»ΠΈΠ·ΡƒΠ΅ΠΌ ΠΏΠ°Π³ΠΈΠ½Π°Ρ†ΠΈΡŽ ΠΈ Π½Π°Π±ΠΎΡ€ CRUD-ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΠ°ΠΌΠΈ ΠΊΠ½ΠΈΠ³.
  3. НапишСм ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ Π²Π°Π»ΠΈΠ΄Π°Ρ‚ΠΎΡ€ ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π΅ΠΌ ΠΎΡˆΠΈΠ±ΠΊΡƒ IntegrityError.
  4. Π‘Π΄Π΅Π»Π°Π΅ΠΌ нСсколько Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΠΎΠ² для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹Ρ… ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΉ Π΄Π°Π½Π½Ρ‹Ρ….
  5. Π”ΠΎΠ±Π°Π²ΠΈΠΌ Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΡ€ΠΎΡΡ‚ΡƒΡŽ (Π±Π΅Π· JS) систСму ΠΎΡ†Π΅Π½ΠΊΠΈ ΠΊΠ½ΠΈΠ³.
  6. Рассмотрим способы Ρ€Π°Π±ΠΎΡ‚Ρ‹ с ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°ΠΌΠΈ Π΄Π°Π½Π½Ρ‹Ρ… Π² ΡˆΠ°Π±Π»ΠΎΠ½ΠΈΠ·Π°Ρ‚ΠΎΡ€Π΅ 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:

/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:

Β /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:

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:

/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:

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>

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° Π²Ρ‹Π±ΠΎΡ€ΠΊΡƒ ΠΏΠΎ Ρ‚Ρ€ΠΈΠ»Π»Π΅Ρ€Π°ΠΌ:

Π€ΠΈΠ»ΡŒΡ‚Ρ€ ΠΏΠΎ Ρ‚Ρ€ΠΈΠ»Π»Π΅Ρ€Π°ΠΌ

И ΠΏΠΎ Π»ΡƒΡ‡ΡˆΠΈΠΌ ΠΊΠ½ΠΈΠ³Π°ΠΌ:

Книги с ΠΎΡ†Π΅Π½ΠΊΠΎΠΉ 5

ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅: ΡˆΠ°Π±Π»ΠΎΠ½ΠΈΠ·Π°Ρ‚ΠΎΡ€Ρƒ 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 Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ:

/reader/routes.py
@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:

index.htmlΒ 
{% for book in books.items %}

И Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π²Ρ‹Π²ΠΎΠ΄ Π½ΠΎΠΌΠ΅Ρ€ΠΎΠ² страниц Π² самом Π½ΠΈΠ·Ρƒ:

index.htmlΒ 
{% 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 выглядит Ρ‚Π°ΠΊ:

/reader/routes.py
@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 – Ρ‚Π°ΠΊ:

/reader/routes.py
@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 ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π±Π»ΠΎΠΊ Π²Ρ‹Π²ΠΎΠ΄Π° ΠΏΠ°Π³ΠΈΠ½Π°Ρ†ΠΈΠΈ:

best.html ΠΈ thrillers.htmlΒ 
{% 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-Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅.

ΠœΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹ ΠΏΠΎ Ρ‚Π΅ΠΌΠ΅

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•

admin
11 дСкабря 2018

ООП Π½Π° Python: ΠΊΠΎΠ½Ρ†Π΅ΠΏΡ†ΠΈΠΈ, ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Python допускаСт Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ»ΠΎΠ³ΠΈΠΈ, Π½ΠΎ Π² Π΅Π³ΠΎ основС...
admin
28 июня 2018

3 самых Π²Π°ΠΆΠ½Ρ‹Ρ… сфСры примСнСния Python: возмоТности языка

БущСствуСт мноТСство областСй примСнСния Python, Π½ΠΎ Π² Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΎΠ½ особСнно...
admin
13 фСвраля 2017

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Python: ΠΎΡ‚ Π½ΠΎΠ²ΠΈΡ‡ΠΊΠ° Π΄ΠΎ профСссионала

Пошаговая инструкция для всСх, ΠΊΡ‚ΠΎ Ρ…ΠΎΡ‡Π΅Ρ‚ ΠΈΠ·ΡƒΡ‡ΠΈΡ‚ΡŒΒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Python...