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

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 ein ForeignKey der eine Beziehung zu einem anderen Modell / einer anderen Tabelle darstellt, in diesem Fall Author (wird nur zu Beispielzwecken verwendet). on_delete teilt der Datenbank mit, was mit dem Objekt zu tun ist, wenn das zugehörige Objekt (ein Author ) gelöscht wird. (Es sei darauf hingewiesen, dass seit django 1,9 on_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äßig CASCADE .)
  • publish_date speichert ein Datum. Sowohl null als auch blank sind auf True 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 als JoinColumn , Intersection table oder mapping 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:

  1. 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)
    
  2. 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()
    
  3. 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.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow