Modelle und Datenbanken
In diesem Kapitel lernst du, das Django ORM zu verwenden, um Datenmodelle zu definieren, Datenbanktabellen zu erstellen und Testdaten einzufügen.
Warum werden Modelle benötigt?
Im vorherigen Kapitel haben wir den Seitentext fest codiert. Ein echtes Blog muss mehrere Artikel speichern können, und der Inhalt kann sich jederzeit ändern.
ModellEs ist Djangos Datenbankschicht: Verwende Python-Klassen, um Datenstrukturen zu definieren, und Django generiert automatisch die entsprechenden Datenbanktabellen.
Du musst keine einzige Zeile SQL schreiben — das istORM (Object-Relational Mapping)der Kernwert.
Definiere das Post-Modell
Openblog/models.py, definiere das Artikel-Modell.
Beispiel
from django.db import models
from django.utils import timezone
class Category(models.Model):
"""Artikelkategorie"""
name = models.CharField('Kategoriename', max_length=50, unique=True)
# slug wird für englische Bezeichner in URLs verwendet (z. B. /category/django/)
slug = models.SlugField('URL-Kennung', max_length=50, unique=True)
class Meta:
verbose_name = 'Kategorien'
verbose_name_plural = 'Kategorien'
def __str__(self):
return self.name
class Post(models.Model):
"""Blogbeitrag"""
# Titel: CharField wird für kurzen Text verwendet; max_length ist erforderlich.
title = models.CharField('Titel', max_length=200)
# slug: Englischer Bezeichner des Artikels in der URL
slug = models.SlugField('URL-Kennung', max_length=200, unique=True)
# Zusammenfassung: TextField wird für langen Text verwendet, blank=True bedeutet optional
summary = models.TextField('Zusammenfassung', blank=True)
# Inhalt: TextField ohne Längenbegrenzung
content = models.TextField('Inhalt')
# Kategorie: ForeignKey Eins-zu-viele-Beziehung, ein Artikel gehört zu einer Kategorie
# on_delete=models.CASCADE bedeutet, dass beim Löschen einer Kategorie auch alle Artikel unter ihr gelöscht werden
category = models.ForeignKey(
Kategorie,
on_delete=models.CASCADE,
verbose_name='Kategorien',
related_name='posts' # Umgekehrte Abfrage: category.posts.all()
)
# auto_now_add: füllt beim Erstellen automatisch die aktuelle Zeit ein
created_at = models.DateTimeField('Erstellungszeit', auto_now_add=True)
# auto_now: wird bei jedem Speichern automatisch auf die aktuelle Zeit aktualisiert
updated_at = models.DateTimeField('Aktualisierungszeit', auto_now=True)
class Meta:
verbose_name = 'Artikel'
verbose_name_plural = 'Artikel'
# Standardmäßig absteigend nach Erstellungszeit sortiert
ordering = ['-created_at']
def __str__(self):
# Zeigt den Titel an, wenn Objekte im Admin-Backend und in der Shell angezeigt werden
return self.title
Kurzreferenz für gängige Feldtypen
| Feldtyp | Entsprechende Datenbanktypen | Anwendungsfall |
|---|---|---|
| CharField(max_length=N) | VARCHAR(N) | Kurzer Text für Titel, Tags, Namen usw. |
| TextField() | TEXT | Artikeltext, Einleitung, Kommentare und andere Inhalte |
| IntegerField() | INTEGER | Ganzzahlen für Anzahlen, Alter usw. |
| DateTimeField() | DATETIME | Veröffentlichungszeit, Aktualisierungszeit |
| ForeignKey() | Fremdschlüssel-Constraint | Eins-zu-viele-Beziehung (Artikel → Kategorie) |
| ManyToManyField() | Verbindungstabelle | Viele-zu-viele-Beziehung (Artikel ←→ Tag) |
| SlugField() | VARCHAR | URL-freundlicher Bezeichner |
| ImageField() | VARCHAR(path) | Titelbild, Avatar (erfordert die Pillow-Bibliothek) |
__str__Die Methode bestimmt, wie das Objekt als Zeichenkette dargestellt wird. Sie wird in den Dropdown-Auswahlfeldern des Admin-Backends und in der Shell-Ausgabe aufgerufen, um den Objektnamen anzuzeigen. Wenn Sie diese Methode nicht schreiben, sehen SiePost object (1)solchen bedeutungslosen Text.
Migration: Modelle mit der Datenbank synchronisieren
Nach dem Schreiben der Modellklassen müssen SieMigrationverwenden, um Datenbanktabellen zu erstellen.
(venv) $ python manage.py makemigrations # 生成迁移文件(检测模型变化)
Migrations for 'blog':
blog/migrations/0001_initial.py
- Create model Category
- Create model Post
(venv) $ python manage.py migrate # 执行迁移(创建数据库表)
Operations to perform:
Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
Applying blog.0001_initial... OK
Arbeitsteilung zwischen den beiden Befehlen:
- makemigrationsmodels.py scannen und Migrationsskripte (Python-Dateien) generieren.
- migrate: Führen Sie die Migrationsskripte aus, um die tatsächlichen Tabellen in der Datenbank zu erstellen.
Nach jeder Änderung an models.py müssen Sie ausführen
makemigrations+migrate这两个命令都不可或缺:只运行 makemigrations 而不运行 migrate,表不会被创建;直接运行 migrate 而不运行 makemigrations,意味着 Django 不知道你需要做更改。
使用 Django Shell 插入测试数据。
在开始编写页面前,先使用 Django Shell 向数据库录入几条数据,以验证模型是否正常工作。
(venv) $ python manage.py shell
这会打开一个交互式 Python Shell,你可以在其中操作数据库。
Beispiel
from blog.models import Category, Post
# 1. 创建
cat_django = Category.objects.create(name='Django', slug='django')
cat_python = Category.objects.create(name='Python', slug='python')
cat_css = Category.objects.create(name='CSS', slug='css')
# 2. Artikel erstellen
Post.objects.create(
title='Der vollständige Django-Einsteigerleitfaden',
slug='django-beginner-guide',
summary='Lerne Django von Grund auf, einschließlich der Kernkonzepte wie Modelle, Views, Templates usw.',
content='<h2>Warum Django lernen?</h2><p>Django ist eines der beliebtesten Web-Frameworks von Python...</p>',
category=cat_django
)
Post.objects.create(
title='Ausführliche Erklärung der asynchronen Programmierung in Python',
slug='python-async',
summary=Verstehe asyncio, Koroutinen und Event-Loops in einem Artikel.,
content=<h2>Was ist eine Koroutine?</h2><p>Eine Koroutine ist eine leichtgewichtigere Nebenläufigkeitslösung als Threads...</p>,
category=cat_python
)
Post.objects.create(
title=Praktisches CSS Grid Layout,
slug='css-grid-layout',
summary=Komplexe responsive Layouts lassen sich mit CSS Grid einfach umsetzen.,
content=<h2>Erste Schritte mit Grid</h2><p>Grid ist ein zweidimensionales Layout-System...</p>,
category=cat_css
)
# 3. Abfragen überprüfen
print(Post.objects.all()) # Alle Artikel ausgeben
print(Post.objects.count()) # Gesamtartikel
print(Post.objects.filter(category=cat_django)) # Artikel in der Kategorie Django
Django ORM Grundabfragen
ORM ermöglicht es Ihnen, mit Python-Methodenketten auf der Datenbank zu arbeiten, ohne SQL zu schreiben.
| Methoden | Äquivalentes SQL | Rückgabewert |
|---|---|---|
Post.objects.all() | SELECT * FROM blog_post | QuerySet (alle Artikel) |
Post.objects.get(id=1) | SELECT ... WHERE id=1 | Einzelnes Objekt (löst eine Ausnahme aus, wenn es nicht gefunden wird) |
Post.objects.filter(category__slug='django') | WHERE category.slug='django' | QuerySet |
Post.objects.order_by('-created_at') | ORDER BY created_at DESC | QuerySet |
Post.objects.exclude(status='draft') | WHERE status != 'draft' | QuerySet |
QuerySet istVerzögerte AuswertungDas bedeutet: Die Abfrage wird nicht sofort ausgeführt; SQL wird erst gesendet, wenn die Daten tatsächlich benötigt werden (z. B. beim Iterieren, Ausgeben oder Umwandeln in eine Liste). So können Sie mehrere Aufrufe von filter verketten, ohne mehrere Abfragen zu erzeugen.
Praktische Übung: Daten für die nachfolgenden Kapitel vorbereiten
Gib in der Shell mehrere weitere Artikel und Kategorien ein, die die drei Kategorien Django, Python und CSS abdecken, mit mindestens 2 Artikeln pro Kategorie.
Du könntest einen Management-Befehl oder ein Skript für die Massen-Einfügung schreiben, aber in diesem Stadium reicht es aus, sie einzeln über die Shell einzufügen.
Kapitelzusammenfassung
In diesem Kapitel hast du den Kern-Workflow des Django-ORM beherrscht: Python-Klassen (Modelle) in models.py definieren, Migrationsdateien mit makemigrations erzeugen, mit migrate mit der Datenbank synchronisieren und die Shell sowie das ORM zum Abfragen und Einfügen von Daten nutzen.
Zu diesem Zeitpunkt ist die Struktur von Artikeln und Kategorien in der Datenbank eingerichtet.
Weitere Erweiterungen