{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Datenbankzugriff\n", "\n", "Für die folgenden Beispiele wollen wir eine Tabelle Personen(nr, name) mit den Attributen `nr` und `Name` erstellen und jeweils wieder abfragen." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "TESTDATEN = [[101, \"Peter\"], \n", " [102, \"Petra\"], \n", " [103, \"Hans\"], \n", " [104, \"Claudia\"]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sqlite\n", "\n", "Mit dem Python-Paket [sqlite3](https://docs.python.org/library/sqlite3.html)\n", "kann auf sqlite-Datenbanken direkt zugegriffen werden. Es muss daher nicht\n", "installiert werden und ist bei jeder Python-Installation vorhanden.\n", "\n", "In der folgenden Beispielanwendung erstellen wir eine Beispieltabelle,\n", "fügen ein paar Daten hinzu und geben diese wieder aus." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [], "source": [ "import sqlite3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nach dem Import des `sqlite3`-Moduls können nun Daten hinzugefügt und anschließend wieder ausgelesen werden.\n", "Zunächst wird eine Verbindung erstellt und aus dieser ein `Cursor` generiert, mit dem auf die Datenbank zugegriffen werden kann.\n", "\n", "Das SQL-Statement enthält ``?``. Diese werden durch die Werte in der Liste, die als zweites Argument übergeben\n", "werden, ersetzt. Hierdurch werden Sicherheitslücken wie SQL-Injection vermieden." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Füge Daten hinzu: 101 Peter\n", "Füge Daten hinzu: 102 Petra\n", "Füge Daten hinzu: 103 Hans\n", "Füge Daten hinzu: 104 Claudia\n" ] } ], "source": [ "conn = sqlite3.connect(\"datenbank.db\")\n", "c = conn.cursor()\n", "c.execute(\"\"\"CREATE TABLE IF NOT EXISTS \n", " personen(nr int, name text)\"\"\")\n", "\n", "for nr, name in TESTDATEN:\n", " # use paramters ? to avoid sql injection\n", " print(\"Füge Daten hinzu:\", nr, name)\n", " c.execute(\n", " \"INSERT INTO personen (nr, name) VALUES(?,?)\", \n", " (nr, name))\n", "\n", "conn.commit()\n", "conn.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Manchmal ist es übersichtlicher, wenn man den Parametern in der SQL-Anweisung einen Namen gibt.\n", "Dann werden statt ``?`` die Parameter mit einem Namen wie ``:mein_parameter`` referenziert." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "conn = sqlite3.connect(\"datenbank.db\")\n", "c = conn.cursor()\n", "\n", "c.execute(\n", " \"INSERT INTO personen (nr, name) VALUES(:nr,:name)\", \n", " {'nr':105, 'name':'Hannes'})\n", "\n", "conn.commit()\n", "conn.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wir finden nun eine Datei `datenbank.db` im aktuellen Verzeichnis." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "datenbank.db\n" ] } ], "source": [ "! ls datenbank.db" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Die Daten können wieder aus der Datei gelesen werden." ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Nr.\t Name\n", "101 \t Peter\n", "102 \t Petra\n", "103 \t Hans\n", "104 \t Claudia\n", "105 \t Hannes\n" ] } ], "source": [ "conn = sqlite3.connect(\"datenbank.db\")\n", "cur = conn.cursor()\n", "cur.execute(\"SELECT nr, name FROM personen\")\n", "\n", "print(\"Nr.\\t Name\")\n", "for i, name in cur:\n", " print(i, \"\\t\", name)\n", "\n", "conn.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ändert man die `row_factory` einer sqlite-Verbindung, so kann man auch über den\n", "Namen auf Einträge zugreifen." ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "101 Peter\n", "102 Petra\n", "103 Hans\n", "104 Claudia\n", "105 Hannes\n" ] } ], "source": [ "conn = sqlite3.connect(\"datenbank.db\")\n", "conn.row_factory = sqlite3.Row\n", "cur = conn.cursor()\n", "cur.execute(\"SELECT nr, name FROM personen\")\n", "for row in cur:\n", " print(row['nr'], row['name'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Auch über das `sqlite3`-Kommandozeilentool lassen sich die Daten anzeigen." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "101|Peter\n", "102|Petra\n", "103|Hans\n", "104|Claudia\n" ] } ], "source": [ "! sqlite3 datenbank.db \"SELECT * FROM personen\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Die Standardausgabe kann auch hübscher dargestellt werden." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "┌─────┬─────────┐\r\n", "│ nr │ name │\r\n", "├─────┼─────────┤\r\n", "│ 101 │ Peter │\r\n", "│ 102 │ Petra │\r\n", "│ 103 │ Hans │\r\n", "│ 104 │ Claudia │\r\n", "└─────┴─────────┘\r\n" ] } ], "source": [ "! sqlite3 --box datenbank.db \"SELECT * FROM personen\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Fremdschlüssel (Foreign Keys) in SQLite\n", "\n", "[Foreign Keys](https://sqlite.org/foreignkeys.html) werden in SQLite standardmäßig nicht\n", "unterstützt und müssen pro Connection einmal über `PRAGMA foreign_keys = ON` aktiviert \n", "werden." ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "conn = sqlite3.connect(\"datenbank.db\")\n", "cur = conn.cursor()\n", "cur.execute(\"\"\"\n", " CREATE TABLE freundschaft (\n", " person1 int, \n", " person2 int,\n", " FOREIGN KEY (person1) REFERENCES personen(nr),\n", " FOREIGN KEY (person2) REFERENCES personen(nr),\n", " PRIMARY KEY (person1, person2)\n", " )\n", " \"\"\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wir befreunden die Personen Peter (101) und Petra (102) miteinander." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "cur.execute(\"INSERT INTO freundschaft VALUES (101,102)\")\n", "conn.commit()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Leider wird nicht geprüft, ob die Personen, die befreundet werden sollen, überhaupt\n", "existieren. \n", "\n", "So würden wir bei der nächsten Anweisung eine Fehlermeldung erwarten, da die Personen\n", "mit den IDs -1 und -2 nicht existieren." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "cur.execute(\"INSERT INTO freundschaft VALUES (-1,-2)\")\n", "conn.commit()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wird die Unterstützung für Fremdschlüssel aktiviert, erfolgt die gewünschte Fehlermeldung." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "ename": "OperationalError", "evalue": "foreign key mismatch - \"freundschaft\" referencing \"personen\"", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mOperationalError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexecute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"PRAGMA foreign_keys = ON\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexecute\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"INSERT INTO freundschaft VALUES (-3,-4)\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0mconn\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcommit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mOperationalError\u001b[0m: foreign key mismatch - \"freundschaft\" referencing \"personen\"" ] } ], "source": [ "cur.execute(\"PRAGMA foreign_keys = ON\")\n", "cur.execute(\"INSERT INTO freundschaft VALUES (-3,-4)\")\n", "conn.commit()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wir löschen zum Schluss die Datenbank-Datei." ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [], "source": [ "! rm datenbank.db" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## MariaDB/MySQL\n", "\n", "Für den Zugriff auf eine MariaDB/MySQL-Datenbank muss zusätzlich ein Connector für\n", "[MySQL](https://dev.mysql.com/doc/connector-python/en/connector-python-installation-binary.html)\n", "oder [MariaDB](https://mariadb.com/de/resources/blog/how-to-connect-python-programs-to-mariadb/)\n", "installiert werden. Im Folgenden konzentrieren wir uns auf die Verwendung des MariaDB-Connectors.\n", "\n", "Für Windows gibt es ein eigenes [Installationsprogramm](https://mariadb.com/docs/connect/programming-languages/python/install/). Für Linux oder den RaspberryPi muss ggf. vorher \n", "[MariaDB Connector/C](https://mariadb.com/docs/connect/programming-languages/c/install/#install-on-debian-ubuntu) \n", "installiert werden.\n", "\n", "Zunächst wird der Connector installiert:\n", "\n", " $ pip install mariadb \n", "\n", "Bei Rechteproblemen:\n", "\n", " $ pip install --user mariadb\n", "\n", "Wenn alles geklappt hat, können wir im Anschluss das neue Modul importieren." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "import mariadb" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wie stellen eine Verbindung mit der Datenbank her. Diesmal müssen wir Zugangsdaten und die Datenbank angeben." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "conn = mariadb.connect(user='root', password='',\n", " host='127.0.0.1',\n", " database='test')\n", "conn.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nun können wir eine Tabelle `personen` in der Datenbank `test` erstellen." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "conn = mariadb.connect(user='root', password='',\n", " host='127.0.0.1',\n", " database='test')\n", "cur = conn.cursor()\n", "cur.execute(\"DROP TABLE IF EXISTS personen\")\n", "cur.execute(\"\"\"CREATE TABLE IF NOT EXISTS \n", " personen(nr int, name text)\"\"\")\n", "\n", "conn.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wir benutzen das Kommandozeilentool `mysql` und lassen uns die Tabellen in der Datenbank `test` anzeigen." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+----------------+\r\n", "| Tables_in_test |\r\n", "+----------------+\r\n", "| personen |\r\n", "+----------------+\r\n" ] } ], "source": [ "! mysql -uroot --execute=\"SHOW TABLES;\" test " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nun können wir neue Daten in die Tabelle einfügen." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Füge Daten hinzu: 101 Peter\n", "Füge Daten hinzu: 102 Petra\n", "Füge Daten hinzu: 103 Hans\n", "Füge Daten hinzu: 104 Claudia\n" ] } ], "source": [ "conn = mariadb.connect(user=\"root\", password=\"\",\n", " host=\"127.0.0.1\", database=\"test\")\n", "cur = conn.cursor()\n", "for nr, name in TESTDATEN:\n", " print(\"Füge Daten hinzu:\", nr, name)\n", " cur.execute(\n", " \"\"\"INSERT INTO personen (nr, name) VALUES(?,?)\"\"\", \n", " (nr, name))\n", "conn.commit()\n", "conn.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Schließlich werden die Daten wieder mit einer SELECT-Anweisung aus der Datenbank abgefragt. Wir nutzen zunächst den Kommandozeilen-Client." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+------+---------+\r\n", "| nr | name |\r\n", "+------+---------+\r\n", "| 101 | Peter |\r\n", "| 102 | Petra |\r\n", "| 103 | Hans |\r\n", "| 104 | Claudia |\r\n", "+------+---------+\r\n" ] } ], "source": [ "! mysql -uroot --execute=\"SELECT * FROM personen\" test " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Die Daten können natürlich auch mit Python abgerufen werden." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "101 Peter\n", "102 Petra\n", "103 Hans\n", "104 Claudia\n" ] } ], "source": [ "conn = mariadb.connect(user=\"root\", password=\"\",\n", " host=\"127.0.0.1\", database=\"test\")\n", "cur = conn.cursor()\n", "cur.execute(\"SELECT nr,name FROM personen\")\n", "for nr, name in cur:\n", " print(nr, name)\n", " \n", "conn.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## NoSQL mit TinyDB\n", "\n", "Jenseits von SQL gibt es noch verschiedene andere Ansätze, Daten in\n", "Datenbanken zu verwalten - hierbei werden keine Tabellen verwendet. Einer\n", "der Ansätze ist z.B. eine dokument-basierte Datenbank. Hier werden Daten\n", "als Dokumente wie z.B. JSON abgelegt. \n", "[TinyDB](https://tinydb.readthedocs.io/) ist eine solche Datenbank für\n", "Python." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Installation\n", "\n", "Die Installation erfolgt auch hier einfach mit Hilfe von pip:\n", "\n", " $ pip install tinydb" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "import tinydb" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Eine Datenbank kann mit der Klasse `TinyDB` leicht erzeugt werden. Wie bei sqlite werden die Daten direkt in einer Datei gespeichert." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "db = tinydb.TinyDB(\"db.json\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Die Datei `db.json` wurd als Textdatei angelegt. Wir können den Inhalt daher leicht betrachten und ggf. verändern." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "db.json: ASCII text, with no line terminators\r\n" ] } ], "source": [ "! file db.json" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\"_default\": {}}" ] } ], "source": [ "! cat db.json" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Daten hinzufügen\n", "\n", "Noch ist die Datenbank leer. Füllen wir sie also mir ein paar Daten. Die Daten können einfache Dictionaries sein." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.insert({\"type\": \"apple\", \"count\": 7})" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.insert({\"type\": \"peach\", \"count\": 3})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Als Rückgabewert erhalten wir eine ID für den neuen Eintrag. Ein anschließender Blick in die Datei offenbart die neuen Inhalte." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{\"_default\": {\"1\": {\"type\": \"apple\", \"count\": 7}, \"2\": {\"type\": \"peach\", \"count\": 3}}}" ] } ], "source": [ "! cat db.json" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wir sehen einen Eintrag `_default`, der auf den Namen der Standardtabelle hinweist, mit der wir arbeiten. Dazu noch die hinzugefügten Einträge." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Daten abfragen\n", "\n", "Lassen wir uns alle Einträge einmal anzeigen." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[{'type': 'apple', 'count': 7}, {'type': 'peach', 'count': 3}]" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.all()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Über diese Liste aus Einzeleinträgen kann auch mit einer Schleife iteriert werden." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'type': 'apple', 'count': 7} Typ: apple\n", "{'type': 'peach', 'count': 3} Typ: peach\n" ] } ], "source": [ "for item in db:\n", " print(item, \"Typ:\", item[\"type\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Bis jetzt haben wir noch nicht viel gewonnen gegenüber einer direkten Speicherung eines Dictionaries. Dokumentenbasierte Datenbanken wie TinyDB bieten jedoch die Möglichkeit, komplexere Anfrage zu stellen.\n", "\n", "Hierfür wird ein Query-Objekt erzeugt." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "query = tinydb.Query()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In der `search`-Methode kann das Query-Objekt für Abfragen genutzt werden." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[{'type': 'apple', 'count': 7}]" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.search(query.type == \"apple\")" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[{'type': 'peach', 'count': 3}]" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.search(query.count < 5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Mit `get` greifen wir auf das erste Ergebnis einer Suche zu. Jeder Eintrag in der Datenbank hat eine eindeutige ID, die über das Attribut `doc_id` abgefragt werden kann." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "peach = db.get(query.type == \"peach\")\n", "peach.doc_id" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Mit der ID können Einträge auch direkt abgerufen werden." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'type': 'peach', 'count': 3}" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.get(doc_id = 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Daten aktualisieren\n", "\n", "Auch Aktualisierungen werden über das Query-Objekt gemacht, wenn nicht alle Datensätze geändert werden sollen." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1]" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.update({\"count\": 10}, query.type == \"apple\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wird keine Bedingung mit einem Query-Objekt verwendet, so werden alle Datensätze geändert." ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 2]" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.update({\"new_key\": \"new_value\"})" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[{'type': 'apple', 'count': 10, 'new_key': 'new_value'},\n", " {'type': 'peach', 'count': 3, 'new_key': 'new_value'}]" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.all()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Schließlich löschen wir wieder alle Einträge." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "db.purge()\n", "db.all()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Und löschen auch die Datenbankdatei." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [], "source": [ "! rm db.json" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Fortgeschrittene Anwendungen mit TinyDB werden im [Handbuch](https://tinydb.readthedocs.io/en/latest/usage.html) beschrieben. Hier werden Fragen zur Performance beantwortet und komplexere Anfragen beschrieben." ] } ], "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.10.6" } }, "nbformat": 4, "nbformat_minor": 2 }