Django
Modelle
Suche…
Einführung
Im einfachen Fall handelt es sich bei einem Modell um eine Python-Klasse, die einer einzelnen Datenbanktabelle zugeordnet ist. Die Attribute der Klasse werden den Spalten in der Tabelle zugeordnet, und eine Instanz der Klasse repräsentiert eine Zeile in der Datenbanktabelle. Die Modelle erben von django.db.models.Model
, das eine umfangreiche API zum Hinzufügen und Filtern von Ergebnissen aus der Datenbank bereitstellt.
Erstellen Sie Ihr erstes Modell
Modelle werden normalerweise in der Datei models.py
in Ihrem Anwendungsunterverzeichnis definiert. Die Model
Klasse des Moduls django.db.models
ist eine gute Einstiegsklasse, um Ihre Modelle zu erweitern. Zum Beispiel:
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey('Author', on_delete=models.CASCADE, related_name='authored_books')
publish_date = models.DateField(null=True, blank=True)
def __str__(self): # __unicode__ in python 2.*
return self.title
Jedes Attribut in einem Modell repräsentiert eine Spalte in der Datenbank.
-
title
ist ein Text mit einer maximalen Länge von 100 Zeichen -
author
ist einForeignKey
der eine Beziehung zu einem anderen Modell / einer anderen Tabelle darstellt, in diesem FallAuthor
(wird nur zu Beispielzwecken verwendet).on_delete
teilt der Datenbank mit, was mit dem Objekt zu tun ist, wenn das zugehörige Objekt (einAuthor
) gelöscht wird. (Es sei darauf hingewiesen, dass seit django 1,9on_delete
kann als zweite Positions Argument verwendet werden. In django 2 ist ein erforderliches Argument , und es ist ratsam , sie als solche zu behandeln sofort. Bei älteren Versionen es wird standardmäßigCASCADE
.) -
publish_date
speichert ein Datum. Sowohlnull
als auchblank
sind aufTrue
gesetzt, um anzuzeigen, dass es sich nicht um ein erforderliches Feld handelt (dh Sie können es zu einem späteren Zeitpunkt hinzufügen oder leer lassen.)
Zusammen mit den Attributen definieren wir eine Methode __str__
Diese gibt den Titel des Buches zurück, der ggf. als string
Darstellung und nicht als Standardwert verwendet wird.
Änderungen auf die Datenbank anwenden (Migrationen)
Nach dem Erstellen eines neuen Modells oder dem Ändern vorhandener Modelle müssen Sie Migrationen für Ihre Änderungen generieren und die Migrationen anschließend auf die angegebene Datenbank anwenden. Dies kann mithilfe des integrierten Migrationssystems von Django durchgeführt werden. Verwenden des Dienstprogramms manage.py
im Projektstammverzeichnis:
python manage.py makemigrations <appname>
Der obige Befehl erstellt die Migrationsskripts, die im Unterverzeichnis migrations
Ihrer Anwendung erforderlich sind. Wenn Sie den Parameter <appname>
weglassen, werden alle Anwendungen verarbeitet, die im Argument INSTALLED_APPS
von settings.py
definiert sind. Wenn Sie es für nötig halten, können Sie die Migrationen bearbeiten.
Sie können überprüfen, welche Migrationen erforderlich sind, ohne die Migration zu erstellen, indem Sie die Option --dry-run verwenden, z.
python manage.py makemigrations --dry-run
So wenden Sie die Migrationen an:
python manage.py migrate <appname>
Der obige Befehl führt die im ersten Schritt generierten Migrationsskripts aus und aktualisiert die Datenbank physisch.
Wenn das Modell der vorhandenen Datenbank geändert wird, ist der folgende Befehl erforderlich, um die erforderlichen Änderungen vorzunehmen.
python manage.py migrate --run-syncdb
Django erstellt die Tabelle standardmäßig mit dem Namen <appname>_<classname>
. Manchmal möchtest du es nicht benutzen. Wenn Sie den Standardnamen ändern möchten, können Sie den Tabellennamen durch Setzen der Tabelle db_table
in der Klasse Meta
db_table
:
from django.db import models
class YourModel(models.Model):
parms = models.CharField()
class Meta:
db_table = "custom_table_name"
Wenn Sie sehen möchten, welcher SQL-Code bei einer bestimmten Migration ausgeführt wird, führen Sie einfach den folgenden Befehl aus:
python manage.py sqlmigrate <app_label> <migration_number>
Django> 1,10
Mit der neuen Option makemigrations --check
wird der Befehl mit einem Status ungleich Null beendet, wenn Modelländerungen ohne Migrationen erkannt werden.
Siehe Migrationen für weitere Details über Migrationen.
Ein Modell mit Beziehungen erstellen
Viele-zu-Eins-Beziehung
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=50)
#Book has a foreignkey (many to one) relationship with author
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
publish_date = models.DateField()
Die allgemeinste Option. Kann überall verwendet werden, wo Sie eine Beziehung darstellen möchten
Viele-zu-Viele-Beziehung
class Topping(models.Model):
name = models.CharField(max_length=50)
# One pizza can have many toppings and same topping can be on many pizzas
class Pizza(models.Model):
name = models.CharField(max_length=50)
toppings = models.ManyToManyField(Topping)
Intern wird dies über eine andere Tabelle dargestellt. ManyToManyField
sollte für Modelle verwendet werden, die in einem Formular bearbeitet werden. Beispiel: Für einen Appointment
wird ein ManyToManyField
Namen Customer
, Pizza
hat Toppings
usw. erstellt.
Viele-zu-Viele-Beziehungen mit Through-Klassen
class Service(models.Model):
name = models.CharField(max_length=35)
class Client(models.Model):
name = models.CharField(max_length=35)
age = models.IntegerField()
services = models.ManyToManyField(Service, through='Subscription')
class Subscription(models.Model):
client = models.ForeignKey(Client)
service = models.ForeignKey(Service)
subscription_type = models.CharField(max_length=1, choices=SUBSCRIPTION_TYPES)
created_at = models.DateTimeField(default=timezone.now)
Auf diese Weise können wir tatsächlich mehr Metadaten über eine Beziehung zwischen zwei Entitäten beibehalten. Wie man sehen kann, kann ein Kunde über mehrere Abonnementtypen mehrere Dienste abonniert haben. Der einzige Unterschied besteht in diesem Fall darin, dass zum Hinzufügen neuer Instanzen zur M2M-Beziehung nicht die Verknüpfungsmethode pizza.toppings.add(topping)
kann. Stattdessen sollte ein neues Objekt der through- Klasse erstellt werden: Subscription.objects.create(client=client, service=service, subscription_type='p')
In anderen Sprachen
through tables
alsJoinColumn
,Intersection table
odermapping table
Eins-zu-Eins-Beziehung
class Employee(models.Model):
name = models.CharField(max_length=50)
age = models.IntegerField()
spouse = models.OneToOneField(Spouse)
class Spouse(models.Model):
name = models.CharField(max_length=50)
Verwenden Sie diese Felder, wenn Sie immer nur eine Kompositionsbeziehung zwischen den beiden Modellen haben.
Grundlegende Django DB-Abfragen
Django ORM ist eine leistungsstarke Abstraktion, mit der Sie Daten aus der Datenbank speichern und abrufen können, ohne selbst SQL-Abfragen schreiben zu müssen.
Nehmen wir folgende Modelle an:
class Author(models.Model):
name = models.CharField(max_length=50)
class Book(models.Model):
name = models.CharField(max_length=50)
author = models.ForeignKey(Author)
Angenommen, Sie haben den obigen Code zu einer Django-Anwendung hinzugefügt und führen den migrate
(damit Ihre Datenbank erstellt wird). Starten Sie die Django-Shell mit
python manage.py shell
Dadurch wird die Standard-Python-Shell gestartet, jedoch werden relevante Django-Bibliotheken importiert, sodass Sie sich direkt auf die wichtigen Teile konzentrieren können.
Beginnen Sie mit dem Import der gerade definierten Modelle (ich models.py
davon aus, dass dies in einer Datei models.py
).
from .models import Book, Author
Führen Sie Ihre erste Auswahlabfrage aus:
>>> Author.objects.all()
[]
>>> Book.objects.all()
[]
Lässt ein Autor- und Buchobjekt erstellen:
>>> hawking = Author(name="Stephen hawking")
>>> hawking.save()
>>> history_of_time = Book(name="history of time", author=hawking)
>>> history_of_time.save()
oder verwenden Sie die Funktion create, um Modellobjekte zu erstellen und in einem Zeilencode zu speichern
>>> wings_of_fire = Book.objects.create(name="Wings of Fire", author="APJ Abdul Kalam")
Jetzt können wir die Abfrage ausführen
>>> Book.objects.all()
[<Book: Book object>]
>>> book = Book.objects.first() #getting the first book object
>>> book.name
u'history of time'
Fügen wir unserer select-Abfrage eine where-Klausel hinzu
>>> Book.objects.filter(name='nothing')
[]
>>> Author.objects.filter(name__startswith='Ste')
[<Author: Author object>]
Um Details über den Autor eines bestimmten Buches zu erhalten
>>> book = Book.objects.first() #getting the first book object
>>> book.author.name # lookup on related model
u'Stephen hawking'
Um alle Bücher von Stephen Hawking zu erhalten (Nachschlagewerk des Autors)
>>> hawking.book_set.all()
[<Book: Book object>]
_set
ist die Notation, die für "Reverse Lookups" verwendet wird. _set
also das _set
im _set
befindet, können wir book_set
für ein book_set
, um alle seine Bücher book_set
.
Eine grundlegende nicht verwaltete Tabelle.
Wenn Sie Django verwenden, möchten Sie möglicherweise schon einmal mit bereits erstellten Tabellen oder mit Datenbankansichten interagieren. In diesen Fällen möchten Sie nicht, dass Django die Tabellen durch seine Migrationen verwaltet. Um dies einzurichten, müssen Sie der Meta
Klasse Ihres Modells nur eine Variable hinzufügen: managed = False
.
Hier ein Beispiel, wie Sie ein nicht verwaltetes Modell erstellen können, um mit einer Datenbankansicht zu interagieren:
class Dummy(models.Model):
something = models.IntegerField()
class Meta:
managed = False
Dies kann einer in SQL definierten Ansicht wie folgt zugeordnet werden.
CREATE VIEW myapp_dummy AS
SELECT id, something FROM complicated_table
WHERE some_complicated_condition = True
Nachdem Sie dieses Modell erstellt haben, können Sie es wie jedes andere Modell verwenden:
>>> Dummy.objects.all()
[<Dummy: Dummy object>, <Dummy: Dummy object>, <Dummy: Dummy object>]
>>> Dummy.objects.filter(something=42)
[<Dummy: Dummy object>]
Fortgeschrittene Modelle
Ein Modell kann viel mehr Informationen liefern als nur die Daten zu einem Objekt. Sehen wir uns ein Beispiel an und zerlegen es in was es nützlich ist:
from django.db import models
from django.urls import reverse
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible
class Book(models.Model):
slug = models.SlugField()
title = models.CharField(max_length=128)
publish_date = models.DateField()
def get_absolute_url(self):
return reverse('library:book', kwargs={'pk':self.pk})
def __str__(self):
return self.title
class Meta:
ordering = ['publish_date', 'title']
Automatischer Primärschlüssel
Möglicherweise stellen Sie fest, dass self.pk
in der Methode get_absolute_url
verwendet wird. Das Feld pk
ist ein Alias für den Primärschlüssel eines Modells. Außerdem fügt Django automatisch einen Primärschlüssel hinzu, wenn dieser fehlt. Das ist eine Sache weniger, die Sie beunruhigen müssen. Sie können Fremdschlüssel für alle Modelle festlegen und sie problemlos erhalten.
Absolute URL
Die erste definierte Funktion ist get_absolute_url
. Auf diese Weise können Sie, wenn Sie ein Buch haben, einen Link zu ihm erstellen, ohne mit dem URL-Tag, dem Auflösen, dem Attribut und dergleichen zu spielen. book.get_absolute_url
Sie einfach book.get_absolute_url
und Sie erhalten den richtigen Link. Als Bonus erhält Ihr Objekt im Django-Admin den Button "Vor Ort anzeigen".
String-Darstellung
Mit einer __str__
Methode können Sie das Objekt verwenden, wenn Sie es anzeigen __str__
. Bei der vorherigen Methode ist das Hinzufügen eines Links zum Buch in einer Vorlage beispielsweise so einfach wie <a href="{{ book.get_absolute_url }}">{{ book }}</a>
. Auf den Punkt. Diese Methode steuert auch, was in der Dropdown-Liste für Administratoren angezeigt wird, beispielsweise für Fremdschlüssel.
Mit dem Klassendekorateur können Sie die Methode für __str__
und __unicode__
auf Python 2 einmal definieren, ohne dass auf Python 3 __str__
__unicode__
.
Slug-Feld
Das Slug-Feld ähnelt einem Zeichenfeld, akzeptiert jedoch weniger Symbole. Standardmäßig werden nur Buchstaben, Zahlen, Unterstriche oder Bindestriche verwendet. Dies ist nützlich, wenn Sie ein Objekt anhand einer schönen Darstellung identifizieren möchten, beispielsweise in der URL.
Die Meta-Klasse
In der Meta
Klasse können wir viel mehr Informationen über die gesamte Objektkollektion definieren. Hier wird nur die Standardreihenfolge festgelegt. Dies ist beispielsweise beim ListView-Objekt nützlich. Es ist eine idealerweise kurze Liste von Feldern erforderlich, die zum Sortieren verwendet wird. Hier wird das Buch zuerst nach dem Veröffentlichungsdatum und dann nach Titel sortiert, wenn das Datum gleich ist.
Andere häufige Attribute sind verbose_name
und verbose_name_plural
. Standardmäßig werden sie aus dem Namen des Modells generiert und sollten in Ordnung sein. Aber die Pluralform ist naiv, indem einfach ein 's' an den Singular angehängt wird, so dass Sie es in einigen Fällen explizit setzen möchten.
Berechnete Werte
Sobald ein Modellobjekt abgerufen wurde, wird es zu einer vollständig realisierten Instanz der Klasse. Auf zusätzliche Methoden kann daher in Formularen und Serialisierern (wie Django Rest Framework) zugegriffen werden.
Die Verwendung von Python-Eigenschaften ist eine elegante Möglichkeit, zusätzliche Werte darzustellen, die aufgrund unterschiedlicher Umstände nicht in der Datenbank gespeichert sind.
def expire():
return timezone.now() + timezone.timedelta(days=7)
class Coupon(models.Model):
expiration_date = models.DateField(default=expire)
@property
def is_expired(self):
return timezone.now() > self.expiration_date
Während Sie in den meisten Fällen Daten mit Anmerkungen zu Ihren Abfragesets ergänzen können, sind berechnete Werte als Modelleigenschaften ideal für Berechnungen, die nicht einfach im Rahmen einer Abfrage ausgewertet werden können.
Außerdem stehen Eigenschaften nicht für die Abfrage zur Verfügung, da sie in der Python-Klasse und nicht als Teil des Schemas deklariert sind.
Hinzufügen einer Zeichenfolgendarstellung eines Modells
Um eine vom Menschen lesbare Präsentation eines Model.__str__()
zu erstellen, müssen Sie die Model.__str__()
Methode (oder Model.__unicode__()
auf python2) implementieren. Diese Methode wird aufgerufen, wenn Sie str()
für eine Instanz Ihres Modells aufrufen str()
z. B. wenn das Modell in einer Vorlage verwendet wird). Hier ist ein Beispiel:
Erstellen Sie ein Buchmodell.
# your_app/models.py from django.db import models class Book(models.Model): name = models.CharField(max_length=50) author = models.CharField(max_length=50)
Erstellen Sie eine Instanz des Modells und speichern Sie es in der Datenbank:
>>> himu_book = Book(name='Himu Mama', author='Humayun Ahmed') >>> himu_book.save()
Führen Sie
print()
in der Instanz aus:>>> print(himu_book) <Book: Book object>
<Buch: Buchobjekt> , die Standardausgabe, hilft uns nicht. Um dies zu beheben, fügen __str__
eine __str__
Methode hinzu.
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible
class Book(models.Model):
name = models.CharField(max_length=50)
author = models.CharField(max_length=50)
def __str__(self):
return '{} by {}'.format(self.name, self.author)
Beachten Sie die python_2_unicode_compatible
Dekorateur ist nur erforderlich , wenn Sie Ihren Code wollen mit 2. Python kompatibel sein Dieser Dekorateur kopiert die __str__
Methode zur Schaffung eines __unicode__
Methode. Importieren Sie es aus django.utils.encoding
.
Wenn wir jetzt die Druckfunktion erneut die Buchinstanz aufrufen:
>>> print(himu_book)
Himu Mama by Humayun Ahmed
Viel besser!
Die Zeichenfolgendarstellung wird auch verwendet, wenn das Modell in einem ModelForm
für " ForeignKeyField
und " ManyToManyField
verwendet wird.
Model Mixins
In den gleichen Fällen können verschiedene Modelle im Produktlebenszyklus dieselben Felder und Verfahren aufweisen. Um diese Ähnlichkeiten zu handhaben, ohne Code-Wiederholungen zu haben, könnte Vererbung verwendet werden. Anstatt eine ganze Klasse zu erben, bietet mixin design pattern die Möglichkeit, einige Methoden und Attribute zu erben ( oder einige sagen dazu, include ). Sehen wir uns ein Beispiel an:
class PostableMixin(models.Model):
class Meta:
abstract=True
sender_name = models.CharField(max_length=128)
sender_address = models.CharField(max_length=255)
receiver_name = models.CharField(max_length=128)
receiver_address = models.CharField(max_length=255)
post_datetime = models.DateTimeField(auto_now_add=True)
delivery_datetime = models.DateTimeField(null=True)
notes = models.TextField(max_length=500)
class Envelope(PostableMixin):
ENVELOPE_COMMERCIAL = 1
ENVELOPE_BOOKLET = 2
ENVELOPE_CATALOG = 3
ENVELOPE_TYPES = (
(ENVELOPE_COMMERCIAL, 'Commercial'),
(ENVELOPE_BOOKLET, 'Booklet'),
(ENVELOPE_CATALOG, 'Catalog'),
)
envelope_type = models.PositiveSmallIntegerField(choices=ENVELOPE_TYPES)
class Package(PostableMixin):
weight = models.DecimalField(max_digits=6, decimal_places=2)
width = models.DecimalField(max_digits=5, decimal_places=2)
height = models.DecimalField(max_digits=5, decimal_places=2)
depth = models.DecimalField(max_digits=5, decimal_places=2)
Um aus einem Modell eine abstrakte Klasse zu machen, müssen Sie abstract=True
in seiner inneren Meta
Klasse Meta
. Django erstellt keine Tabellen für abstrakte Modelle in der Datenbank. Bei den Modellen Envelope
und Package
werden jedoch entsprechende Tabellen in der Datenbank erstellt.
Außerdem werden in den Feldern einige Modellmethoden für mehr als ein Modell benötigt. Somit können diese Methoden zu Mixins hinzugefügt werden, um eine Wiederholung des Codes zu verhindern. Wenn wir beispielsweise eine Methode zum PostableMixin
Lieferdatums für PostableMixin
erstellen, kann von beiden PostableMixin
Elementen aus darauf zugegriffen werden:
class PostableMixin(models.Model):
class Meta:
abstract=True
...
...
def set_delivery_datetime(self, dt=None):
if dt is None:
from django.utils.timezone import now
dt = now()
self.delivery_datetime = dt
self.save()
Diese Methode kann für die Kinder wie folgt verwendet werden:
>> envelope = Envelope.objects.get(pk=1)
>> envelope.set_delivery_datetime()
>> pack = Package.objects.get(pk=1)
>> pack.set_delivery_datetime()
UUID Primärschlüssel
Standardmäßig verwendet ein Modell einen automatisch inkrementierenden (Ganzzahl) Primärschlüssel. Dadurch erhalten Sie eine Reihenfolge der Tasten 1, 2, 3.
Es können verschiedene Primärschlüsseltypen mit kleinen Änderungen am Modell festgelegt werden.
Eine UUID ist eine universell eindeutige Kennung. Dies ist eine 32-stellige Zufallskennung, die als ID verwendet werden kann. Dies ist eine gute Option, die verwendet werden soll, wenn keine sequentiellen IDs Datensätzen in Ihrer Datenbank zugewiesen werden sollen. Bei Verwendung in PostgreSQL wird dies in einem uuid-Datentyp gespeichert, andernfalls in einem Zeichen (32).
import uuid
from django.db import models
class ModelUsingUUID(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
Der generierte Schlüssel hat das Format 7778c552-73fc-4bc4-8bf9-5a2f6f7b7f47
Erbe
Die Vererbung zwischen Modellen kann auf zwei Arten erfolgen:
- eine allgemeine abstrakte Klasse (siehe Beispiel "Model Mixins")
- ein gemeinsames Modell mit mehreren Tabellen
Die Multi-Tabellen-Vererbung erstellt eine Tabelle für die allgemeinen Felder und eine pro Modellmodell:
from django.db import models
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
erstellt 2 Tabellen, eine für Place
und eine für Restaurant
mit einem versteckten OneToOne
Feld für Place
für die allgemeinen Felder.
Beachten Sie, dass dies jedes Mal, wenn Sie ein Restaurant-Objekt abrufen, eine zusätzliche Abfrage zu den Places-Tabellen erfordert.