Practice Completed

main
amanfromspace 2025-11-17 11:54:30 +03:30
parent 57067e4f14
commit 876b8da1dd
25 changed files with 28229 additions and 0 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Amirreza Panahi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

17
app.py Normal file
View File

@ -0,0 +1,17 @@
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def home():
data = {
"en_name": "Mohammad Amin Mirzaee",
"fa_name": "محمد امین میرزائی",
"stuNumber": "04121129705027",
}
return render_template("index.html", data=data)
if __name__ == "__main__":
app.run(debug=True)

View File

@ -0,0 +1,48 @@
from datetime import datetime
from flask import Flask, render_template
app = Flask(__name__)
FEATURES = [
(
"render_template",
"EN: render_template is a function provided by Flask that renders an HTML template and returns it as a response to a client (browser). Flask uses a template engine called Jinja2. You write HTML files with placeholders or dynamic content, and render_template fills in those placeholders when the page is requested.",
),
(
"render_template",
" فا: این تابع توسط فلسک ارائه شده و کد های اچ تی ام ال را که در پوشه تمپلیتس است رندر می کند، فلسک در واقع از انجین یا موتوری به نام جینجا2 استفاده می کند. شما می توانید فایل های اچ تی ام ال را به صورت مستقیم و یا پویا در فایل های پایتون به اچ تی ام ال وصل کنید و در خواست به صفحاتتون بفرستید",
),
(
"/templates",
"EN: Store HTML files or templates that your Flask app will render. Flask automatically looks here when you call render_template.",
),
(
"/templates",
"فا: ذخیره فایل های اچ تی ام ال و قالب ها در برنامه فلسک خود که رندر خواهد کرد. فلسک اتوماتیک این پوشه را رصد می کند در صورتیکه تابع رندر_تمپلیتس فراخوانی شود",
),
(
"/static",
"EN: Store static files like CSS, JavaScript, images, fonts — anything that doesnt change dynamically. Flask serves files from this folder automatically.",
),
(
"/static",
"فا: تمامی فایل های استاتیک از جمله کد های سی اس اس و جاوا اسکریپت و عکس ها . فونت ها یا مدیا ها را ذخیره می کند که در حال تغییر به صورت پویا نیستند. فلسک این فایل ها را به صورت اتوماتیک برای شما تنظیم کرده و می توانید از مسیر آن استفاده کنید",
),
]
@app.route("/")
def homepage():
"""Render a simple HTML page that uses dynamic data."""
return render_template(
"index.html",
features=FEATURES,
current_time=datetime.utcnow(),
)
if __name__ == "__main__":
app.run(debug=True)

View File

@ -0,0 +1 @@
Flask==3.0.3

View File

@ -0,0 +1,19 @@
document.addEventListener("DOMContentLoaded", () => {
const highlightButton = document.querySelector("[data-js='highlight']");
const timestampButton = document.querySelector("[data-js='timestamp']");
const container = document.querySelector("main");
const timestampTarget = document.querySelector("[data-js='timestamp-value']");
if (highlightButton) {
highlightButton.addEventListener("click", () => {
container.classList.toggle("highlighted");
});
}
if (timestampButton) {
timestampButton.addEventListener("click", () => {
const now = new Date().toISOString().replace("T", " ").slice(0, 19) + "Z";
timestampTarget.textContent = now;
});
}
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -0,0 +1,83 @@
:root {
color-scheme: light dark;
font-family: "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 2.5rem 1rem 4rem;
background: #f3f4f6;
color: #111;
}
main {
max-width: 700px;
margin: 0 auto;
background: #fff;
border-radius: 12px;
padding: 2rem;
box-shadow: 0 12px 30px rgba(15, 23, 42, 0.15);
transition: transform 150ms ease, box-shadow 150ms ease;
}
main.highlighted {
transform: translateY(-2px);
box-shadow: 0 20px 40px rgba(37, 99, 235, 0.25);
}
h1 {
margin-top: 0;
font-size: 2.25rem;
color: #2563eb;
}
ul {
padding-left: 1.25rem;
}
li {
margin-bottom: 0.75rem;
}
footer {
margin-top: 2rem;
font-size: 0.85rem;
color: #475569;
}
code {
background: #f1f5f9;
color: #0f172a;
padding: 0.15rem 0.3rem;
border-radius: 4px;
}
.actions {
margin: 1.5rem 0;
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
}
button {
padding: 0.65rem 1.2rem;
border-radius: 999px;
border: none;
background: #2563eb;
color: #fff;
font-weight: 600;
cursor: pointer;
transition: background 120ms ease, transform 120ms ease;
}
button:hover {
background: #1d4ed8;
}
button:active {
transform: scale(0.98);
}

View File

@ -0,0 +1,88 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>گزارش دوم کار با HTML Templates در Flask</title>
<link
rel="stylesheet"
href="{{ url_for('static', filename='style.css') }}"
/>
<script src="{{ url_for('static', filename='app.js') }}" defer></script>
</head>
<body>
<main>
<h1>My Info</h1>
<p>Mohammad Amin Mirzaee - 04121129705027</p>
<h2>
What is <code>render_template</code> & What is the role of the
<code>/templates</code> and <code>/static</code> folders?
</h2>
<ul>
{% for title, description in features %}
<li>
<strong>{{ title }}:</strong>
{{ description }}
</li>
{% endfor %}
</ul>
<div class="actions">
<button type="button" data-js="highlight">Toggle highlight</button>
<button type="button" data-js="timestamp">Update timestamp</button>
</div>
<p>
The current (UTC) time was rendered by Flask:
<strong data-js="timestamp-value">
{{ current_time.strftime("%Y-%m-%d %H:%M:%S") }}Z
</strong>
</p>
<footer>
Commands ( already in venv )
<ul>
<li><code>cd examples/html-basic</code> وارد پروژه می شویم</li>
<li>
<code>pip install -r requirements.txt</code> نصب پکیج های مورد نیاز
</li>
<li><code>python app.py</code> اجرای برنامه</li>
</ul>
<h3>Before</h3>
<img
src="{{ url_for('static', filename='img/before.png') }}"
alt="Before"
width="600"
/>
<h3>After</h3>
<img
src="{{ url_for('static', filename='img/after.png') }}"
alt="After"
width="600"
/>
<h3>Hierarchy / Tree</h3>
<img
src="{{ url_for('static', filename='img/tree.png') }}"
alt="After"
width="600"
/>
<p>
Changes in <code>index.html</code> file: I changed the text of each
elements, also added some html elements/tag like img, p, h2, h3, ...
then using <code>/static</code> folder to put my images ( screenshots
) and using them in page with url_for function to find static
folder and filename ( using flask in order to import media ) I also
use ul and li tags to list commands I used for running the
application.
</p>
<p>
تغییرات در فایل ایندکس اچ تی ام ال: من متن های هر تگی را تغییر دادم و
اضافه کردم یکسری تگ هایی مثل تگ آی ام جی، پی، تگ های اچ، .... و بعد از
پوشه استاتیک برای قرار دادن عکس ها و اسکرین شات ها با تابع مخصوص فلسک
برای پیدا کردن مسیر آن استفاده کردم در ادامه با تگ یو ال و ال آی لیستی
از فرمان های اجرای برنامه را قرار دادم
</p>
</footer>
</main>
</body>
</html>

8
examples/postgresql/.env Normal file
View File

@ -0,0 +1,8 @@
# PostgreSQL connection string in the form postgresql://USER:PASS@HOST:PORT/DBNAME
DATABASE_URL=postgresql://me:root@localhost:5432/test
# Port for the Flask development server
PORT=5001
# Enable the debugger and auto-reload (true/false)
FLASK_DEBUG=true

View File

@ -0,0 +1,8 @@
# PostgreSQL connection string in the form postgresql://USER:PASS@HOST:PORT/DBNAME
DATABASE_URL=postgresql://demo_user:demo_pass@localhost:5432/demo
# Port for the Flask development server
PORT=5001
# Enable the debugger and auto-reload (true/false)
FLASK_DEBUG=true

491
examples/postgresql/app.py Normal file
View File

@ -0,0 +1,491 @@
import os
from decimal import Decimal
from typing import Any, Mapping, Sequence
import psycopg2
from psycopg2 import IntegrityError
from psycopg2.extras import RealDictCursor
from dotenv import load_dotenv
from flask import Flask, Response, jsonify, request
"""
Flask + PostgreSQL learning lab.
This single file now demonstrates every foundational database task you encounter
in CRUD apps:
- /init create the table and helper indexes
- /reset drop and recreate the schema (danger zone, but educational)
- /seed insert sample rows with optional UPSERT behavior
- /health verify the database connection
- /items list items as JSON
- /items/<id> read/update/delete individual rows (JSON payloads)
- /add legacy query-param insert for quick URL experiments
- /search filter by name/value plus pagination
- /stats aggregate queries (min/max/avg)
- /schema inspect the table definition using information_schema
- /list tab-separated export for spreadsheets/CLI work
Connection details stay in environment variables so you can point the app at any
database without editing code.
"""
load_dotenv()
DATABASE_URL = os.getenv(
"DATABASE_URL",
"postgresql://postgres:root@localhost:5432/postgres",
)
PORT = int(os.getenv("PORT", "5000"))
DEBUG = os.getenv("FLASK_DEBUG", "false").lower() in {"1", "true", "yes"}
TRUE_VALUES = {"1", "true", "yes", "on"}
SELECT_COLUMNS = "id, name, value, note, created_at, updated_at"
SEED_ITEMS = [
{"name": "Desk", "value": 199.99, "note": "Spacious work surface"},
{"name": "Chair", "value": 89.5, "note": "Ergonomic and adjustable"},
{"name": "Lamp", "value": 35.0, "note": "LED task lighting"},
{"name": "Notebook", "value": 6.25, "note": "Grid-paper notebook"},
{"name": "Plant", "value": 18.75, "note": "Adds a splash of green"},
]
app = Flask(__name__)
def get_conn() -> psycopg2.extensions.connection:
"""Return a new psycopg2 connection using DATABASE_URL."""
return psycopg2.connect(DATABASE_URL)
def create_items_table(drop_existing: bool = False) -> None:
"""(Re)create the demo table and the indexes we rely on."""
with get_conn() as conn, conn.cursor() as cur:
if drop_existing:
cur.execute("DROP TABLE IF EXISTS items")
cur.execute(
"""
CREATE TABLE IF NOT EXISTS items (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
value DOUBLE PRECISION NOT NULL CHECK (value >= 0),
note TEXT NOT NULL DEFAULT '',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
"""
)
cur.execute("CREATE INDEX IF NOT EXISTS idx_items_value ON items (value)")
cur.execute(
"CREATE INDEX IF NOT EXISTS idx_items_created_at ON items (created_at)"
)
def _floatify(value: Any) -> float | None:
if value is None:
return None
if isinstance(value, Decimal):
return float(value)
return float(value)
def _serialize_item(row: Mapping[str, Any]) -> dict[str, Any]:
"""Convert psycopg2 rows into JSON-friendly data."""
return {
"id": row["id"],
"name": row["name"],
"value": _floatify(row.get("value")),
"note": row.get("note") or "",
"created_at": row.get("created_at").isoformat()
if row.get("created_at")
else None,
"updated_at": row.get("updated_at").isoformat()
if row.get("updated_at")
else None,
}
def _run_select(sql: str, params: Sequence[Any] | None = None) -> list[dict[str, Any]]:
with get_conn() as conn, conn.cursor(cursor_factory=RealDictCursor) as cur:
cur.execute(sql, params or ())
rows = cur.fetchall()
return [_serialize_item(row) for row in rows]
def _select_one(sql: str, params: Sequence[Any] | None = None) -> dict[str, Any] | None:
with get_conn() as conn, conn.cursor(cursor_factory=RealDictCursor) as cur:
cur.execute(sql, params or ())
row = cur.fetchone()
return _serialize_item(row) if row else None
def _coerce_name(raw: Any) -> str:
name = str(raw or "").strip()
if not name:
raise ValueError("name is required")
return name
def _coerce_value(raw: Any) -> float:
try:
value = float(raw)
except (TypeError, ValueError):
raise ValueError("value must be a number")
if value < 0:
raise ValueError("value must be >= 0")
return value
def _coerce_note(raw: Any) -> str:
return str(raw or "").strip()
def _parse_create_payload(data: Mapping[str, Any]) -> tuple[str, float, str]:
return (
_coerce_name(data.get("name")),
_coerce_value(data.get("value")),
_coerce_note(data.get("note")),
)
def _parse_partial_payload(data: Mapping[str, Any]) -> dict[str, Any]:
fields: dict[str, Any] = {}
if "name" in data:
fields["name"] = _coerce_name(data.get("name"))
if "value" in data:
fields["value"] = _coerce_value(data.get("value"))
if "note" in data:
fields["note"] = _coerce_note(data.get("note"))
if not fields:
raise ValueError("provide at least one of name, value, or note")
return fields
def _insert_item(name: str, value: float, note: str) -> dict[str, Any]:
with get_conn() as conn, conn.cursor(cursor_factory=RealDictCursor) as cur:
cur.execute(
f"""
INSERT INTO items (name, value, note)
VALUES (%s, %s, %s)
RETURNING {SELECT_COLUMNS}
""",
(name, value, note),
)
row = cur.fetchone()
return _serialize_item(row)
def _update_item(item_id: int, fields: Mapping[str, Any]) -> dict[str, Any] | None:
if not fields:
return None
assignments = ", ".join(f"{column} = %s" for column in fields)
params = [*fields.values(), item_id]
with get_conn() as conn, conn.cursor(cursor_factory=RealDictCursor) as cur:
cur.execute(
f"""
UPDATE items
SET {assignments}, updated_at = NOW()
WHERE id = %s
RETURNING {SELECT_COLUMNS}
""",
params,
)
row = cur.fetchone()
return _serialize_item(row) if row else None
def _delete_item(item_id: int) -> bool:
with get_conn() as conn, conn.cursor() as cur:
cur.execute("DELETE FROM items WHERE id = %s", (item_id,))
return cur.rowcount > 0
def _as_bool(value: Any) -> bool:
if isinstance(value, bool):
return value
return str(value or "").strip().lower() in TRUE_VALUES
def _parse_limit(raw: Any, default: int = 20) -> int:
try:
limit = int(raw) if raw is not None else default
except (TypeError, ValueError):
limit = default
return max(1, min(100, limit))
@app.get("/health")
def health_check():
"""Simple connection test that also returns the database server time."""
with get_conn() as conn, conn.cursor() as cur:
cur.execute("SELECT NOW()")
(current_time,) = cur.fetchone()
return jsonify({"status": "ok", "database_time": current_time.isoformat()})
@app.get("/init")
def init_db():
"""Create the items table if it does not yet exist."""
create_items_table(drop_existing=False)
return "ok: table ready\n"
@app.post("/reset")
def reset_db():
"""Drop the table and recreate it from scratch."""
create_items_table(drop_existing=True)
return jsonify({"status": "ok", "message": "table dropped and recreated"})
@app.post("/seed")
def seed_data():
"""
Insert a batch of sample rows.
Accepts JSON:
{
"replace": true, # optional, truncate before inserting
"items": [
{"name": "...", "value": 1.23, "note": "..."},
...
]
}
"""
payload = request.get_json(silent=True) or {}
replace = _as_bool(payload.get("replace") or request.args.get("replace"))
dataset = payload.get("items") or SEED_ITEMS
if not isinstance(dataset, list):
return jsonify({"error": "items must be a JSON list"}), 400
parsed_rows: list[tuple[str, float, str]] = []
for entry in dataset:
if not isinstance(entry, Mapping):
return jsonify({"error": "each item must be an object"}), 400
try:
parsed_rows.append(_parse_create_payload(entry))
except ValueError as exc:
return jsonify({"error": f"invalid item: {exc}"}), 400
if not parsed_rows:
return jsonify({"error": "no items to insert"}), 400
create_items_table(drop_existing=False)
with get_conn() as conn, conn.cursor(cursor_factory=RealDictCursor) as cur:
if replace:
cur.execute("TRUNCATE TABLE items RESTART IDENTITY")
cur.executemany(
"""
INSERT INTO items (name, value, note)
VALUES (%s, %s, %s)
ON CONFLICT (name) DO UPDATE
SET value = EXCLUDED.value,
note = EXCLUDED.note,
updated_at = NOW()
""",
parsed_rows,
)
cur.execute("SELECT COUNT(*) AS total FROM items")
total = cur.fetchone()["total"]
return jsonify(
{
"status": "ok",
"processed": len(parsed_rows),
"replace": replace,
"total_rows": total,
}
)
@app.get("/items")
def list_items_json():
"""Return all rows as JSON."""
rows = _run_select(f"SELECT {SELECT_COLUMNS} FROM items ORDER BY created_at")
return jsonify({"count": len(rows), "items": rows})
@app.post("/items")
def create_item():
"""Create a row from a JSON payload."""
data = request.get_json(silent=True) or {}
try:
name, value, note = _parse_create_payload(data)
except ValueError as exc:
return jsonify({"error": str(exc)}), 400
try:
item = _insert_item(name, value, note)
except IntegrityError:
return jsonify({"error": "name must be unique"}), 409
return jsonify(item), 201
@app.get("/items/<int:item_id>")
def get_item(item_id: int):
"""Fetch a single row by ID."""
row = _select_one(
f"SELECT {SELECT_COLUMNS} FROM items WHERE id = %s", (item_id,)
)
if not row:
return jsonify({"error": "item not found"}), 404
return jsonify(row)
@app.put("/items/<int:item_id>")
def replace_item(item_id: int):
"""Replace an existing row (requires name + value)."""
data = request.get_json(silent=True) or {}
try:
name, value, note = _parse_create_payload(data)
except ValueError as exc:
return jsonify({"error": str(exc)}), 400
try:
row = _update_item(item_id, {"name": name, "value": value, "note": note})
except IntegrityError:
return jsonify({"error": "name must be unique"}), 409
if not row:
return jsonify({"error": "item not found"}), 404
return jsonify(row)
@app.patch("/items/<int:item_id>")
def update_item(item_id: int):
"""Partially update a row."""
data = request.get_json(silent=True) or {}
try:
fields = _parse_partial_payload(data)
except ValueError as exc:
return jsonify({"error": str(exc)}), 400
try:
row = _update_item(item_id, fields)
except IntegrityError:
return jsonify({"error": "name must be unique"}), 409
if not row:
return jsonify({"error": "item not found"}), 404
return jsonify(row)
@app.delete("/items/<int:item_id>")
def delete_item(item_id: int):
"""Remove a row permanently."""
if not _delete_item(item_id):
return jsonify({"error": "item not found"}), 404
return jsonify({"status": "ok", "deleted_id": item_id})
@app.get("/search")
def search_items():
"""Filter by partial name and/or numeric ranges."""
name_query = (request.args.get("q") or "").strip()
min_value_raw = request.args.get("min_value")
max_value_raw = request.args.get("max_value")
limit = _parse_limit(request.args.get("limit"))
try:
min_value = _coerce_value(min_value_raw) if min_value_raw else None
max_value = _coerce_value(max_value_raw) if max_value_raw else None
except ValueError as exc:
return jsonify({"error": str(exc)}), 400
conditions = []
params: list[Any] = []
if name_query:
conditions.append("name ILIKE %s")
params.append(f"%{name_query}%")
if min_value is not None:
conditions.append("value >= %s")
params.append(min_value)
if max_value is not None:
conditions.append("value <= %s")
params.append(max_value)
where_clause = f"WHERE {' AND '.join(conditions)}" if conditions else ""
params.append(limit)
sql = f"""
SELECT {SELECT_COLUMNS}
FROM items
{where_clause}
ORDER BY value DESC
LIMIT %s
"""
rows = _run_select(sql, params)
return jsonify({"returned": len(rows), "items": rows})
@app.get("/stats")
def stats():
"""Aggregate information about the table."""
with get_conn() as conn, conn.cursor(cursor_factory=RealDictCursor) as cur:
cur.execute(
"""
SELECT
COUNT(*) AS total_rows,
COALESCE(SUM(value), 0) AS total_value,
COALESCE(MIN(value), 0) AS min_value,
COALESCE(MAX(value), 0) AS max_value,
COALESCE(AVG(value), 0) AS avg_value
FROM items
"""
)
row = cur.fetchone()
return jsonify(
{
"total_rows": row["total_rows"],
"total_value": _floatify(row["total_value"]),
"min_value": _floatify(row["min_value"]),
"max_value": _floatify(row["max_value"]),
"avg_value": _floatify(row["avg_value"]),
}
)
@app.get("/schema")
def describe_schema():
"""Inspect the table definition via information_schema."""
with get_conn() as conn, conn.cursor(cursor_factory=RealDictCursor) as cur:
cur.execute(
"""
SELECT column_name, data_type, is_nullable, column_default
FROM information_schema.columns
WHERE table_name = 'items'
ORDER BY ordinal_position
"""
)
columns = cur.fetchall()
return jsonify({"columns": columns})
@app.get("/add")
def add_item():
"""Insert a new row using query parameters (e.g. ?name=foo&value=42)."""
data = {
"name": request.args.get("name"),
"value": request.args.get("value"),
"note": request.args.get("note", ""),
}
try:
name, value, note = _parse_create_payload(data)
except ValueError as exc:
return f"error: {exc}\n", 400
try:
item = _insert_item(name, value, note)
except IntegrityError:
return "error: name must be unique\n", 409
return f"ok: inserted id={item['id']}\n"
@app.get("/list")
def list_items_text():
"""Return the stored items in a tab-separated plain-text response."""
with get_conn() as conn, conn.cursor() as cur:
cur.execute("SELECT id, name, value, note FROM items ORDER BY id")
rows = cur.fetchall()
lines = ["id\tname\tvalue\tnote"] + [
f"{row[0]}\t{row[1]}\t{row[2]:.2f}\t{row[3]}" for row in rows
]
return Response("\n".join(lines) + "\n", mimetype="text/plain")
if __name__ == "__main__":
app.run(host="127.0.0.1", port=PORT, debug=DEBUG)

View File

@ -0,0 +1,3 @@
Flask
psycopg2-binary
python-dotenv

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

27368
get-pip.py Normal file

File diff suppressed because it is too large Load Diff

1
requirements.txt Normal file
View File

@ -0,0 +1 @@
Flask==3.0.3

15
static/css/style.css Normal file
View File

@ -0,0 +1,15 @@
body {
font-family: Arial, sans-serif;
background-color: #f9f9f9;
padding: 50px;
}
p {
font-size: 18px;
color: #34495e;
}
img {
border-radius: 10px;
margin-top: 20px;
}

BIN
static/img/browser.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

BIN
static/img/terminal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

58
templates/index.html Normal file
View File

@ -0,0 +1,58 @@
<!DOCTYPE html>
<html>
<head>
<title>گزارش اول برنامه Hello World با Flask</title>
<link
rel="stylesheet"
href="{{ url_for('static', filename='css/style.css') }}"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
/>
</head>
<body class="p-5">
<div class="card p-4 shadow">
<h1 class="mb-3 text-primary">Hello World, Welcome!</h1>
<p class="fs-4">My name is <strong>{{ data.en_name }}</strong>.</p>
<p class="fs-4">Student Number: {{ data.stuNumber }}</p>
<p class="fs-4">
نام و نام خانوادگی من <strong>{{ data.fa_name }}</strong> است
</p>
<p class="fs-4">شماره دانشجویی: {{ data.stuNumber }}</p>
<h6>
Flask is a web framework for Python that allows you to build websites,
web apps, and APIs easily.
</h6>
<h6>
فلسک یک فریم ورک یا چهارچوب وب است که برای پایتون است و به شما اجازه می
دهد تا وبسایت ها و وب اپ ها و ای پی آی ها را به راحتی بسازید
</h6>
<h3>Commands / دستورات</h3>
<ul>
<li><code>python get-pip.py</code> برای نصب پایپ</li>
<li><code>python -m venv venv</code> اجرا محیط مجازی و ایجاد پوشه آن</li>
<li><code>cd venv/Scripts</code> رفتن به مسیر پوشه و اکتیو کردن محیط</li>
<li><code>activate</code> با خط فرمان ویندوز</li>
<li><code>cd ../../</code> (Welcome-to-flask) بازگشت به مسیر پروژه</li>
<li><code>pip install -r requirements.txt</code> نصب برنامه های مورد نیاز</li>
<li><code>python app.py</code> اجرای برنامه با محیط</li>
<li><code>deactivate</code> در صورت بستن یا دی اکتیو کردن</li>
</ul>
<hr />
<h5>Terminal Logs / گزارشات ترمینال</h5>
<img
src="{{ url_for('static', filename='img/terminal.png') }}"
alt="Terminal"
width="800"
/>
<h5>Browser / مرورگر</h5>
<img
src="{{ url_for('static', filename='img/browser.png') }}"
alt="Browser"
width="1200"
/>
</div>
</body>
</html>