07092026
test / build-docs (push) Successful in 1s

This commit is contained in:
jonnybravo
2026-09-07 17:02:48 +02:00
parent 6678aed520
commit 23b7df0037
118 changed files with 2029 additions and 1467 deletions
@@ -1,7 +0,0 @@
Folgende Punkte
- erstellen eine SQlite DB
- Die DB soll folgende Tabellen haben Genre, MyList,
- Die Anzeige soll über Flask angezeigt werden
Weitere Schritte folgen !!!
@@ -1,69 +0,0 @@
import DBcm
def create_movie_database(db_name="movie_db.db"):
create_my_list = """
create table if not exists movie_list (
id integer not null primary key autoincrement,
titel varchar(64) not null,
genre_id integer not null,
regie_id integer not null
)
"""
create_genre = """
create table if not exists genre (
id integer not null primary key autoincrement,
name varchar(64) not null
)
"""
create_regie = """
create table if not exists regie (
id integer not null primary key autoincrement,
surname varchar(64) not null,
lastname varchr(64) not null
)
"""
create_medium = """
create table if not exists medium (
id integer not null primary key autoincrement,
medium varchar(64) not null
)
"""
with DBcm.UseDatabase(db_name) as db:
db.execute(create_my_list)
db.execute(create_genre)
db.execute(create_regie)
db.execute(create_medium)
def all_genres(db_name="movie_db.db"):
ALL_GENRE = "SELECT * from genre"
with DBcm.UseDatabase(db_name) as db:
db.execute(ALL_GENRE)
all_genre = [i[1] for i in db.fetchall()]
return all_genre
def search_genre_id(db_name="movie_db.db", genre_name=str):
GENRE_QUERY = """
select id from genre
where name = ?
"""
try:
with DBcm.UseDatabase(db_name) as db:
db.execute(GENRE_QUERY, (genre_name,))
genre_id = db.fetchone()[0]
return int(genre_id)
except:
return int(0)
if __name__ == "__main__":
create_movie_database()
print(all_genres())
print(search_genre_id(genre_name="war"))
@@ -1,534 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "5263a987-da36-46d7-a2e7-d0658cda09c1",
"metadata": {},
"outputs": [],
"source": [
"import DBcm"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "3f6b0763-4106-4bfa-9aef-7afbd180c6d4",
"metadata": {},
"outputs": [],
"source": [
"db_name = \"movie_db.db\"\n",
"\n",
"create_my_list = \"\"\"\n",
" create table if not exists movie_list (\n",
" id integer not null primary key autoincrement,\n",
" titel varchar(64) not null,\n",
" genre_id integer not null,\n",
" regie_id integer not null\n",
" \n",
" )\n",
"\n",
"\"\"\"\n",
"\n",
"create_genre = \"\"\"\n",
" create table if not exists genre (\n",
" id integer not null primary key autoincrement,\n",
" name varchar(64) not null\n",
" )\n",
"\"\"\"\n",
"\n",
"create_regie = \"\"\"\n",
" create table if not exists regie (\n",
" id integer not null primary key autoincrement,\n",
" surname varchar(64) not null,\n",
" lastname varchr(64) not null\n",
" )\n",
"\"\"\"\n",
"\n",
"\n",
"with DBcm.UseDatabase(db_name) as db: \n",
" db.execute(create_my_list)\n",
" db.execute(create_genre)\n",
" db.execute(create_regie)\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "376ef812-97b5-45ba-8ef1-eb8d7829494a",
"metadata": {},
"outputs": [],
"source": [
"# ADDed Genre values\n",
"\n",
"ADD_GENRE_VALUE = \"\"\"\n",
" INSERT INTO genre(name)\n",
" SELECT ?\n",
" WHERE NOT EXISTS (SELECT 1 FROM genre WHERE name = ?);\n",
" \"\"\"\n",
"\n",
"with open(\"genre_list\", \"r\") as fs: \n",
" for genre_value in fs.readlines():\n",
" with DBcm.UseDatabase(db_name) as db:\n",
" db.execute(ADD_GENRE_VALUE, (genre_value.strip(), genre_value.strip()))\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "63b16a41-88bf-4832-a26c-09180832f597",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['action', 'adventure', 'animation', 'biography', 'comedy', 'crime', 'cult movie', 'disney', 'documentary', 'drama', 'erotic', 'family', 'fantasy', 'film-noir', 'gangster', 'gay and lesbian', 'history', 'horror', 'military', 'music', 'musical', 'mystery', 'nature', 'neo-noir', 'period', 'pixar', 'road movie', 'romance', 'sci-fi', 'short', 'spy', 'super hero', 'thriller', 'visually stunning', 'war', 'western']\n"
]
}
],
"source": [
"def all_genres():\n",
" ALL_GENRE = \"\"\"\n",
" SELECT * from genre \n",
" \"\"\" \n",
" with DBcm.UseDatabase(db_name) as db:\n",
" db.execute(ALL_GENRE)\n",
" all_genre = [i[1] for i in db.fetchall()]\n",
" \n",
" return all_genre\n",
"\n",
"print(all_genres())\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 36,
"id": "89b20b5f-34aa-4490-a4c0-c186c9fa30bd",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1\n",
"36\n"
]
}
],
"source": [
"def search_genre_id(genre_name):\n",
" GENRE_QUERY = \"\"\"\n",
" select id from genre\n",
" where name = ?\n",
" \"\"\"\n",
" try:\n",
" with DBcm.UseDatabase(db_name) as db:\n",
" db.execute(GENRE_QUERY,(genre_name,))\n",
" genre_id = db.fetchone()[0]\n",
" return int(genre_id)\n",
" except:\n",
" return int(0)\n",
"\n",
"\n",
"def search_medium_id(genre_name):\n",
" GENRE_QUERY = \"\"\"\n",
" select id from genre\n",
" where medium = ?\n",
" \"\"\"\n",
" try:\n",
" with DBcm.UseDatabase(db_name) as db:\n",
" db.execute(GENRE_QUERY,(genre_name,))\n",
" genre_id = db.fetchone()[0]\n",
" return int(genre_id)\n",
" except:\n",
" return int(0)\n",
"\n",
"print(search_genre_id(genre_name=\"action\"))\n",
"print(search_genre_id(genre_name=\"western\"))"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "c70d91a5-7855-465d-a4a6-daebc065ee37",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0-John-Smith\n",
"1-James-Johnson\n",
"2-William-Williams\n",
"3-Michael-Brown\n",
"4-David-Davis\n",
"5-Richard-Miller\n",
"6-Joseph-Wilson\n",
"7-Charles-Moore\n",
"8-Thomas-Taylor\n",
"9-Daniel-Anderson\n",
"10-Paul-Thomas\n",
"11-Mark-Jackson\n",
"12-Donna-White\n",
"13-Michelle-Harris\n",
"14-Laura-Martin\n",
"15-Sara-Thompson\n",
"16-Ana-Garcia\n",
"17-Carlos-Rodriguez\n",
"18-Maria-Martinez\n",
"19-Jose-Hernandez\n",
"20-Luis-Lopez\n",
"21-Rosa-Gonzalez\n",
"22-Pedro-Perez\n",
"23-Miguel-Sanchez\n",
"24-Juan-Ramirez\n",
"25-Ana-Flores\n",
"26-Isabella-Cruz\n",
"27-Victor-Rivera\n",
"28-Kevin-Lee\n",
"29-Brian-Walker\n",
"30-Emily-Hall\n",
"31-Ryan-Allen\n",
"32-Aaron-Young\n",
"33-Jeffrey-King\n",
"34-Joshua-Wright\n",
"35-Brandon-Scott\n",
"36-Frank-Turner\n",
"37-Gregory-Carter\n",
"38-Samuel-Phillips\n",
"39-Chris-Evans\n",
"40-Anthony-Collins\n",
"41-Eric-Stewart\n",
"42-Frank-Snyder\n",
"43-Thomas-Baker\n",
"44-Jeremy-Nelson\n",
"45-Steven-Roberts\n",
"46-Edward-Campbell\n",
"47-Ryan-Miller\n",
"48-Jacob-Davis\n",
"49-David-Garcia\n",
"50-Sophia-Rodriguez\n",
"51-Emma-Martinez\n",
"52-Noah-Hernandez\n",
"53-Ava-Lopez\n",
"54-Ethan-Gonzalez\n",
"55-Mia-Perez\n",
"56-William-Sanchez\n",
"57-James-Ramirez\n",
"58-Olivia-Flores\n",
"59-Lucas-Cruz\n",
"60-Isabella-Rivera\n",
"61-David-Lee\n",
"62-Sophie-Walker\n",
"63-Matthew-Hall\n",
"64-Emma-Allen\n",
"65-Ryan-Young\n",
"66-Ava-King\n",
"67-Ethan-Wright\n",
"68-Mia-Scott\n",
"69-William-Turner\n",
"70-James-Carter\n",
"71-Olivia-Phillips\n",
"72-Lucas-Evans\n",
"73-Sophie-Collins\n",
"74-Noah-Stewart\n",
"75-Ava-Snyder\n",
"76-Ethan-Baker\n",
"77-Mia-Nelson\n",
"78-Noah-Roberts\n",
"79-Emma-Campbell\n",
"80-William-Miller\n",
"81-James-Davis\n",
"82-Olivia-Garcia\n",
"83-Lucas-Rodriguez\n",
"84-Sophie-Martinez\n",
"85-Noah-Hernandez\n",
"86-Ava-Lopez\n",
"87-Ethan-Gonzalez\n",
"88-Mia-Perez\n",
"89-William-Sanchez\n",
"90-James-Ramirez\n",
"91-Olivia-Flores\n",
"92-Lucas-Cruz\n",
"93-Isabella-Rivera\n",
"94-David-Lee\n",
"95-Sophie-Walker\n",
"96-Matthew-Hall\n",
"97-Emma-Allen\n",
"98-Ryan-Young\n",
"99-Ava-King\n",
"100-Ethan-Wright\n",
"101-Mia-Scott\n",
"102-William-Turner\n",
"103-James-Carter\n",
"104-Olivia-Phillips\n",
"105-Lucas-Evans\n",
"106-Sophie-Collins\n",
"107-Noah-Stewart\n",
"108-Ava-Snyder\n",
"109-Ethan-Baker\n",
"110-Mia-Nelson\n",
"111-Noah-Roberts\n",
"112-Emma-Campbell\n",
"113-William-Miller\n",
"114-James-Davis\n",
"115-Olivia-Garcia\n",
"116-Lucas-Rodriguez\n",
"117-Sophie-Martinez\n",
"118-Noah-Hernandez\n",
"119-Ava-Lopez\n",
"120-Ethan-Gonzalez\n",
"121-Mia-Perez\n",
"122-William-Sanchez\n",
"123-James-Ramirez\n",
"124-Olivia-Flores\n",
"125-Lucas-Cruz\n",
"126-Isabella-Rivera\n",
"127-David-Lee\n",
"128-Sophie-Walker\n",
"129-Matthew-Hall\n",
"130-Emma-Allen\n",
"131-Ryan-Young\n",
"132-Ava-King\n",
"133-Ethan-Wright\n",
"134-Mia-Scott\n",
"135-William-Turner\n",
"136-James-Carter\n",
"137-Olivia-Phillips\n",
"138-Lucas-Evans\n",
"139-Sophie-Collins\n",
"140-Noah-Stewart\n",
"141-Ava-Snyder\n",
"142-Ethan-Baker\n",
"143-Mia-Nelson\n",
"144-Noah-Roberts\n",
"145-Emma-Campbell\n",
"146-William-Miller\n",
"147-James-Davis\n",
"148-Olivia-Garcia\n",
"149-Lucas-Rodriguez\n",
"150-Sophie-Martinez\n",
"151-Noah-Hernandez\n",
"152-Ava-Lopez\n",
"153-Ethan-Gonzalez\n",
"154-Mia-Perez\n",
"155-William-Sanchez\n",
"156-James-Ramirez\n",
"157-Olivia-Flores\n",
"158-Lucas-Cruz\n",
"159-Isabella-Rivera\n",
"160-David-Lee\n",
"161-Sophie-Walker\n",
"162-Matthew-Hall\n",
"163-Emma-Allen\n",
"164-Ryan-Young\n",
"165-Ava-King\n",
"166-Ethan-Wright\n",
"167-Mia-Scott\n",
"168-William-Turner\n",
"169-James-Carter\n",
"170-Olivia-Phillips\n",
"171-Lucas-Evans\n",
"172-Sophie-Collins\n",
"173-Noah-Stewart\n",
"174-Ava-Snyder\n",
"175-Ethan-Baker\n",
"176-Mia-Nelson\n",
"177-Noah-Roberts\n",
"178-Emma-Campbell\n",
"179-William-Miller\n",
"180-James-Davis\n",
"181-Olivia-Garcia\n",
"182-Lucas-Rodriguez\n",
"183-Sophie-Martinez\n",
"184-Noah-Hernandez\n",
"185-Ava-Lopez\n",
"186-Ethan-Gonzalez\n",
"187-Mia-Perez\n",
"188-William-Sanchez\n",
"189-James-Ramirez\n",
"190-Olivia-Flores\n",
"191-Lucas-Cruz\n",
"192-Isabella-Rivera\n",
"193-David-Lee\n",
"194-Sophie-Walker\n",
"195-Matthew-Hall\n",
"196-Emma-Allen\n",
"197-Ryan-Young\n",
"198-Ava-King\n",
"199-Ethan-Wright\n",
"200-Mia-Scott\n",
"201-William-Turner\n",
"202-James-Carter\n",
"203-Olivia-Phillips\n",
"204-Lucas-Evans\n",
"205-Sophie-Collins\n",
"206-Noah-Stewart\n",
"207-Ava-Snyder\n",
"208-Ethan-Baker\n",
"209-Mia-Nelson\n",
"210-Noah-Roberts\n",
"211-Emma-Campbell\n",
"212-William-Miller\n",
"213-James-Davis\n",
"214-Olivia-Garcia\n",
"215-Lucas-Rodriguez\n",
"216-Sophie-Martinez\n",
"217-Noah-Hernandez\n",
"218-Ava-Lopez\n",
"219-Ethan-Gonzalez\n",
"220-Mia-Perez\n",
"221-William-Sanchez\n",
"222-James-Ramirez\n",
"223-Olivia-Flores\n",
"224-Lucas-Cruz\n",
"225-Isabella-Rivera\n",
"226-David-Lee\n",
"227-Sophie-Walker\n",
"228-Matthew-Hall\n",
"229-Emma-Allen\n",
"230-Ryan-Young\n",
"231-Ava-King\n",
"232-Ethan-Wright\n",
"233-Mia-Scott\n",
"234-William-Turner\n",
"235-James-Carter\n",
"236-Olivia-Phillips\n",
"237-Lucas-Evans\n",
"238-Sophie-Collins\n",
"239-Noah-Stewart\n",
"240-Ava-Snyder\n",
"241-Ethan-Baker\n",
"242-Mia-Nelson\n",
"243-Noah-Roberts\n",
"244-Emma-Campbell\n",
"245-William-Miller\n",
"246-James-Davis\n",
"247-Olivia-Garcia\n",
"248-Lucas-Rodriguez\n",
"249-Sophie-Martinez\n",
"250-Noah-Hernandez\n",
"251-Ava-Lopez\n",
"252-Ethan-Gonzalez\n",
"253-Mia-Perez\n",
"254-William-Sanchez\n",
"255-James-Ramirez\n",
"256-Olivia-Flores\n",
"257-Lucas-Cruz\n",
"258-Isabella-Rivera\n",
"259-David-Lee\n",
"260-Sophie-Walker\n",
"261-Matthew-Hall\n",
"262-Emma-Allen\n",
"263-Ryan-Young\n",
"264-Ava-King\n",
"265-Ethan-Wright\n",
"266-Mia-Scott\n",
"267-William-Turner\n",
"268-James-Carter\n",
"269-Olivia-Phillips\n",
"270-Lucas-Evans\n",
"271-Sophie-Collins\n",
"272-Noah-Stewart\n",
"273-Ava-Snyder\n",
"274-Ethan-Baker\n",
"275-Mia-Nelson\n",
"276-Noah-Roberts\n",
"277-Emma-Campbell\n",
"278-William-Miller\n",
"279-James-Davis\n",
"280-Olivia-Garcia\n",
"281-Lucas-Rodriguez\n",
"282-Sophie-Martinez\n",
"283-Noah-Hernandez\n",
"284-Ava-Lopez\n",
"285-Ethan-Gonzalez\n",
"286-Mia-Perez\n",
"287-William-Sanchez\n",
"288-James-Ramirez\n",
"289-Olivia-Flores\n",
"290-Lucas-Cruz\n",
"291-Isabella-Rivera\n",
"292-David-Lee\n",
"293-Sophie-Walker\n",
"294-Matthew-Hall\n",
"295-Emma-Allen\n",
"296-Ryan-Young\n",
"297-Ava-King\n",
"298-Ethan-Wright\n",
"299-Mia-Scott\n",
"300-William-Turner\n",
"301-James-Carter\n",
"302-Olivia-Phillips\n",
"303-Lucas-Evans\n",
"304-Sophie-Collins\n",
"305-Noah-Stewart\n",
"306-Ava-Snyder\n",
"307-Ethan-Baker\n",
"308-Mia-Nelson\n",
"309-Noah-Roberts\n",
"310-Emma-Campbell\n",
"311-William-Miller\n",
"312-James-Davis\n",
"313-Olivia-Garcia\n",
"314-Lucas-Rodriguez\n",
"315-Sophie-Martinez\n",
"316-Noah-Hernandez\n",
"317-Ava-Lopez\n",
"318-Ethan-Gonzalez\n",
"319-Mia-Perez\n",
"320-William-Sanchez\n",
"321-James-Ramirez\n",
"322-Olivia-Flores\n",
"323-Lucas-Cruz\n",
"324-Isabella-Rivera\n",
"325-David-Lee\n",
"326-Sophie-Walker\n"
]
}
],
"source": [
"import pandas as pd\n",
"usecols = [\"Name\", \"Vorname\"]\n",
"air = pd.read_csv(\"regie_name.csv\", usecols=usecols)\n",
"\n",
"for count, (i, b) in enumerate(zip(air[\"Name\"], air[\"Vorname\"])):\n",
" print(count, b, i, sep=\"-\")\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ee4b5dee-6b41-49eb-8d75-9db50d20fdef",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
+19
View File
@@ -0,0 +1,19 @@
FROM python:3.9-slim-bookworm
WORKDIR /app
# Install build dependencies for mariadb-connector-c
RUN apt-get update && apt-get install -y \
default-libmysqlclient-dev \
gcc \
pkg-config \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5082
CMD ["python3", "main.py"]
+116 -5
View File
@@ -1,7 +1,118 @@
Folgende Punkte
# Movie-DB
- erstellen eine SQlite DB
- Die DB soll folgende Tabellen haben Genre, MyList,
- Die Anzeige soll über Flask angezeigt werden
Eine webbasierte Anwendung zur Verwaltung einer persönlichen Filmsammlung.
Weitere Schritte folgen !!!
## Funktionsumfang (Features)
* **Benutzer-System:** Vollständiges Registrierungs- und Login-System, sodass jeder Benutzer seine eigene, private Filmsammlung verwalten kann.
* **Persönliche Filmlisten:** Jeder Benutzer sieht und durchsucht nur die Filme, die er selbst hinzugefügt hat.
* **Filme hinzufügen:** Filme können manuell oder durch ein automatisiertes Scraping von IMDb hinzugefügt werden.
* **Umfassende Suche:** Eine globale Suchleiste ermöglicht die gleichzeitige Suche nach Titel, Genre und Regisseur.
* **Paginierung:** Die Filmliste ist in Seiten aufgeteilt, um auch bei großen Sammlungen übersichtlich zu bleiben.
* **Sichere Verbindung:** Die Anwendung wird über HTTPS mit einem selbst-signierten SSL-Zertifikat bereitgestellt.
* **Containerisierung:** Die gesamte Anwendung ist mit Docker und Docker Compose containerisiert, was die Bereitstellung vereinfacht.
* **Automatisierte Bereitstellung:** Ein Ansible-Playbook automatisiert das Deployment der Anwendung.
## Voraussetzungen
Stellen Sie sicher, dass die folgende Software auf Ihrem System installiert ist:
* Python 3
* pip
* Docker
* Docker Compose
* Ansible
## Inbetriebnahme
Es gibt drei Möglichkeiten, die Anwendung zu starten.
### 1. Direkter Start mit Python
Dies ist die klassische Methode für die lokale Entwicklung.
1. **Abhängigkeiten installieren:**
```bash
pip install -r requirements.txt
```
2. **Anwendung starten:**
```bash
python3 main.py
```
3. **Zugriff:** Öffnen Sie Ihren Browser und gehen Sie zu `https://localhost:5082`. Sie müssen eine Browser-Warnung aufgrund des selbst-signierten Zertifikats akzeptieren.
### 2. Start mit Docker
Diese Methode kapselt die Anwendung in einem Container.
1. **Docker-Image erstellen:**
```bash
docker build -t movie-db-app .
```
2. **Docker-Container starten:**
```bash
docker run -p 5082:5082 movie-db-app
```
3. **Zugriff:** Öffnen Sie Ihren Browser und gehen Sie zu `https://localhost:5082`.
### 3. Start mit Ansible und Docker Compose (Empfohlen)
Dies ist die automatisierte Methode, die einen sauberen Deployment-Prozess sicherstellt.
1. **Ansible Docker-Sammlung installieren (falls noch nicht geschehen):**
```bash
ansible-galaxy collection install community.docker
```
2. **Ansible-Playbook ausführen:**
```bash
ansible-playbook start.yml
```
(Möglicherweise müssen Sie Ihr `sudo`-Passwort eingeben.)
3. **Zugriff:** Öffnen Sie Ihren Browser und gehen Sie zu `https://localhost:5082`.
## Projektstruktur
Die wichtigsten Dateien und Ordner im Überblick:
```
.
├── Dockerfile
├── docker-compose.yml
├── main.py
├── moviedb_func.py
├── movie_db.db
├── README.md
├── requirements.txt
├── start.yml
├── cert.pem
├── key.pem
└── templates/
├── base.html
├── index.html
├── login.html
└── register.html
```
* `main.py`: Die Hauptdatei der Flask-Anwendung. Sie enthält die Routen und die Anwendungslogik.
* `moviedb_func.py`: Enthält die gesamte Geschäftslogik, Datenbankfunktionen und die `User`-Klasse.
* `templates/`: Der Ordner für alle HTML-Templates.
* `movie_db.db`: Die SQLite-Datenbankdatei.
* `Dockerfile`: Die Bauanleitung für das Docker-Image der Anwendung.
* `docker-compose.yml`: Definiert die Anwendung als Docker-Dienst für eine einfache Verwaltung.
* `start.yml`: Das Ansible-Playbook für die automatisierte Bereitstellung.
* `requirements.txt`: Liste der Python-Abhängigkeiten.
* `cert.pem`, `key.pem`: Das selbst-signierte SSL-Zertifikat und der private Schlüssel.
## Benutzung
1. **Registrieren:** Erstellen Sie auf der Registrierungsseite einen neuen Benutzeraccount.
2. **Einloggen:** Melden Sie sich mit Ihren neuen Zugangsdaten an.
3. **Filme hinzufügen:** Nutzen Sie den "Film hinzufügen"-Button, um Filme entweder durch die IMDb-Suche oder manuell zu Ihrer Sammlung hinzuzufügen.
4. **Suchen:** Verwenden Sie die Suchleiste, um Ihre Sammlung nach Titeln, Genres oder Regisseuren zu durchsuchen.
## Mögliche zukünftige Erweiterungen
* **Bearbeiten & Löschen:** Funktionen zum Bearbeiten und Löschen von bereits hinzugefügten Filmen.
* **Detailseite:** Eine eigene Seite für jeden Film mit mehr Details (Schauspieler, Handlung, etc.).
* **Sortieroptionen:** Die Möglichkeit, die Filmliste nach verschiedenen Kriterien zu sortieren.
Binary file not shown.
+29
View File
@@ -0,0 +1,29 @@
-----BEGIN CERTIFICATE-----
MIIFCTCCAvGgAwIBAgIUDplU7xn71S8Rb5v7dXQ9cZmD1S4wDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MDgyNjExNTIwMVoXDTI2MDgy
NjExNTIwMVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF
AAOCAg8AMIICCgKCAgEA0J1PNqsrg+BL/zy7nTaRwfP96gGGvnQtHFHBifX7qF6e
bXKvxU77tGE9D0i5t36N2ktMl6PGI2CmhFz5mkcVrXnfWGLoYV2jLlYQOdKvwFJo
7R4QuGa8nLHLdGUkhSSgRxkol9rHUcok5ZpfA1iVFbrpgqel3Lmh0h3qXx7YiPTo
Y8ZhFQDoF4TXJYGrSC2BlAtbOSwT/L/n983VIA3dugzQ+3H78OWmfGcCB8Q8d5hN
FP+igWj/29U3vCmvlgXpzaM+X1TtL9uxqm/GWw/+jIj4Wn+2mxhMFS2B/OeWEW5y
oTYvZywK/eap9ieyKpzi+lND3eTvD+icpj1hFBt5qa+R9P1bj369q6IMSxNrf5YJ
cDesywy5MIIAPN+21nNYi13ZSwSnfEI/13klBk0rdhBulDAPGvH1DZEAc4ePagMQ
uhJtW6wl50yNJADxszAa1mbIIk/v7r+vPt32XTylqlaI3koU2XjjmyXcsAFLdgcS
ymCtxNWe37U58qb1J3QKDbaskq6kJiJBWZlASa3ANp19UdWvAnuznhhfXws0cV6b
qFoeKKkyWOsPln+Ifuw1VONJOMJmoT4L+kHuKnMDqdusuGdIlJXfeW00vMLIRx8O
8j8dUHfFqWRnE98VO9WZlsbagYgW96n9zyeZvfW3VgncrqMVZYC2YadbSH+hG40C
AwEAAaNTMFEwHQYDVR0OBBYEFIp7yQD9oKNeYS2hFMBzgIQWoZzGMB8GA1UdIwQY
MBaAFIp7yQD9oKNeYS2hFMBzgIQWoZzGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
hvcNAQELBQADggIBAHQpvGXNoeHjmVxuMmZSuiccOdfJXiWBTM7g7Eqq0nzTuzK/
IvmBkTxK8BG1j9X+9vBDJ3KZAIMVviepqxUNMGMQNa9DcVnOxaB01UdRqM9hh+jg
EkBgN325BgrX5Vh/HS7MX2VboM+WmBcfWtt3afKv2Tv2mzZ6bPPDdbH/SJouxfXD
Ea+n3IXniskmY7kUVTy7uRQUAJXyLulcrXAJgOwws80JEXrrjZwcpt9PxzzxXu4c
TUZQ1A5FgHgXecYM1WJA9nQr7NH9TewssKaoYOEltwOxbqc0bxAOtFX02dSTpRY/
0LwLC1Nqm34c96CX1t/WLfWf/RY2j5FoqFKxOY6CnpCW4DXjMZ3OEPmikT6XJ85G
q9LB4AqT/G1cyQzoT78SwDk6Ln3ahzP0MiaQeZ/KBJbqnfxOtcDWAmRTtIPYpMYH
eW8K+Y0Z3UvR+FqawuR5pvz5T/XYC/tutK4+KLCecorruT/Ye5qEALb+XcugU5iE
3FeZ/iAUxn8UKAGtfogQHYMOZ5lllAgRCKYhEYp28Rlkrk9LBXPzMimUfPZ2RSwx
XSkTYZEFEMw+4YQdOGqesW/hGpG6Ojmb/bmqG5TAzTdFUXsc6YgrJIP7lCIkEBnb
jF+S8Yb9Gq1s3ohiyI71kdVoOgWUGbqkkQ9xEZQzRzB1zcOLKelpdI7BEkjE
-----END CERTIFICATE-----
+10
View File
@@ -0,0 +1,10 @@
services:
web:
build: .
container_name: movie-db-web
ports:
- "5082:5082"
volumes:
- .:/app
restart: always
# command: python3 main.py # Use this if you want to run in foreground for debugging
+59
View File
@@ -0,0 +1,59 @@
# Benötigt die Installation von 'requests' und 'beautifulsoup4'
# pip install requests beautifulsoup4
import requests
from bs4 import BeautifulSoup
import sys
import re
def suche_film_url(film_titel):
"""
Sucht auf IMDb nach einem Film und gibt die deutsche URL der Filmseite zurück.
Args:
film_titel: Der Titel des Films, nach dem gesucht werden soll.
Returns:
Die deutsche URL der Filmseite oder None, wenn nichts gefunden wurde.
"""
such_url = f"https://www.imdb.com/find?q={film_titel.replace(' ', '+')}"
# Header, um die deutsche Seite zu bevorzugen
headers = {
'Accept-Language': 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'
}
try:
response = requests.get(such_url, headers=headers)
response.raise_for_status() # Löst eine Ausnahme für HTTP-Fehler aus
soup = BeautifulSoup(response.text, 'html.parser')
# Finden des ersten Links im Titel-Ergebnisbereich
ergebnis_bereich = soup.find('section', {'data-testid': 'find-results-section-title'})
if ergebnis_bereich:
link_tag = ergebnis_bereich.find('a', href=re.compile(r'/title/tt\d+'))
if link_tag and 'href' in link_tag.attrs:
pfad = link_tag['href']
# Extrahieren der Titel-ID (z.B. tt0133093)
match = re.search(r'(tt\d+)', pfad)
if match:
titel_id = match.group(1)
return f"https://www.imdb.com/de/title/{titel_id}"
except requests.exceptions.RequestException as e:
print(f"Ein Fehler bei der Anfrage ist aufgetreten: {e}")
return None
return None
if __name__ == "__main__":
if len(sys.argv) > 1:
film_name = " ".join(sys.argv[1:])
url = suche_film_url(film_name)
if url:
print(f"URL für '{film_name}' gefunden: {url}")
else:
print(f"Konnte keinen Film mit dem Titel '{film_name}' finden.")
else:
print("Benutzung: python imdb_suche.py <film_titel>")
+52
View File
@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
krvHLxyb9R+o1UzlvYkUiF+lOMVpLB8=
-----END PRIVATE KEY-----
+96 -28
View File
@@ -1,59 +1,127 @@
import flask
from flask import render_template, redirect, url_for, flash
from flask_login import LoginManager, login_user, logout_user, login_required, current_user
import moviedb_func
app = flask.Flask(__name__)
app.secret_key = "Start1234!"
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "login"
@login_manager.user_loader
def load_user(user_id):
return moviedb_func.get_user_by_id(user_id)
@app.route("/register", methods=["GET", "POST"])
def register():
if flask.request.method == "POST":
username = flask.request.form.get("username")
password = flask.request.form.get("password")
if moviedb_func.get_user_by_username(username):
flash("Benutzername existiert bereits")
return redirect(url_for("register"))
moviedb_func.add_user(username, password)
return redirect(url_for("login"))
return render_template("register.html")
@app.route("/login", methods=["GET", "POST"])
def login():
if flask.request.method == "POST":
username = flask.request.form.get("username")
password = flask.request.form.get("password")
user = moviedb_func.get_user_by_username(username)
if user and user.check_password(password):
login_user(user)
return redirect(url_for("index"))
flash("Ungültiger Benutzername oder Passwort")
return render_template("login.html")
@app.route("/logout")
@login_required
def logout():
logout_user()
return redirect(url_for("login"))
@app.route("/", methods=["GET", "POST"])
@login_required
def index():
page = flask.request.args.get('page', 1, type=int)
per_page = 20
search_query = None
if flask.request.method == "POST":
search_query = flask.request.form.get("search")
else:
search_query = flask.request.args.get("search")
data_all, total_pages = moviedb_func.show_movie_list(user_id=current_user.id, search_query=search_query, page=page, per_page=per_page)
return render_template(
"index.html",
sitename="Meine Movieliste !!!",
data_all=data_all,
total_pages=total_pages,
current_page=page,
search_query=search_query
)
@app.get("/add_movie")
def add_movie():
return flask.render_template(
return render_template(
"add_movie.html",
sitename="Meine Movieliste !!!",
url="output",
select_movie="add_movie",
select_genre="add_genre",
select_medium="add_medium",
select_regie="add_regie",
data=moviedb_func.all_select(),
data_medium=moviedb_func.all_select(what_select="medium"),
data_regie=moviedb_func.all_select(what_select="regie"),
data_all=moviedb_func.show_movie_list()
data_medium=moviedb_func.all_select(what_select="medium")
)
@app.post("/output")
@login_required
def csv_output():
select_add_movie = flask.request.form["add_movie"]
select_genre = flask.request.form["add_genre"]
select_genre_id = moviedb_func.search_id(
search_name=flask.request.form["add_genre"])
select_medium = flask.request.form["add_medium"]
select_medium_id = moviedb_func.search_id(
search_name=flask.request.form["add_medium"], select_from="medium", select_where="medium")
select_regie = flask.request.form["add_regie"]
select_regie_id = moviedb_func.search_id(
search_name=flask.request.form["add_regie"], select_from="regie", select_where="regie")
search_name=select_medium, select_from="medium", select_where="medium")
moviedb_func.add_movie_to_list(movie_name=select_add_movie, regie_id=select_regie_id,
medium_id=select_medium_id, genre_id=select_genre_id)
if moviedb_func.scrape_and_add_movie(movie_name=select_add_movie,
medium_id=select_medium_id, user_id=current_user.id):
return redirect(url_for('index'))
else:
return redirect(url_for('add_movie_manually', movie_name=select_add_movie, medium_id=select_medium_id))
return flask.render_template(
"output.html",
sitename="Meine Movieliste !!!",
add_movie=select_add_movie,
add_genre=select_genre,
add_medium=select_medium,
add_regie=select_regie,
add_genre_id=select_genre_id,
add_medium_id=select_medium_id,
add_regie_id=select_regie_id
# data=modify_csv.read_csv_file(),
# sum_all=modify_csv.sum_all(),
@app.get("/add_movie_manually")
@login_required
def add_movie_manually():
movie_name = flask.request.args.get('movie_name')
medium_id = flask.request.args.get('medium_id')
return render_template(
"add_movie_manually.html",
sitename="Manuelle Eingabe",
movie_name=movie_name,
medium_id=medium_id
)
@app.post("/save_manual")
@login_required
def save_manual():
movie_name = flask.request.form["movie_name"]
medium_id = flask.request.form["medium_id"]
director_name = flask.request.form["director_name"]
release_year = flask.request.form["release_year"]
genre_name = flask.request.form["genre_name"]
moviedb_func.add_manual_movie(movie_name=movie_name, medium_id=int(medium_id), director_name=director_name, release_year=int(release_year), genre_name=genre_name, user_id=current_user.id)
return redirect("/")
if __name__ == "__main__":
app.run(port=5082, host="0.0.0.0", debug=True)
moviedb_func.create_movie_database()
app.run(port=5082, host="0.0.0.0", debug=True, ssl_context=('cert.pem', 'key.pem'))
Binary file not shown.
+275 -23
View File
@@ -2,17 +2,103 @@ import DBcm
from mariadb import ProgrammingError
import pandas as pd
import sqlite3
import urllib.request
import json
import re
import ssl
import imdb_suche
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
def get_movie_details(imdb_url):
"""
Ruft eine IMDb-Filmseite auf und extrahiert den Regisseur und die Hauptdarsteller.
Args:
imdb_url (str): Die vollständige URL zur IMDb-Filmseite.
Returns:
dict: Ein Wörterbuch mit "director" und "actors" oder None bei einem Fehler.
"""
if not re.match(r"https://www.imdb.com/de/title/tt\d+/?", imdb_url):
print(f"Fehler: Ungültige IMDb-URL: {imdb_url}. Die URL sollte so aussehen: https://www.imdb.com/de/title/tt...")
return None
try:
# SSL-Kontext erstellen, um Zertifikatsüberprüfungsfehler zu umgehen
context = ssl._create_unverified_context()
# User-Agent setzen, um wie ein Browser auszusehen und Blockaden zu vermeiden
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'}
req = urllib.request.Request(imdb_url, headers=headers)
with urllib.request.urlopen(req, context=context) as response:
html_content = response.read().decode('utf-8')
# Suchen Sie nach dem strukturierten Datenblock (JSON-LD), der Filminformationen enthält
match = re.search(
r'<script type="application/ld\+json">(.*?)</script>', html_content, re.DOTALL)
if not match:
print("Fehler: Konnte den JSON-LD-Datenblock auf der Seite nicht finden.")
return None
json_data = json.loads(match.group(1))
# Extrahieren des Regisseurs
director = [d.get('name') for d in json_data.get("director", [])] if isinstance(
json_data.get("director"), list) else [json_data.get("director", {}).get("name")]
# Extrahieren der Schauspieler
actors = [a.get('name') for a in json_data.get("actor", [])]
# Extrahieren des Erscheinungsjahres
release_year = json_data.get("datePublished", "").split("-")[0]
# Extrahieren des Genres
genre = json_data.get("genre", [])
if isinstance(genre, list):
genre = ", ".join(genre)
return {
"director": [d for d in director if d],
"actors": [a for a in actors if a],
"release_year": release_year,
"genre": genre
}
except urllib.error.HTTPError as e:
print(f"HTTP-Fehler beim Abrufen der URL: {e.code} {e.reason}")
return None
except Exception as e:
print(f"Ein Fehler ist aufgetreten: {e}")
return None
def create_movie_database(db_name="movie_db.db"):
create_user_table = """
CREATE TABLE IF NOT EXISTS user (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
username VARCHAR(64) NOT NULL UNIQUE,
password_hash VARCHAR(128) NOT NULL
);
"""
create_my_list = """
create table if not exists movie_list (
id integer not null primary key autoincrement,
titel varchar(64) not null,
genre_id integer not null,
regie_id integer not null,
medium_id integer not null
regie_id integer,
medium_id integer not null,
release_year integer,
user_id integer not null,
FOREIGN KEY (user_id) REFERENCES user (id)
)
"""
@@ -60,6 +146,7 @@ def create_movie_database(db_name="movie_db.db"):
"""
with DBcm.UseDatabase(db_name) as db:
db.execute(create_user_table)
db.execute(create_my_list)
db.execute(create_genre)
db.execute(create_regie)
@@ -104,7 +191,39 @@ def all_select(db_name="movie_db.db", what_select="genre"):
return "Wrong Value !!!"
def search_id(db_name="movie_db.db", search_name=str, select_from="genre", select_where="name"):
def get_or_create_regie(director_name: str, db_name: str = "movie_db.db"):
ADD_REGIE_VALUE = """
INSERT INTO regie (surname, lastname )
SELECT ?, ?
WHERE NOT EXISTS
(SELECT surname, lastname
FROM regie
WHERE surname = ? AND lastname = ?);
"""
director_split = director_name.split(" ")
surname = director_split[0]
lastname = " ".join(director_split[1:])
with DBcm.UseDatabase(db_name) as db:
db.execute(ADD_REGIE_VALUE, (surname, lastname, surname, lastname))
db.execute("SELECT id FROM regie WHERE surname = ? AND lastname = ?", (surname, lastname))
regie_id = db.fetchone()[0]
return regie_id
def get_or_create_genre(genre_name: str, db_name: str = "movie_db.db"):
ADD_GENRE_VALUE = """
INSERT INTO genre(name)
SELECT ?
WHERE NOT EXISTS (SELECT 1 FROM genre WHERE name = ?);
"""
with DBcm.UseDatabase(db_name) as db:
db.execute(ADD_GENRE_VALUE, (genre_name, genre_name))
db.execute("SELECT id FROM genre WHERE name = ?", (genre_name,))
genre_id = db.fetchone()[0]
return genre_id
def search_id(search_name: str, select_from: str = "genre", select_where: str = "name", db_name: str = "movie_db.db"):
if select_from == "regie":
split_search = search_name.split(" ")
GENRE_QUERY = f"""select id from {select_from}
@@ -125,43 +244,176 @@ def search_id(db_name="movie_db.db", search_name=str, select_from="genre", selec
return int(0)
def add_movie_to_list(db_name="movie_db.db", movie_name=str, genre_id=int, regie_id=int, medium_id=int):
def scrape_and_add_movie(movie_name: str, medium_id: int, user_id: int, db_name: str = "movie_db.db"):
url = imdb_suche.suche_film_url(movie_name)
if not url:
return False
details = get_movie_details(url + "/")
if not details:
return False
regie_id = None
if details.get("director"):
regie_id = get_or_create_regie(director_name=details["director"][0])
release_year = details.get("release_year")
genre_name = details.get("genre")
genre_id = None
if genre_name:
genre_id = get_or_create_genre(genre_name=genre_name)
SQL_PARAM = f"""
INSERT INTO movie_list (titel, genre_id, regie_id, medium_id )
SELECT ?, ?, ?, ?
WHERE NOT EXISTS
(SELECT titel FROM movie_list WHERE titel = ?);
INSERT INTO movie_list (titel, genre_id, regie_id, medium_id, release_year, user_id)
VALUES (?, ?, ?, ?, ?, ?);
"""
try:
with DBcm.UseDatabase(db_name) as db:
db.execute(SQL_PARAM, (movie_name.lower(), genre_id,
regie_id, medium_id, movie_name.lower(),))
except ProgrammingError:
raise ProgrammingError("Konnte nicht in die DB schreiben")
regie_id, medium_id, release_year, user_id,))
except ProgrammingError as e:
print(f"Error adding movie: {e}")
return False
return True
def show_movie_list(db_name="movie_db.db"):
def add_manual_movie(movie_name: str, medium_id: int, director_name: str, release_year: int, genre_name: str, user_id: int, db_name: str = "movie_db.db"):
regie_id = get_or_create_regie(director_name=director_name)
genre_id = get_or_create_genre(genre_name=genre_name)
SQL_PARAM = f"""
INSERT INTO movie_list (titel, genre_id, regie_id, medium_id, release_year, user_id)
VALUES (?, ?, ?, ?, ?, ?);
"""
try:
with DBcm.UseDatabase(db_name) as db:
db.execute(SQL_PARAM, (movie_name.lower(), genre_id,
regie_id, medium_id, release_year, user_id,))
except ProgrammingError as e:
print(f"Error adding movie: {e}")
return False
return True
def show_movie_list(db_name="movie_db.db", user_id=None, search_query=None, page=1, per_page=20):
"""Zeigt eine paginierte Liste von Filmen an, die nach einem Suchbegriff gefiltert werden können."""
# Basis-SQL-Abfrage
SQL_BASE = """FROM movie_list
INNER JOIN genre ON movie_list.genre_id=genre.id
INNER JOIN regie ON movie_list.regie_id=regie.id
INNER JOIN medium ON movie_list.medium_id=medium.id"""
# Filter-Bedingungen
params = []
where_clauses = []
if user_id:
where_clauses.append("movie_list.user_id = ?")
params.append(user_id)
if search_query:
search_param = f"%{search_query}%"
where_clauses.append("(titel LIKE ? OR genre.name LIKE ? OR (regie.surname || ' ' || regie.lastname) LIKE ?)")
params.extend([search_param, search_param, search_param])
SQL_WHERE = ""
if where_clauses:
SQL_WHERE = " WHERE " + " AND ".join(where_clauses)
# Verbindung zur Datenbank
db = sqlite3.connect(db_name)
# Gesamtzahl der Filme für die Paginierung ermitteln
COUNT_SQL = f"SELECT COUNT(movie_list.id) {SQL_BASE}{SQL_WHERE}"
total_movies = db.execute(COUNT_SQL, params).fetchone()[0]
total_pages = (total_movies + per_page - 1) // per_page
# Filme für die aktuelle Seite abrufen
offset = (page - 1) * per_page
SELECT_SQL = f"""SELECT
movie_list.id,
titel,
genre.name AS genre,
regie.surname as regie_surname,
regie.lastname as regie_lastname,
medium.medium,
movie_list.release_year
{SQL_BASE}{SQL_WHERE}
LIMIT ? OFFSET ?"""
paginated_params = params + [per_page, offset]
SELCET_VALUE = pd.read_sql(SELECT_SQL, db, params=paginated_params)
# Ergebnis in eine Liste von Dictionaries umwandeln
return_list_dict = []
for id, titel, genre, regie_surname, regie_lastname, medium, release_year in zip(SELCET_VALUE["id"], SELCET_VALUE["titel"], SELCET_VALUE["genre"], SELCET_VALUE["regie_surname"], SELCET_VALUE["regie_lastname"], SELCET_VALUE["medium"], SELCET_VALUE["release_year"]):
return_list_dict.append(
{"id": id, "titel": titel, "genre": genre, "regie": regie_surname + " " + regie_lastname, "medium": medium, "release_year": release_year})
return return_list_dict, total_pages
def get_movie_by_title(movie_title: str, db_name: str = "movie_db.db"):
SQL_PARAM = f"""SELECT
movie_list.id,
titel,
genre.name AS genre,
regie.surname as regie_surname,
regie.lastname as regie_lastname,
medium.medium
medium.medium,
movie_list.release_year
FROM movie_list
INNER JOIN genre ON movie_list.genre_id=genre.id
INNER JOIN regie ON movie_list.regie_id=regie.id
INNER JOIN medium ON movie_list.medium_id=medium.id
WHERE movie_list.titel = ?
;
"""
db = sqlite3.connect(db_name)
SELCET_VALUE = pd.read_sql(SQL_PARAM, db)
return_list_dict = []
for id, titel, genre, regie_surname, regie_lastname, medium in zip(SELCET_VALUE["id"], SELCET_VALUE["titel"], SELCET_VALUE["genre"], SELCET_VALUE["regie_surname"], SELCET_VALUE["regie_lastname"], SELCET_VALUE["medium"]):
return_list_dict.append(
{"id": id, "titel": titel, "genre": genre, "regie": regie_surname + " " + regie_lastname, "medium": medium})
return return_list_dict
with DBcm.UseDatabase(db_name) as db:
db.execute(SQL_PARAM, (movie_title.lower(),))
movie = db.fetchone()
if movie:
return {"id": movie[0], "titel": movie[1], "genre": movie[2], "regie": movie[3] + " " + movie[4], "medium": movie[5], "release_year": movie[6]}
return None
class User(UserMixin):
def __init__(self, id, username, password_hash):
self.id = id
self.username = username
self.password_hash = password_hash
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
def add_user(username, password, db_name="movie_db.db"):
password_hash = generate_password_hash(password)
SQL = "INSERT INTO user (username, password_hash) VALUES (?, ?)"
with DBcm.UseDatabase(db_name) as db:
db.execute(SQL, (username, password_hash))
def get_user_by_username(username, db_name="movie_db.db"):
SQL = "SELECT * FROM user WHERE username = ?"
with DBcm.UseDatabase(db_name) as db:
db.execute(SQL, (username,))
user_data = db.fetchone()
if user_data:
return User(id=user_data[0], username=user_data[1], password_hash=user_data[2])
return None
def get_user_by_id(user_id, db_name="movie_db.db"):
SQL = "SELECT * FROM user WHERE id = ?"
with DBcm.UseDatabase(db_name) as db:
db.execute(SQL, (user_id,))
user_data = db.fetchone()
if user_data:
return User(id=user_data[0], username=user_data[1], password_hash=user_data[2])
return None
if __name__ == "__main__":
@@ -169,7 +421,7 @@ if __name__ == "__main__":
# print(all_select())
# id_genre = search_id(
# search_name="DVD", select_from="medium", select_where="medium")
add_movie_to_list(movie_name="Schlumpfland",
genre_id=1, regie_id=1, medium_id=1)
scrape_and_add_movie(movie_name="Die unglaubliche Reise in einem verrückten Flugzeug",
medium_id=1)
for test in show_movie_list():
print(test.get("id"), test.get("medium"))
print(test.get("id"), test.get("medium"), test.get("release_year"))
+4
View File
@@ -1,2 +1,6 @@
flask
dbcm
pandas
requests
beautifulsoup4
Flask-Login
+28
View File
@@ -0,0 +1,28 @@
---
- name: Deploy and start Movie-DB Application
hosts: localhost
connection: local
become: yes
vars:
project_name: movie-db
install_dir: "/opt/{{ project_name }}"
project_src: "{{ playbook_dir }}"
tasks:
- name: Create installation directory
ansible.builtin.file:
path: "{{ install_dir }}"
state: directory
mode: '0755'
- name: Copy docker-compose file
ansible.builtin.copy:
src: "{{ project_src }}/docker-compose.yml"
dest: "{{ install_dir }}/docker-compose.yml"
- name: Start application with Docker Compose
community.docker.docker_compose:
project_src: "{{ install_dir }}"
state: present
restarted: yes
+17 -47
View File
@@ -1,50 +1,20 @@
{% extends "base.html" %}
{% block body %}
<form action="{{ url }}" method="POST">
<input type="text"
placeholder="Movie"
name="{{ select_movie }}"
id="{{ select_movie }}">
&nbsp;
<select name="{{ select_genre }}" id="{{ select_genre }}">
{% for name in data %}
<option value="{{ name }}">{{ name }}</option>
{% endfor %}
</select>
&nbsp;
<select name="{{ select_medium }}" id="{{ select_medium }}">
{% for name in data_medium %}
<option value="{{ name }}">{{ name }}</option>
{% endfor %}
</select>
&nbsp;
<select name="{{ select_regie }}" id="{{ select_regie }}">
{% for name in data_regie %}
<option value="{{ name }}">{{ name }}</option>
{% endfor %}
</select>
&nbsp;
<button type="submit"> Eingabe </button>
<form action="{{ url }}" method="POST" class="mb-3">
<div class="mb-3">
<input type="text"
class="form-control"
placeholder="Movie"
name="{{ select_movie }}"
id="{{ select_movie }}">
</div>
<div class="mb-3">
<select name="{{ select_medium }}" id="{{ select_medium }}" class="form-select">
{% for name in data_medium %}
<option value="{{ name }}">{{ name }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary">Eingabe</button>
</form>
<br>
<table border="1" width="50%">
<tr>
<th>Id</th>
<th>Name</th>
<th>Genre</th>
<th>Regie</th>
<th>Medium</th>
</tr>
{% for list_all in data_all %}
<tr>
<td>{{list_all.get("id")}}</td>
<td>{{list_all.get("titel")}}</td>
<td>{{list_all.get("genre")}}</td>
<td>{{list_all.get("regie")}}</td>
<td>{{list_all.get("medium")}}</td>
</tr>
{% endfor %}
</table>
{% endblock %}
{% endblock %}
@@ -0,0 +1,22 @@
{% extends "base.html" %}
{% block body %}
<h3 class="mb-3">Film nicht gefunden. Bitte manuell eingeben:</h3>
<form action="/save_manual" method="POST">
<input type="hidden" name="movie_name" value="{{ movie_name }}">
<input type="hidden" name="medium_id" value="{{ medium_id }}">
<div class="mb-3">
<label for="genre_name" class="form-label">Genre:</label>
<input type="text" class="form-control" id="genre_name" name="genre_name" required>
</div>
<div class="mb-3">
<label for="director_name" class="form-label">Regisseur:</label>
<input type="text" class="form-control" id="director_name" name="director_name" required>
</div>
<div class="mb-3">
<label for="release_year" class="form-label">Erscheinungsjahr:</label>
<input type="number" class="form-control" id="release_year" name="release_year" required>
</div>
<button type="submit" class="btn btn-primary">Speichern</button>
</form>
{% endblock %}
+36 -12
View File
@@ -1,12 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<title> {{ sitename }} </title>
</head>
<body>
<h2> {{ sitename }} </h2>
<p> Es werden alle Filmtitel in einer Liste angezeigt.
{% block body %}
{% endblock %}
</body>
</html>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ sitename }}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for('index') }}">{{ sitename }}</a>
<div class="collapse navbar-collapse">
<ul class="navbar-nav ms-auto">
{% if current_user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('logout') }}">Logout</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('login') }}">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('register') }}">Registrieren</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<div class="container mt-4">
{% block body %}{% endblock %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>
</html>
+60
View File
@@ -0,0 +1,60 @@
{% extends "base.html" %}
{% block body %}
<a href="/add_movie" class="btn btn-primary mb-3">Film hinzufügen</a>
<form method="post" action="{{ url_for('index') }}">
<div class="row mb-3">
<div class="col">
<label for="search" class="form-label">Suche</label>
<input type="text" name="search" id="search" class="form-control" value="{{ search_query }}">
</div>
</div>
<button type="submit" class="btn btn-primary">Suchen</button>
</form>
<table class="table table-striped table-bordered mt-3">
<thead class="table-dark">
<tr>
<th>Id</th>
<th>Name</th>
<th>Genre</th>
<th>Regie</th>
<th>Medium</th>
<th>Erscheinungsjahr</th>
</tr>
</thead>
<tbody>
{% for list_all in data_all %}
<tr>
<td>{{list_all.get("id")}}</td>
<td>{{list_all.get("titel")}}</td>
<td>{{list_all.get("genre")}}</td>
<td>{{list_all.get("regie")}}</td>
<td>{{list_all.get("medium")}}</td>
<td>{{list_all.get("release_year")}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<nav aria-label="Page navigation">
<ul class="pagination">
<li class="page-item {% if current_page == 1 %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('index', page=1, search=search_query) }}">Erste</a>
</li>
<li class="page-item {% if current_page == 1 %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('index', page=current_page - 1, search=search_query) }}">Zurück</a>
</li>
<li class="page-item disabled">
<a class="page-link" href="#">Seite {{ current_page }} von {{ total_pages }}</a>
</li>
<li class="page-item {% if current_page == total_pages %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('index', page=current_page + 1, search=search_query) }}">Weiter</a>
</li>
<li class="page-item {% if current_page == total_pages %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('index', page=total_pages, search=search_query) }}">Letzte</a>
</li>
</ul>
</nav>
{% endblock %}
+25
View File
@@ -0,0 +1,25 @@
{% extends "base.html" %}
{% block body %}
<div class="container">
<h2>Login</h2>
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="alert alert-danger">
{{ messages[0] }}
</div>
{% endif %}
{% endwith %}
<form method="post">
<div class="mb-3">
<label for="username" class="form-label">Benutzername</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Passwort</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
<p class="mt-3">Noch keinen Account? <a href="{{ url_for('register') }}">Hier registrieren</a>.</p>
</div>
{% endblock %}
-10
View File
@@ -1,10 +0,0 @@
{% extends "base.html" %}
{% block body %}
<p>
Film = {{ add_movie }} <br>
Genre = {{ add_genre }} <span>&nbsp genre_id = {{ add_genre_id }} <br>
Medium = {{ add_medium }} <span>&nbsp medium_id = {{add_medium_id }} <br>
Regie = {{ add_regie }} <span>&nbsp reg_id = {{ add_regie_id }} <br>
</p>
{% endblock %}
+18
View File
@@ -0,0 +1,18 @@
{% extends "base.html" %}
{% block body %}
<div class="container">
<h2>Registrieren</h2>
<form method="post">
<div class="mb-3">
<label for="username" class="form-label">Benutzername</label>
<input type="text" class="form-control" id="username" name="username" required>
</div>
<div class="mb-3">
<label for="password" class="form-label">Passwort</label>
<input type="password" class="form-control" id="password" name="password" required>
</div>
<button type="submit" class="btn btn-primary">Registrieren</button>
</form>
<p class="mt-3">Schon einen Account? <a href="{{ url_for('login') }}">Hier einloggen</a>.</p>
</div>
{% endblock %}
-650
View File
@@ -1,650 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "5263a987-da36-46d7-a2e7-d0658cda09c1",
"metadata": {},
"outputs": [],
"source": [
"import DBcm"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "3f6b0763-4106-4bfa-9aef-7afbd180c6d4",
"metadata": {},
"outputs": [],
"source": [
"db_name = \"movie_db.db\"\n",
"\n",
"create_my_list = \"\"\"\n",
" create table if not exists movie_list (\n",
" id integer not null primary key autoincrement,\n",
" titel varchar(64) not null,\n",
" genre_id integer not null,\n",
" regie_id integer not null\n",
" \n",
" )\n",
"\n",
"\"\"\"\n",
"\n",
"create_genre = \"\"\"\n",
" create table if not exists genre (\n",
" id integer not null primary key autoincrement,\n",
" name varchar(64) not null\n",
" )\n",
"\"\"\"\n",
"\n",
"create_regie = \"\"\"\n",
" create table if not exists regie (\n",
" id integer not null primary key autoincrement,\n",
" surname varchar(64) not null,\n",
" lastname varchr(64) not null\n",
" )\n",
"\"\"\"\n",
"\n",
"\n",
"with DBcm.UseDatabase(db_name) as db: \n",
" db.execute(create_my_list)\n",
" db.execute(create_genre)\n",
" db.execute(create_regie)\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "376ef812-97b5-45ba-8ef1-eb8d7829494a",
"metadata": {},
"outputs": [],
"source": [
"# ADDed Genre values\n",
"\n",
"ADD_GENRE_VALUE = \"\"\"\n",
" INSERT INTO genre(name)\n",
" SELECT ?\n",
" WHERE NOT EXISTS (SELECT 1 FROM genre WHERE name = ?);\n",
" \"\"\"\n",
"\n",
"with open(\"genre_list\", \"r\") as fs: \n",
" for genre_value in fs.readlines():\n",
" with DBcm.UseDatabase(db_name) as db:\n",
" db.execute(ADD_GENRE_VALUE, (genre_value.strip(), genre_value.strip()))\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "63b16a41-88bf-4832-a26c-09180832f597",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['action', 'adventure', 'animation', 'biography', 'comedy', 'crime', 'cult movie', 'disney', 'documentary', 'drama', 'erotic', 'family', 'fantasy', 'film-noir', 'gangster', 'gay and lesbian', 'history', 'horror', 'military', 'music', 'musical', 'mystery', 'nature', 'neo-noir', 'period', 'pixar', 'road movie', 'romance', 'sci-fi', 'short', 'spy', 'super hero', 'thriller', 'visually stunning', 'war', 'western']\n"
]
}
],
"source": [
"def all_genres():\n",
" ALL_GENRE = \"\"\"\n",
" SELECT * from genre \n",
" \"\"\" \n",
" with DBcm.UseDatabase(db_name) as db:\n",
" db.execute(ALL_GENRE)\n",
" all_genre = [i[1] for i in db.fetchall()]\n",
" \n",
" return all_genre\n",
"\n",
"print(all_genres())\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 36,
"id": "89b20b5f-34aa-4490-a4c0-c186c9fa30bd",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1\n",
"36\n"
]
}
],
"source": [
"def search_genre_id(genre_name):\n",
" GENRE_QUERY = \"\"\"\n",
" select id from genre\n",
" where name = ?\n",
" \"\"\"\n",
" try:\n",
" with DBcm.UseDatabase(db_name) as db:\n",
" db.execute(GENRE_QUERY,(genre_name,))\n",
" genre_id = db.fetchone()[0]\n",
" return int(genre_id)\n",
" except:\n",
" return int(0)\n",
"\n",
"\n",
"def search_medium_id(genre_name):\n",
" GENRE_QUERY = \"\"\"\n",
" select id from genre\n",
" where medium = ?\n",
" \"\"\"\n",
" try:\n",
" with DBcm.UseDatabase(db_name) as db:\n",
" db.execute(GENRE_QUERY,(genre_name,))\n",
" genre_id = db.fetchone()[0]\n",
" return int(genre_id)\n",
" except:\n",
" return int(0)\n",
"\n",
"print(search_genre_id(genre_name=\"action\"))\n",
"print(search_genre_id(genre_name=\"western\"))"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "c70d91a5-7855-465d-a4a6-daebc065ee37",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0-John-Smith\n",
"1-James-Johnson\n",
"2-William-Williams\n",
"3-Michael-Brown\n",
"4-David-Davis\n",
"5-Richard-Miller\n",
"6-Joseph-Wilson\n",
"7-Charles-Moore\n",
"8-Thomas-Taylor\n",
"9-Daniel-Anderson\n",
"10-Paul-Thomas\n",
"11-Mark-Jackson\n",
"12-Donna-White\n",
"13-Michelle-Harris\n",
"14-Laura-Martin\n",
"15-Sara-Thompson\n",
"16-Ana-Garcia\n",
"17-Carlos-Rodriguez\n",
"18-Maria-Martinez\n",
"19-Jose-Hernandez\n",
"20-Luis-Lopez\n",
"21-Rosa-Gonzalez\n",
"22-Pedro-Perez\n",
"23-Miguel-Sanchez\n",
"24-Juan-Ramirez\n",
"25-Ana-Flores\n",
"26-Isabella-Cruz\n",
"27-Victor-Rivera\n",
"28-Kevin-Lee\n",
"29-Brian-Walker\n",
"30-Emily-Hall\n",
"31-Ryan-Allen\n",
"32-Aaron-Young\n",
"33-Jeffrey-King\n",
"34-Joshua-Wright\n",
"35-Brandon-Scott\n",
"36-Frank-Turner\n",
"37-Gregory-Carter\n",
"38-Samuel-Phillips\n",
"39-Chris-Evans\n",
"40-Anthony-Collins\n",
"41-Eric-Stewart\n",
"42-Frank-Snyder\n",
"43-Thomas-Baker\n",
"44-Jeremy-Nelson\n",
"45-Steven-Roberts\n",
"46-Edward-Campbell\n",
"47-Ryan-Miller\n",
"48-Jacob-Davis\n",
"49-David-Garcia\n",
"50-Sophia-Rodriguez\n",
"51-Emma-Martinez\n",
"52-Noah-Hernandez\n",
"53-Ava-Lopez\n",
"54-Ethan-Gonzalez\n",
"55-Mia-Perez\n",
"56-William-Sanchez\n",
"57-James-Ramirez\n",
"58-Olivia-Flores\n",
"59-Lucas-Cruz\n",
"60-Isabella-Rivera\n",
"61-David-Lee\n",
"62-Sophie-Walker\n",
"63-Matthew-Hall\n",
"64-Emma-Allen\n",
"65-Ryan-Young\n",
"66-Ava-King\n",
"67-Ethan-Wright\n",
"68-Mia-Scott\n",
"69-William-Turner\n",
"70-James-Carter\n",
"71-Olivia-Phillips\n",
"72-Lucas-Evans\n",
"73-Sophie-Collins\n",
"74-Noah-Stewart\n",
"75-Ava-Snyder\n",
"76-Ethan-Baker\n",
"77-Mia-Nelson\n",
"78-Noah-Roberts\n",
"79-Emma-Campbell\n",
"80-William-Miller\n",
"81-James-Davis\n",
"82-Olivia-Garcia\n",
"83-Lucas-Rodriguez\n",
"84-Sophie-Martinez\n",
"85-Noah-Hernandez\n",
"86-Ava-Lopez\n",
"87-Ethan-Gonzalez\n",
"88-Mia-Perez\n",
"89-William-Sanchez\n",
"90-James-Ramirez\n",
"91-Olivia-Flores\n",
"92-Lucas-Cruz\n",
"93-Isabella-Rivera\n",
"94-David-Lee\n",
"95-Sophie-Walker\n",
"96-Matthew-Hall\n",
"97-Emma-Allen\n",
"98-Ryan-Young\n",
"99-Ava-King\n",
"100-Ethan-Wright\n",
"101-Mia-Scott\n",
"102-William-Turner\n",
"103-James-Carter\n",
"104-Olivia-Phillips\n",
"105-Lucas-Evans\n",
"106-Sophie-Collins\n",
"107-Noah-Stewart\n",
"108-Ava-Snyder\n",
"109-Ethan-Baker\n",
"110-Mia-Nelson\n",
"111-Noah-Roberts\n",
"112-Emma-Campbell\n",
"113-William-Miller\n",
"114-James-Davis\n",
"115-Olivia-Garcia\n",
"116-Lucas-Rodriguez\n",
"117-Sophie-Martinez\n",
"118-Noah-Hernandez\n",
"119-Ava-Lopez\n",
"120-Ethan-Gonzalez\n",
"121-Mia-Perez\n",
"122-William-Sanchez\n",
"123-James-Ramirez\n",
"124-Olivia-Flores\n",
"125-Lucas-Cruz\n",
"126-Isabella-Rivera\n",
"127-David-Lee\n",
"128-Sophie-Walker\n",
"129-Matthew-Hall\n",
"130-Emma-Allen\n",
"131-Ryan-Young\n",
"132-Ava-King\n",
"133-Ethan-Wright\n",
"134-Mia-Scott\n",
"135-William-Turner\n",
"136-James-Carter\n",
"137-Olivia-Phillips\n",
"138-Lucas-Evans\n",
"139-Sophie-Collins\n",
"140-Noah-Stewart\n",
"141-Ava-Snyder\n",
"142-Ethan-Baker\n",
"143-Mia-Nelson\n",
"144-Noah-Roberts\n",
"145-Emma-Campbell\n",
"146-William-Miller\n",
"147-James-Davis\n",
"148-Olivia-Garcia\n",
"149-Lucas-Rodriguez\n",
"150-Sophie-Martinez\n",
"151-Noah-Hernandez\n",
"152-Ava-Lopez\n",
"153-Ethan-Gonzalez\n",
"154-Mia-Perez\n",
"155-William-Sanchez\n",
"156-James-Ramirez\n",
"157-Olivia-Flores\n",
"158-Lucas-Cruz\n",
"159-Isabella-Rivera\n",
"160-David-Lee\n",
"161-Sophie-Walker\n",
"162-Matthew-Hall\n",
"163-Emma-Allen\n",
"164-Ryan-Young\n",
"165-Ava-King\n",
"166-Ethan-Wright\n",
"167-Mia-Scott\n",
"168-William-Turner\n",
"169-James-Carter\n",
"170-Olivia-Phillips\n",
"171-Lucas-Evans\n",
"172-Sophie-Collins\n",
"173-Noah-Stewart\n",
"174-Ava-Snyder\n",
"175-Ethan-Baker\n",
"176-Mia-Nelson\n",
"177-Noah-Roberts\n",
"178-Emma-Campbell\n",
"179-William-Miller\n",
"180-James-Davis\n",
"181-Olivia-Garcia\n",
"182-Lucas-Rodriguez\n",
"183-Sophie-Martinez\n",
"184-Noah-Hernandez\n",
"185-Ava-Lopez\n",
"186-Ethan-Gonzalez\n",
"187-Mia-Perez\n",
"188-William-Sanchez\n",
"189-James-Ramirez\n",
"190-Olivia-Flores\n",
"191-Lucas-Cruz\n",
"192-Isabella-Rivera\n",
"193-David-Lee\n",
"194-Sophie-Walker\n",
"195-Matthew-Hall\n",
"196-Emma-Allen\n",
"197-Ryan-Young\n",
"198-Ava-King\n",
"199-Ethan-Wright\n",
"200-Mia-Scott\n",
"201-William-Turner\n",
"202-James-Carter\n",
"203-Olivia-Phillips\n",
"204-Lucas-Evans\n",
"205-Sophie-Collins\n",
"206-Noah-Stewart\n",
"207-Ava-Snyder\n",
"208-Ethan-Baker\n",
"209-Mia-Nelson\n",
"210-Noah-Roberts\n",
"211-Emma-Campbell\n",
"212-William-Miller\n",
"213-James-Davis\n",
"214-Olivia-Garcia\n",
"215-Lucas-Rodriguez\n",
"216-Sophie-Martinez\n",
"217-Noah-Hernandez\n",
"218-Ava-Lopez\n",
"219-Ethan-Gonzalez\n",
"220-Mia-Perez\n",
"221-William-Sanchez\n",
"222-James-Ramirez\n",
"223-Olivia-Flores\n",
"224-Lucas-Cruz\n",
"225-Isabella-Rivera\n",
"226-David-Lee\n",
"227-Sophie-Walker\n",
"228-Matthew-Hall\n",
"229-Emma-Allen\n",
"230-Ryan-Young\n",
"231-Ava-King\n",
"232-Ethan-Wright\n",
"233-Mia-Scott\n",
"234-William-Turner\n",
"235-James-Carter\n",
"236-Olivia-Phillips\n",
"237-Lucas-Evans\n",
"238-Sophie-Collins\n",
"239-Noah-Stewart\n",
"240-Ava-Snyder\n",
"241-Ethan-Baker\n",
"242-Mia-Nelson\n",
"243-Noah-Roberts\n",
"244-Emma-Campbell\n",
"245-William-Miller\n",
"246-James-Davis\n",
"247-Olivia-Garcia\n",
"248-Lucas-Rodriguez\n",
"249-Sophie-Martinez\n",
"250-Noah-Hernandez\n",
"251-Ava-Lopez\n",
"252-Ethan-Gonzalez\n",
"253-Mia-Perez\n",
"254-William-Sanchez\n",
"255-James-Ramirez\n",
"256-Olivia-Flores\n",
"257-Lucas-Cruz\n",
"258-Isabella-Rivera\n",
"259-David-Lee\n",
"260-Sophie-Walker\n",
"261-Matthew-Hall\n",
"262-Emma-Allen\n",
"263-Ryan-Young\n",
"264-Ava-King\n",
"265-Ethan-Wright\n",
"266-Mia-Scott\n",
"267-William-Turner\n",
"268-James-Carter\n",
"269-Olivia-Phillips\n",
"270-Lucas-Evans\n",
"271-Sophie-Collins\n",
"272-Noah-Stewart\n",
"273-Ava-Snyder\n",
"274-Ethan-Baker\n",
"275-Mia-Nelson\n",
"276-Noah-Roberts\n",
"277-Emma-Campbell\n",
"278-William-Miller\n",
"279-James-Davis\n",
"280-Olivia-Garcia\n",
"281-Lucas-Rodriguez\n",
"282-Sophie-Martinez\n",
"283-Noah-Hernandez\n",
"284-Ava-Lopez\n",
"285-Ethan-Gonzalez\n",
"286-Mia-Perez\n",
"287-William-Sanchez\n",
"288-James-Ramirez\n",
"289-Olivia-Flores\n",
"290-Lucas-Cruz\n",
"291-Isabella-Rivera\n",
"292-David-Lee\n",
"293-Sophie-Walker\n",
"294-Matthew-Hall\n",
"295-Emma-Allen\n",
"296-Ryan-Young\n",
"297-Ava-King\n",
"298-Ethan-Wright\n",
"299-Mia-Scott\n",
"300-William-Turner\n",
"301-James-Carter\n",
"302-Olivia-Phillips\n",
"303-Lucas-Evans\n",
"304-Sophie-Collins\n",
"305-Noah-Stewart\n",
"306-Ava-Snyder\n",
"307-Ethan-Baker\n",
"308-Mia-Nelson\n",
"309-Noah-Roberts\n",
"310-Emma-Campbell\n",
"311-William-Miller\n",
"312-James-Davis\n",
"313-Olivia-Garcia\n",
"314-Lucas-Rodriguez\n",
"315-Sophie-Martinez\n",
"316-Noah-Hernandez\n",
"317-Ava-Lopez\n",
"318-Ethan-Gonzalez\n",
"319-Mia-Perez\n",
"320-William-Sanchez\n",
"321-James-Ramirez\n",
"322-Olivia-Flores\n",
"323-Lucas-Cruz\n",
"324-Isabella-Rivera\n",
"325-David-Lee\n",
"326-Sophie-Walker\n"
]
}
],
"source": [
"import pandas as pd\n",
"usecols = [\"Name\", \"Vorname\"]\n",
"air = pd.read_csv(\"regie_name.csv\", usecols=usecols)\n",
"\n",
"for count, (i, b) in enumerate(zip(air[\"Name\"], air[\"Vorname\"])):\n",
" print(count, b, i, sep=\"-\")\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "ee4b5dee-6b41-49eb-8d75-9db50d20fdef",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Name</th>\n",
" <th>Vorname</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Smith</td>\n",
" <td>John</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>Johnson</td>\n",
" <td>James</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>Williams</td>\n",
" <td>William</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>Brown</td>\n",
" <td>Michael</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>Davis</td>\n",
" <td>David</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Name Vorname\n",
"0 Smith John\n",
"1 Johnson James\n",
"2 Williams William\n",
"3 Brown Michael\n",
"4 Davis David"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import pandas as pd\n",
"air = pd.read_csv(\"regie_name.csv\", nrows=5)\n",
"air"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "8017742d-3b8e-4847-b5a3-4f28e0c9057a",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Name\n",
"Flores 10.0\n",
"Davis 10.0\n",
"Gonzalez 10.0\n",
"Garcia 10.0\n",
"Cruz 10.0\n",
" ... \n",
"Taylor 1.0\n",
"White 1.0\n",
"Thompson 1.0\n",
"Wilson 1.0\n",
"Williams 1.0\n",
"Length: 47, dtype: float64\n"
]
}
],
"source": [
"chunker = pd.read_csv(\"regie_name.csv\", chunksize=1000)\n",
"tot = pd.Series([], dtype='int64')\n",
"for piece in chunker:\n",
" tot = tot.add(piece[\"Name\"].value_counts(), fill_value=0)\n",
"tot = tot.sort_values(ascending=False)\n",
"print(tot)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d7531f34-19a6-4606-88f2-1c4fdd3b0b7d",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}