1
0
Fork 0
mirror of https://github.com/EDeev/web-dev.git synced 2026-10-08 04:59:37 +03:00

Compare commits

..

No commits in common. "9a23fc52e0ac7c6b59db1b842b22ed048f26c668" and "81b91a8c2bedc9a74818298238aaeb38b09bcf97" have entirely different histories.

63 changed files with 158 additions and 175 deletions

View file

@ -1,42 +0,0 @@
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
lint-and-homework:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install ruff==0.14.0 pytest==8.4.2
- name: Ruff (синтаксис и ошибки)
run: ruff check --select E9,F .
- name: Тесты домашних заданий
run: |
cd hws/hw-1 && pytest -q test.py && cd ../..
cd hws/hw-2 && pytest -q test.py
apps:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
app: [labs/lab-1/app, labs/lab-2/app, labs/lab-3/app, labs/lab-4/app, labs/lab-5/app, labs/lab-6/app, ex]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Зависимости
run: |
req=$(dirname ${{ matrix.app }})/requirements.txt
[ -f ${{ matrix.app }}/requirements.txt ] && req=${{ matrix.app }}/requirements.txt
pip install -r $req
- name: Приложение импортируется
working-directory: ${{ matrix.app }}
run: python -c "import app"

12
.gitignore vendored
View file

