🌐 Python mājaslapu izstrādē
Python nav tikai skripti un datu analīze — ar Flask vai Django var veidot pilnvērtīgus web serverus, dinamiskas lapas un REST API. Šajā sadaļā iepazīsimies ar Flask un Django, veidojot lapas tāpat kā Webpamati.lv.
Flask vs Django vs FastAPI
Kuru izvēlēties?
- Flask — mazāki projekti, mācību nolūki, pilna kontrole. Izskatās līdzīgi PHP — tu pats izlemj, kā kārtot failus.
- Django — lieli projekti ar lietotāju sistēmu, datubāzi, admin paneli. Daudz gatava koda no kastes.
- FastAPI — REST API izstrādei, asinhrons, automātiska dokumentācija.
# Instalēšana pip install flask # Mikro-ietvars – brīvība un vienkāršība pip install django # Pilns ietvars – "baterijas iekļautas" pip install fastapi uvicorn # Moderns, ātrs, async API
Flask — pirmā lapa
pip install flask
mkdir mana_lapa && cd mana_lapa
# Izveidot app.py
# app.py
from flask import Flask
app = Flask(__name__)
# Maršruts (kā PHP fails + Apache route)
@app.route("/")
def sakumlapa():
return "<h1>Sveika, Flask!</h1><p>Mana pirmā Python lapa.</p>"
@app.route("/par-mums")
def par_mums():
return "<h1>Par mums</h1>"
# Dinamisks maršruts (URL parametrs)
@app.route("/temats/<string:nosaukums>")
def temats(nosaukums):
return f"<h1>Temats: {nosaukums}</h1>"
@app.route("/lietotajs/<int:id>")
def lietotajs(id):
return f"Lietotājs ar ID: {id}"
if __name__ == "__main__":
app.run(debug=True, port=5000) # debug=True automātiski restartē
# Palaist serveri
python app.py
# → Atvērt: http://localhost:5000/
# Vai ar flask komandu
flask --app app run --debug
Jinja2 veidnes — kā PHP templates
Flask izmanto Jinja2 veidnes — HTML faili ar Python loģiku. Principiāli līdzīgi PHP lapu struktūrai kā Webpamati.lv.
# Projekta struktūra (līdzīgi Webpamati.lv struktūrai)
mana_lapa/
├── app.py
├── templates/
│ ├── base.html ← Bāzes veidne (kā header.php + footer.php)
│ ├── index.html
│ └── temats.html
└── static/
├── css/
│ └── style.css
└── js/
└── main.js
{# templates/base.html – bāzes veidne (kā includes/ mapē) #}
<!DOCTYPE html>
<html lang="lv">
<head>
<meta charset="UTF-8">
<title>{% block title %}Webpamati{% endblock %} – Webpamati.lv</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<nav class="sidebar">
<a href="{{ url_for('sakumlapa') }}" class="logo">Webpamati.lv</a>
<ul>
{% for temats in navigacija %}
<li><a href="{{ url_for('temats_lapa', slug=temats.slug) }}"
class="{{ 'aktīvs' if temats.slug == aktīvais else '' }}">
{{ temats.nosaukums }}
</a></li>
{% endfor %}
</ul>
</nav>
<main>
{% block saturs %}{% endblock %}
</main>
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
</body>
</html>
{# templates/temats.html – pārmanto bāzes veidni #}
{% extends "base.html" %}
{% block title %}{{ temats.nosaukums }}{% endblock %}
{% block saturs %}
<div class="topic-header">
<h1>{{ temats.nosaukums }}</h1>
<p>{{ temats.apraksts }}</p>
</div>
{% for sadala in temats.sadalas %}
<div class="section">
<h2>{{ sadala.virsraksts }}</h2>
<div class="code-block">
<pre>{{ sadala.kods }}</pre>
</div>
</div>
{% endfor %}
{% if nav_sekojosais %}
<a href="{{ url_for('temats_lapa', slug=nav_sekojosais.slug) }}" class="next-btn">
Tālāk: {{ nav_sekojosais.nosaukums }} →
</a>
{% endif %}
{% endblock %}
# app.py – pilnīgāks piemērs ar veidnēm
from flask import Flask, render_template
app = Flask(__name__)
# Dati (vēlāk ielasīs no datubāzes)
temati = [
{"slug": "ievads", "nosaukums": "Ievads Python", "apraksts": "..."},
{"slug": "mainigi", "nosaukums": "Mainīgie", "apraksts": "..."},
{"slug": "funkcijas","nosaukums": "Funkcijas", "apraksts": "..."},
]
@app.route("/")
def sakumlapa():
return render_template("index.html",
temati=temati,
lappuse="sakulapa")
@app.route("/temats/<string:slug>")
def temats_lapa(slug):
temats = next((t for t in temati if t["slug"] == slug), None)
if temats is None:
return render_template("404.html"), 404
return render_template("temats.html",
temats=temats,
navigacija=temati,
aktīvais=slug)
if __name__ == "__main__":
app.run(debug=True)
Formas apstrāde
Flask forma apstrāde ir līdzīga PHP $_POST / $_GET.
from flask import Flask, request, redirect, url_for, session, flash
app = Flask(__name__)
app.secret_key = "slepena-atslega-123" # Session šifrēšanai
@app.route("/meklefgt", methods=["GET", "POST"])
def meklefgt():
rezultati = []
vards = ""
if request.method == "POST":
vards = request.form.get("meklet", "").strip() # kā PHP $_POST["meklet"]
if vards:
rezultati = [t for t in temati if vards.lower() in t["nosaukums"].lower()]
else:
flash("Lūdzu ievadi meklēšanas vārdu!") # Flash ziņojumi
return render_template("meklet.html", rezultati=rezultati, vards=vards)
@app.route("/pieteikties", methods=["GET", "POST"])
def pieteikties():
if request.method == "POST":
epasts = request.form.get("epasts", "")
parole = request.form.get("parole", "")
# Pārbaudīt lietotāju (piemērs)
if epasts == "admin@webpamati.lv" and parole == "parole":
session["lietotajs"] = epasts # Saglabāt sesijā
flash("Veiksmīgi pieteicies!", "success")
return redirect(url_for("sakumlapa"))
else:
flash("Nepareizs e-pasts vai parole!", "error")
return render_template("pieteikties.html")
@app.route("/atteikties")
def atteikties():
session.pop("lietotajs", None)
return redirect(url_for("sakumlapa"))
{# templates/pieteikties.html #}
{% extends "base.html" %}
{% block saturs %}
{# Flash ziņojumi #}
{% for kategorija, zinojums in get_flashed_messages(with_categories=true) %}
<div class="alert alert-{{ kategorija }}">{{ zinojums }}</div>
{% endfor %}
<form method="POST" action="{{ url_for('pieteikties') }}">
<label>E-pasts: <input type="email" name="epasts" required></label>
<label>Parole: <input type="password" name="parole" required></label>
<button type="submit">Pieteikties</button>
</form>
{% endblock %}
Python + MySQL (datubāze)
pip install mysql-connector-python
# vai
pip install PyMySQL flask-sqlalchemy
# Tieša MySQL savienošanās ar mysql-connector
import mysql.connector
from flask import Flask, render_template
app = Flask(__name__)
def dabūt_savienojumu():
return mysql.connector.connect(
host="localhost",
user="root",
password="",
database="webpamati",
charset="utf8mb4"
)
@app.route("/temati")
def visi_temati():
conn = dabūt_savienojumu()
cursor = conn.cursor(dictionary=True) # dictionary=True → vārdnīcas (kā PHP fetch_assoc)
cursor.execute("SELECT * FROM temati WHERE publicets = 1 ORDER BY kārtiba")
temati = cursor.fetchall()
cursor.close()
conn.close()
return render_template("temati.html", temati=temati)
@app.route("/temats/<int:id>")
def temats_pec_id(id):
conn = dabūt_savienojumu()
cursor = conn.cursor(dictionary=True)
# Prepared statement (aizsardzība pret SQL injection)
cursor.execute("SELECT * FROM temati WHERE id = %s", (id,))
temats = cursor.fetchone()
cursor.close()
conn.close()
if temats is None:
return render_template("404.html"), 404
return render_template("temats.html", temats=temats)
# Flask-SQLAlchemy ORM — pythoniskāks veids
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "mysql+pymysql://root:@localhost/webpamati"
db = SQLAlchemy(app)
# Modelis – kā Python klase = MySQL tabula
class Temats(db.Model):
__tablename__ = "temati"
id = db.Column(db.Integer, primary_key=True)
slug = db.Column(db.String(100), unique=True, nullable=False)
nosaukums = db.Column(db.String(255), nullable=False)
apraksts = db.Column(db.Text)
publicets = db.Column(db.Boolean, default=True)
def __repr__(self):
return f"<Temats {self.nosaukums}>"
# Vaicājumi ar ORM
@app.route("/temati")
def visi_temati():
temati = Temats.query.filter_by(publicets=True).order_by(Temats.nosaukums).all()
return render_template("temati.html", temati=temati)
@app.route("/temats/<string:slug>")
def temats_lapa(slug):
temats = Temats.query.filter_by(slug=slug).first_or_404()
return render_template("temats.html", temats=temats)
Flask vs PHP — salīdzinājums
# Flask (Python) # PHP ekvivalents
# ------------------------------------------------------
# @app.route("/lapa") # lapa.php
# request.method # $_SERVER["REQUEST_METHOD"]
# request.form["lauks"] # $_POST["lauks"]
# request.args["q"] # $_GET["q"]
# session["lietotajs"] # $_SESSION["lietotajs"]
# redirect(url_for("funkcija")) # header("Location: lapa.php")
# render_template("t.html", x=y) # include "t.php"; (ar $x = $y)
# flash("Ziņojums!") # $_SESSION["flash"] = "Ziņojums!"
# g.db (globāls konteksts) # (globāls $db mainīgais)
# Piemērs: vienāda loģika abās valodās
# --- Python/Flask ---
@app.route("/komentars", methods=["POST"])
def pievienot_komentaru():
teksts = request.form.get("teksts", "").strip()
if len(teksts) < 5:
flash("Komentārs ir pārāk īss!")
return redirect(url_for("sakumlapa"))
conn = dabūt_savienojumu()
cursor = conn.cursor()
cursor.execute(
"INSERT INTO komentari (teksts, laiks) VALUES (%s, NOW())",
(teksts,)
)
conn.commit()
cursor.close()
conn.close()
flash("Komentārs pievienots!")
return redirect(url_for("sakumlapa"))
// PHP ekvivalents
if ($_SERVER["REQUEST_METHOD"] === "POST") {
$teksts = trim($_POST["teksts"] ?? "");
if (strlen($teksts) < 5) {
$_SESSION["flash"] = "Komentārs ir pārāk īss!";
header("Location: index.php");
exit;
}
$stmt = $pdo->prepare("INSERT INTO komentari (teksts, laiks) VALUES (?, NOW())");
$stmt->execute([$teksts]);
$_SESSION["flash"] = "Komentārs pievienots!";
header("Location: index.php");
exit;
}
Django — īss ieskats
Django ir "akumulatoru iekļauts" ietvars — tas automātiski nodrošina lietotāju sistēmu, admin paneli, ORM, formu validāciju un drošību.
🌐 Webpamati.lv ar Python?
Šī pati Webpamati.lv lapa ir veidota ar PHP. Tomēr ar Flask vai Django varētu izveidot identisku lapu Python valodā — tādu pašu sānjoslu, koda blokus, navigāciju. Atšķirība ir tikai sintaksē: PHP faili → Flask maršruti, include → Jinja2 {% extends %}, $_POST → request.form.
pip install django
# Jauns projekts
django-admin startproject webpamati . # "." = pašreizējā mapē
# Jauna aplikācija (kā modulāra PHP sadaļa)
python manage.py startapp temati
# Projekta struktūra
# webpamati/
# ├── manage.py ← Pārvaldības rīks
# ├── webpamati/
# │ ├── settings.py ← Konfigurācija (datubāze, apps, u.c.)
# │ ├── urls.py ← Galvenais URL maršrutētājs
# │ └── wsgi.py
# └── temati/ ← Aplikācija
# ├── models.py ← Datubāzes modeļi
# ├── views.py ← Loģika (kā PHP faili)
# ├── urls.py ← URLs šai aplikācijai
# └── templates/ ← HTML veidnes
# Palaist attīstības serveri
python manage.py runserver # http://localhost:8000/
# temati/models.py – datubāzes modelis
from django.db import models
class Kategorija(models.Model):
nosaukums = models.CharField(max_length=100)
class Meta:
verbose_name_plural = "Kategorijas"
def __str__(self):
return self.nosaukums
class Temats(models.Model):
LIMENIS = [("iesacejs", "Iesācējs"), ("videjs", "Vidējs"), ("eksperts", "Eksperts")]
kategorija = models.ForeignKey(Kategorija, on_delete=models.CASCADE)
slug = models.SlugField(unique=True)
nosaukums = models.CharField(max_length=255)
apraksts = models.TextField()
limenis = models.CharField(max_length=20, choices=LIMENIS, default="iesacejs")
publicets = models.BooleanField(default=True)
izveidots = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ["nosaukums"]
def __str__(self):
return self.nosaukums
# Migrācijas – Django izveido tabulas automātiski
# python manage.py makemigrations
# python manage.py migrate
# temati/views.py
from django.shortcuts import render, get_object_or_404
from .models import Temats, Kategorija
def sakumlapa(request):
temati = Temats.objects.filter(publicets=True).select_related("kategorija")
kategorijas = Kategorija.objects.all()
return render(request, "sakumlapa.html", {
"temati": temati,
"kategorijas": kategorijas,
})
def temats_detalu(request, slug):
temats = get_object_or_404(Temats, slug=slug, publicets=True)
# Nākamais un iepriekšējais temats
try:
sekojosais = Temats.objects.filter(
kategorija=temats.kategorija, id__gt=temats.id
).order_by("id").first()
except Temats.DoesNotExist:
sekojosais = None
return render(request, "temats.html", {
"temats": temats,
"sekojosais": sekojosais,
})
# temati/urls.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.sakumlapa, name="sakumlapa"),
path("t/<slug:slug>/", views.temats_detalu, name="temats"),
]
# webpamati/urls.py – galvenais maršrutētājs
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path("admin/", admin.site.urls), # Bezmaksas admin panelis!
path("", include("temati.urls")),
]
# Django admin – reģistrēt modeli admina panelī
# temati/admin.py
from django.contrib import admin
from .models import Temats, Kategorija
@admin.register(Temats)
class TematsAdmin(admin.ModelAdmin):
list_display = ["nosaukums", "kategorija", "limenis", "publicets"]
list_filter = ["kategorija", "limenis", "publicets"]
search_fields = ["nosaukums", "apraksts"]
prepopulated_fields = {"slug": ("nosaukums",)}
admin.site.register(Kategorija)
# python manage.py createsuperuser
# → http://localhost:8000/admin/ Pilns satura vadības panelis!