@ -1,12 +0,0 @@
__pycache__/
*.py[cod]
.venv/
venv/
.env
*.db
instance/
ex/app/static/uploads/*
!ex/app/static/uploads/.gitkeep
labs/lab-6/app/media/images/*
!labs/lab-6/app/media/images/.gitkeep
.pytest_cache/

View file

@ -1,56 +0,0 @@
# Web Development
[Русский](README.md) · **English**
[![CI](https://github.com/EDeev/web-dev/actions/workflows/ci.yml/badge.svg)](https://github.com/EDeev/web-dev/actions/workflows/ci.yml)
Labs, homework and the exam project for the "Web Development" course at Moscow Polytechnic University:
six Flask apps, 37 Python exercises with tests, and an online library.
**Status:** coursework (Moscow Polytech, group 241-327, 2025/26), completed, archived ·
labs at [web-dev.deev.space](https://web-dev.deev.space), exam at [ex-web.deev.su](https://ex-web.deev.su)
![Exam: online library](docs/screenshots/exam.png)
**Stack:** Python · Flask · Jinja2 · Flask-Login · Flask-SQLAlchemy · Flask-Migrate · SQLite/MySQL · Bootstrap 5 · pytest
| Folder | Contents |
|---|---|
| `labs/lab-1` | blog post template with Flask and Jinja2 |
| `labs/lab-2` | request data: parameters, headers, cookies, forms, phone number validation |
| `labs/lab-3` | sign-in with Flask-Login, protected pages, sessions |
| `labs/lab-4` | user accounts CRUD: database, validation, password hashing |
| `labs/lab-5` | roles and permissions, visit log, reports with CSV export |
| `labs/lab-6` | education portal: course reviews, ratings, pagination, filters |
| `hws/hw-1`, `hws/hw-2` | 37 Python exercises (algorithms, files, decorators, generators, OOP) and 241 tests |
| `ex` | exam: book catalog with search, reviews and roles (admin, moderator, user) |
## Running
```bash
cd labs/lab-3 && pip install -r requirements.txt
cd app && FLASK_DEBUG=1 python app.py
cd ex && pip install -r requirements.txt
python db/db_seed.py # database, roles and test users (passwords are printed)
python run.py
```
`SECRET_KEY` and `FLASK_DEBUG` come from environment variables. Homework tests:
`cd hws/hw-1 && pytest test.py`.
## License
Coursework (Web Development, Moscow Polytechnic University, 2025/26). The code is open for study; there
is no separate license.
## Author
**Egor Deev** — [GitHub](https://github.com/EDeev) · [Telegram](https://t.me/DeevEgor) · [egor@deev.space](mailto:egor@deev.space)
---
<div align="center">
<sub>⭐ If you find this project useful, give it a star on GitHub!</sub>
<p><sub>Made with ❤️ — <a href="https://deev.space">deev.space</a></sub></p>
</div>

106
README.md
View file

@ -1,56 +1,90 @@
# Веб-разработка # Курс Веб-разработки
[![Python](https://img.shields.io/badge/Python-3776AB?style=flat&logo=python&logoColor=white)](https://www.python.org/)
[![Flask](https://img.shields.io/badge/Flask-000000?style=flat&logo=flask&logoColor=white)](https://flask.palletsprojects.com/)
[![SQLite](https://img.shields.io/badge/SQLite-003B57?style=flat&logo=sqlite&logoColor=white)](https://www.sqlite.org/)
[![Bootstrap](https://img.shields.io/badge/Bootstrap-7952B3?style=flat&logo=bootstrap&logoColor=white)](https://getbootstrap.com/)
**Русский** · [English](README.en.md) Репозиторий содержит выполненные лабораторные работы и домашние задания по курсу "Веб-разработка" в Московском Политехническом университете.
[![CI](https://github.com/EDeev/web-dev/actions/workflows/ci.yml/badge.svg)](https://github.com/EDeev/web-dev/actions/workflows/ci.yml) **Веб-сайт проекта:** [web-dev.deev.space](https://web-dev.deev.space)
Лабораторные, домашние задания и экзаменационный проект по курсу «Веб-разработка» в Московском **Автор:** Деев Егор Викторович, группа 241-327
Политехе: шесть Flask-приложений, 37 задач на Python с тестами и электронная библиотека.
**Статус:** учебный проект (Московский Политех, группа 241-327, 2025/26), завершён, в архиве · ## Структура репозитория
лабораторные — [web-dev.deev.space](https://web-dev.deev.space), экзамен — [ex-web.deev.su](https://ex-web.deev.su)
![Экзамен: электронная библиотека](docs/screenshots/exam.png) ### Лабораторные работы
**Стек:** Python · Flask · Jinja2 · Flask-Login · Flask-SQLAlchemy · Flask-Migrate · SQLite/MySQL · Bootstrap 5 · pytest #### [Лабораторная работа №1](https://web-dev.deev.space/lab1)
Создание шаблона для отображения записи блога с использованием Flask и Jinja2. Реализация базовой структуры приложения, шаблонов для отображения постов и комментариев.
| Папка | Что внутри | **Стек:** Flask, Jinja2, Bootstrap 5
|---|---|
| `labs/lab-1` | шаблон записи блога на Flask и Jinja2 |
| `labs/lab-2` | данные запроса: параметры, заголовки, cookies, формы, проверка телефона |
| `labs/lab-3` | вход через Flask-Login, защищённые страницы, сессии |
| `labs/lab-4` | CRUD учётных записей: база, валидация, хеширование паролей |
| `labs/lab-5` | роли и права, журнал посещений, отчёты с экспортом в CSV |
| `labs/lab-6` | образовательный портал: отзывы к курсам, рейтинг, пагинация, фильтры |
| `hws/hw-1`, `hws/hw-2` | 37 задач на Python (алгоритмы, файлы, декораторы, генераторы, ООП) и 241 тест |
| `ex` | экзамен: каталог книг с поиском, рецензиями и ролями (администратор, модератор, пользователь) |
## Запуск #### [Лабораторная работа №2](https://web-dev.deev.space/lab2)
Работа с данными запроса. Реализация обработки параметров URL, заголовков, cookies и форм. Валидация номера телефона на стороне сервера.
```bash **Стек:** Flask, регулярные выражения
cd labs/lab-3 && pip install -r requirements.txt
cd app && FLASK_DEBUG=1 python app.py
cd ex && pip install -r requirements.txt #### [Лабораторная работа №3](https://web-dev.deev.space/lab3)
python db/db_seed.py # база, роли и тестовые пользователи (пароли выводятся в консоль) Реализация аутентификации пользователей с использованием Flask-Login. Создание системы входа, защищенных страниц и управления сессиями.
python run.py
```
`SECRET_KEY` и `FLASK_DEBUG` задаются переменными окружения. Тесты домашних заданий: **Стек:** Flask, Flask-Login, session management
`cd hws/hw-1 && pytest test.py`.
## Лицензия #### [Лабораторная работа №4](https://web-dev.deev.space/lab4)
Разработка CRUD-приложения для управления учетными записями пользователей. Работа с базой данных, валидация данных, хеширование паролей.
Учебный проект (Веб-разработка, Московский Политех, 2025/26). Код открыт для изучения, отдельной **Стек:** Flask, Flask-SQLAlchemy, MySQL, bcrypt
лицензии нет.
## Автор #### [Лабораторная работа №5](https://web-dev.deev.space/lab5)
Авторизация пользователей и формирование статистических отчетов. Реализация системы ролей, декораторов проверки прав, журнала посещений и экспорта в CSV.
**Деев Егор Викторович** — [GitHub](https://github.com/EDeev) · [Telegram](https://t.me/DeevEgor) · [egor@deev.space](mailto:egor@deev.space) **Стек:** Flask, Flask-Login, Blueprints, CSV export
#### [Лабораторная работа №6](https://web-dev.deev.space/lab6)
Доработка образовательного портала: добавление системы отзывов к курсам, рейтинговой системы, пагинации и фильтрации.
**Стек:** Flask, Flask-SQLAlchemy, Flask-Migrate, MySQL
### Домашние задания
#### [Домашнее задание №1](https://github.com/EDeev/web-dev/tree/main/hws/hw-1)
Решение 20 задач на Python: базовые алгоритмы, работа с файлами, регулярные выражения, структуры данных. Покрытие тестами с использованием pytest (60+ тестов).
**Темы:** базовый синтаксис Python, работа с файлами, алгоритмы, структуры данных
#### [Домашнее задание №2](https://github.com/EDeev/web-dev/tree/main/hws/hw-2)
Решение 17 задач на Python: функции, декораторы, генераторы, ООП, работа с файловой системой. Покрытие тестами с использованием pytest (60+ тестов).
**Темы:** функции, декораторы, генераторы, ООП, аргументы командной строки, работа с файлами
## План развития
- Развертывание всех лабораторных работ на хостинге
- Добавление CI/CD pipeline для автоматического тестирования
- Документирование API endpoints
- Рефакторинг кода с применением паттернов проектирования
- Добавление Docker-контейнеризации для упрощения развертывания
## Технологический стек
- **Backend:** Python, Flask, Flask-Login, Flask-SQLAlchemy, Flask-Migrate
- **Frontend:** HTML5, CSS3, Bootstrap 5, Jinja2
- **База данных:** MySQL, SQLite
- **Тестирование:** pytest
- **Деплой:** NGINX, Unit
## Контакты
- Email: egor@deev.space
- Telegram: @Egor_Deev
- GitHub: @EDeev
## Лицензия и использование
Данный репозиторий создан в образовательных целях. Код доступен для изучения и адаптации без указания авторства.
--- ---
<div align="center"> <div align="center">
<sub>⭐ Если проект оказался полезным, поставьте звёздочку на GitHub!</sub> <sub>⭐ Если проект оказался полезным, поставьте звездочку на GitHub!</sub>
<p><sub>Сделано с ❤️ — <a href="https://deev.space">deev.space</a></sub></p> <p><sub>Создано с ❤️ от вашего дорогого - <a href="https://deev.space">deev.space</a> ©</sub></p>
</div> </div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

2
ex/README.md Normal file
View file

@ -0,0 +1,2 @@
## Сайт развёрнут на домене https://ex-web.deev.su
Тестовые аккаунты (администратор, модератор, пользователь) создаёт `ex/db/db_seed.py`; пароли задаются переменными `SEED_ADMIN_PASSWORD`, `SEED_MODER_PASSWORD`, `SEED_USER_PASSWORD` или генерируются при запуске и выводятся в консоль.

View file

@ -9,7 +9,7 @@ import bleach
import markdown import markdown
app = Flask(__name__) app = Flask(__name__)
app.secret_key = os.environ.get('SECRET_KEY', 'exam-secret-key-2026') app.secret_key = 'exam-secret-key-2026'
_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) _ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
app.config['UPLOAD_FOLDER'] = os.path.join(os.path.dirname(__file__), 'static', 'uploads') app.config['UPLOAD_FOLDER'] = os.path.join(os.path.dirname(__file__), 'static', 'uploads')

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="280">
<rect width="200" height="280" fill="#1cc88a"/>
<text x="100" y="155" font-family="Arial" font-size="48" font-weight="bold"
fill="white" text-anchor="middle">КР</text>
</svg>

After

Width:  |  Height:  |  Size: 254 B

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="280">
<rect width="200" height="280" fill="#858796"/>
<text x="100" y="155" font-family="Arial" font-size="48" font-weight="bold"
fill="white" text-anchor="middle">ГР</text>
</svg>

After

Width:  |  Height:  |  Size: 254 B

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="280">
<rect width="200" height="280" fill="#e74a3b"/>
<text x="100" y="155" font-family="Arial" font-size="48" font-weight="bold"
fill="white" text-anchor="middle">ВО</text>
</svg>

After

Width:  |  Height:  |  Size: 254 B

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="280">
<rect width="200" height="280" fill="#f6c23e"/>
<text x="100" y="155" font-family="Arial" font-size="48" font-weight="bold"
fill="white" text-anchor="middle">АВ</text>
</svg>

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 KiB

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="280">
<rect width="200" height="280" fill="#e74a3b"/>
<text x="100" y="155" font-family="Arial" font-size="48" font-weight="bold"
fill="white" text-anchor="middle">МА</text>
</svg>

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 863 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="280">
<rect width="200" height="280" fill="#f6c23e"/>
<text x="100" y="155" font-family="Arial" font-size="48" font-weight="bold"
fill="white" text-anchor="middle">19</text>
</svg>

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="280">
<rect width="200" height="280" fill="#4e73df"/>
<text x="100" y="155" font-family="Arial" font-size="48" font-weight="bold"
fill="white" text-anchor="middle">ПР</text>
</svg>

After

Width:  |  Height:  |  Size: 254 B

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="280">
<rect width="200" height="280" fill="#1cc88a"/>
<text x="100" y="155" font-family="Arial" font-size="48" font-weight="bold"
fill="white" text-anchor="middle">ДЮ</text>
</svg>

After

Width:  |  Height:  |  Size: 254 B

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="280">
<rect width="200" height="280" fill="#f6c23e"/>
<text x="100" y="155" font-family="Arial" font-size="48" font-weight="bold"
fill="white" text-anchor="middle">ГА</text>
</svg>

After

Width:  |  Height:  |  Size: 254 B

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="280">
<rect width="200" height="280" fill="#e74a3b"/>
<text x="100" y="155" font-family="Arial" font-size="48" font-weight="bold"
fill="white" text-anchor="middle">ТР</text>
</svg>

After

Width:  |  Height:  |  Size: 254 B

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="280">
<rect width="200" height="280" fill="#e74a3b"/>
<text x="100" y="155" font-family="Arial" font-size="48" font-weight="bold"
fill="white" text-anchor="middle">ШЕ</text>
</svg>

After

Width:  |  Height:  |  Size: 254 B

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="280">
<rect width="200" height="280" fill="#4e73df"/>
<text x="100" y="155" font-family="Arial" font-size="48" font-weight="bold"
fill="white" text-anchor="middle">ВЛ</text>
</svg>

After

Width:  |  Height:  |  Size: 254 B

BIN
ex/db/library.db Normal file

Binary file not shown.

View file

@ -8,4 +8,4 @@ if __name__ == '__main__':
with app.app_context(): with app.app_context():
if not os.path.exists(app.config['DATABASE']): if not os.path.exists(app.config['DATABASE']):
init_db() init_db()
app.run(debug=os.environ.get('FLASK_DEBUG') == '1') app.run(debug=True)

View file

@ -1,4 +1,5 @@
import random import random
import math
def circle_square_mk(r, n): def circle_square_mk(r, n):
inside = 0 inside = 0

View file

@ -1,3 +1,4 @@
import operator
def person_lister(f): def person_lister(f):
def inner(people): def inner(people):

View file

@ -2,6 +2,7 @@ import pytest
import math import math
import os import os
import subprocess import subprocess
import tempfile
from fact import fact_it, fact_rec from fact import fact_it, fact_rec
from show_employee import show_employee from show_employee import show_employee
from sum_and_sub import sum_and_sub from sum_and_sub import sum_and_sub
@ -10,7 +11,7 @@ from my_sum import my_sum
from email_validation import fun from email_validation import fun
from fibonacci import fibonacci from fibonacci import fibonacci
from average_scores import compute_average_scores from average_scores import compute_average_scores
from plane_angle import Point from plane_angle import Point, plane_angle
from complex_numbers import Complex from complex_numbers import Complex
from circle_square_mk import circle_square_mk from circle_square_mk import circle_square_mk
from log_decorator import function_logger from log_decorator import function_logger

View file

@ -1,4 +1,3 @@
import os
import random import random
from flask import Flask, render_template from flask import Flask, render_template
from faker import Faker from faker import Faker
@ -49,4 +48,4 @@ def about():
return render_template('about.html', title='Об авторе') return render_template('about.html', title='Об авторе')
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=os.environ.get('FLASK_DEBUG') == '1') app.run(debug=True)

View file

@ -1,4 +1,3 @@
import os
import re import re
import random import random
from flask import Flask, render_template, request from flask import Flask, render_template, request
@ -105,4 +104,4 @@ def phone():
) )
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=os.environ.get('FLASK_DEBUG') == '1') app.run(debug=True)

View file

@ -1,4 +1,3 @@
import os
import re import re
import random import random
from flask import Flask, render_template, request, session, redirect, url_for, flash from flask import Flask, render_template, request, session, redirect, url_for, flash
@ -9,7 +8,7 @@ fake = Faker('ru_RU')
app = Flask(__name__) app = Flask(__name__)
application = app application = app
app.secret_key = os.environ.get('SECRET_KEY', '1234567890secret') app.secret_key = '1234567890secret'
login_manager = LoginManager() login_manager = LoginManager()
login_manager.init_app(app) login_manager.init_app(app)
@ -167,4 +166,4 @@ def phone():
) )
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=os.environ.get('FLASK_DEBUG') == '1') app.run(debug=True)

View file

@ -1,8 +1,7 @@
import os
import re import re
import random import random
from datetime import datetime from datetime import datetime
from flask import Flask, render_template, request, session, redirect, url_for, flash from flask import Flask, render_template, request, session, redirect, url_for, flash, abort
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt from flask_bcrypt import Bcrypt
@ -12,7 +11,7 @@ fake = Faker('ru_RU')
app = Flask(__name__) app = Flask(__name__)
application = app application = app
app.secret_key = os.environ.get('SECRET_KEY', '1234567890secret') app.secret_key = '1234567890secret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db' app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
@ -448,4 +447,4 @@ def change_password():
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=os.environ.get('FLASK_DEBUG') == '1') app.run(debug=True)

Binary file not shown.

View file

@ -7,7 +7,6 @@ MarkupSafe==2.1.1
python-dateutil==2.8.2 python-dateutil==2.8.2
six==1.16.0 six==1.16.0
Werkzeug==2.0.3 Werkzeug==2.0.3
Flask-Login==0.6.3 Flask-Login
Flask-SQLAlchemy==2.5.1 Flask-SQLAlchemy
SQLAlchemy==1.4.54 Flask-Bcrypt
Flask-Bcrypt==1.0.1

View file

@ -1,9 +1,8 @@
import os
import re import re
import random import random
from functools import wraps from functools import wraps
from datetime import datetime from datetime import datetime
from flask import Flask, render_template, request, session, redirect, url_for, flash from flask import Flask, render_template, request, session, redirect, url_for, flash, abort
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt from flask_bcrypt import Bcrypt
@ -13,7 +12,7 @@ fake = Faker('ru_RU')
app = Flask(__name__) app = Flask(__name__)
application = app application = app
app.secret_key = os.environ.get('SECRET_KEY', '1234567890secret') app.secret_key = '1234567890secret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db' app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
@ -516,4 +515,4 @@ with app.app_context():
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=os.environ.get('FLASK_DEBUG') == '1') app.run(debug=True)

Binary file not shown.

View file

@ -51,7 +51,7 @@ def index():
return redirect(url_for('index')) return redirect(url_for('index'))
m = _get_app_module() m = _get_app_module()
VisitLog = m.VisitLog db, VisitLog = m.db, m.VisitLog
page = request.args.get('page', 1, type=int) page = request.args.get('page', 1, type=int)
per_page = 10 per_page = 10

View file

@ -7,7 +7,6 @@ MarkupSafe==2.1.1
python-dateutil==2.8.2 python-dateutil==2.8.2
six==1.16.0 six==1.16.0
Werkzeug==2.0.3 Werkzeug==2.0.3
Flask-Login==0.6.3 Flask-Login
Flask-SQLAlchemy==2.5.1 Flask-SQLAlchemy
SQLAlchemy==1.4.54 Flask-Bcrypt
Flask-Bcrypt==1.0.1

View file

@ -1,6 +1,6 @@
import os import os
SECRET_KEY = os.environ.get('SECRET_KEY', 'secret-key') SECRET_KEY = 'secret-key'
SQLALCHEMY_DATABASE_URI = 'sqlite:///project.db' SQLALCHEMY_DATABASE_URI = 'sqlite:///project.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_TRACK_MODIFICATIONS = False

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 970 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View file

@ -1,6 +1,7 @@
import os import os
from typing import Optional, List from typing import Optional, Union, List
from datetime import datetime from datetime import datetime
import sqlalchemy as sa
from werkzeug.security import check_password_hash, generate_password_hash from werkzeug.security import check_password_hash, generate_password_hash
from flask_login import UserMixin from flask_login import UserMixin
from flask import url_for from flask import url_for