Szukaj…


Wprowadzenie

W podstawowym przypadku modelem jest klasa Python, która jest odwzorowywana na pojedynczą tabelę bazy danych. Atrybuty mapy klas do kolumn w tabeli i instancja klasy reprezentuje wiersz w tabeli bazy danych. Modele dziedziczą po django.db.models.Model który zapewnia bogate API do dodawania i filtrowania wyników z bazy danych.

Stwórz swój pierwszy model

Tworzenie pierwszego modelu

Modele są zazwyczaj zdefiniowane w pliku models.py w podkatalogu aplikacji. Klasa Model modułu django.db.models to dobra klasa początkowa do rozszerzenia modeli. Na przykład:

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

Każdy atrybut w modelu reprezentuje kolumnę w bazie danych.

  • title jest tekstem o maksymalnej długości 100 znaków
  • author jest ForeignKey który reprezentuje związek z innym modelem / tabelą, w tym przypadku Author (używanym tylko dla celów). on_delete informuje bazę danych, co zrobić z obiektem, jeśli powiązany obiekt ( Author ) zostanie usunięty. (Należy zauważyć, że ponieważ django 1.9 on_delete może być użyty jako drugi argument pozycyjny. W django 2 jest to wymagany argument i zaleca się, aby traktować go jako taki. W starszych wersjach domyślnie będzie to CASCADE .)
  • publish_date przechowuje datę. Zarówno null jak i blank są ustawione na True aby wskazać, że nie jest to pole wymagane (tj. Możesz dodać je później lub pozostawić puste).

Wraz z atrybutami definiujemy metodę __str__ zwraca tytuł książki, która będzie w razie potrzeby używana jako jej string , a nie domyślny.

Stosowanie zmian w bazie danych (migracje)

Po utworzeniu nowego modelu lub zmodyfikowaniu istniejących modeli konieczne będzie wygenerowanie migracji dla wprowadzonych zmian, a następnie zastosowanie migracji do określonej bazy danych. Można to zrobić za pomocą wbudowanego systemu migracji Django. Korzystanie z narzędzia manage.py w katalogu głównym projektu:

python manage.py makemigrations <appname>

Powyższe polecenie utworzy skrypty migracji, które są niezbędne w podkatalogu migrations aplikacji. <appname> parametru <appname> spowoduje przetworzenie wszystkich aplikacji zdefiniowanych w argumencie INSTALLED_APPS settings.py . Jeśli uznasz to za konieczne, możesz edytować migracje.

Możesz sprawdzić, jakie migracje są wymagane bez faktycznego tworzenia migracji, użyj opcji --dry-run, np .:

python manage.py makemigrations --dry-run

Aby zastosować migracje:

python manage.py migrate <appname>

Powyższe polecenie wykona skrypty migracji wygenerowane w pierwszym kroku i fizycznie zaktualizuje bazę danych.

Jeśli model istniejącej bazy danych zostanie zmieniony, konieczne jest wykonanie następującego polecenia w celu wprowadzenia niezbędnych zmian.

python manage.py migrate --run-syncdb

Django domyślnie utworzy tabelę o nazwie <appname>_<classname> nazwa klasy <appname>_<classname> . Czasami nie chcesz go używać. Jeśli chcesz zmienić domyślną nazwę, możesz ogłosić nazwę tabeli, ustawiając db_table w klasie Meta :

from django.db import models

class YourModel(models.Model):
    parms = models.CharField()
    class Meta:
        db_table = "custom_table_name"

Jeśli chcesz zobaczyć, jaki kod SQL zostanie wykonany przez określoną migrację, po prostu uruchom następującą komendę:

python manage.py sqlmigrate <app_label> <migration_number>

Django> 1.10
Nowa opcja makemigrations --check powoduje, że polecenie kończy działanie z niezerowym statusem, gdy wykryte zostaną zmiany modelu bez migracji.

Zobacz Migracje, aby uzyskać więcej informacji na temat migracji.

Tworzenie modelu z relacjami

Relacja wiele do jednego

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()

Najbardziej ogólna opcja. Może być używany wszędzie tam, gdzie chcesz reprezentować związek

Relacja wiele do wielu

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)

Wewnętrznie jest to reprezentowane przez inną tabelę. I ManyToManyField należy umieścić na modelach, które będą edytowane w formularzu. Np .: Appointment będzie miało ManyToManyField nazwie Customer , Pizza ma Toppings i tak dalej.

Relacje wiele do wielu za pomocą klas „Through”

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)

W ten sposób możemy zachować więcej metadanych dotyczących relacji między dwoma podmiotami. Jak widać, klient może subskrybować kilka usług za pośrednictwem kilku rodzajów subskrypcji. Jedyną różnicą w tym przypadku jest to, że aby dodać nowe instancje do relacji M2M, nie można użyć metody skrótu pizza.toppings.add(topping) , zamiast tego należy utworzyć nowy obiekt klasy przelotowej , Subscription.objects.create(client=client, service=service, subscription_type='p')

W innych językach through tables są również znane jako JoinColumn , Intersection table lub mapping table

Relacja jeden do jednego

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)

Użyj tych pól, jeśli będziesz mieć tylko związek między dwoma modelami.

Podstawowe zapytania DB Django

Django ORM to potężna abstrakcja, która pozwala przechowywać i pobierać dane z bazy danych bez samodzielnego pisania zapytań SQL.

Załóżmy następujące modele:

class Author(models.Model):
   name = models.CharField(max_length=50)

class Book(models.Model): 
   name = models.CharField(max_length=50)
   author = models.ForeignKey(Author)

Zakładając, że dodałeś powyższy kod do aplikacji django i uruchom komendę migrate (aby tworzona była baza danych). Uruchom powłokę Django przez

python manage.py shell

Spowoduje to uruchomienie standardowej powłoki Pythona, ale z zaimportowanymi odpowiednimi bibliotekami Django, dzięki czemu można bezpośrednio skupić się na ważnych częściach.

Zacznij od zaimportowania właśnie zdefiniowanych modeli (zakładam, że odbywa się to w pliku models.py )

from .models import Book, Author

Uruchom pierwsze wybrane zapytanie:

>>> Author.objects.all() 
[]
>>> Book.objects.all()
[]

Utwórzmy autora i zarezerwuj obiekt:

>>> hawking = Author(name="Stephen hawking")
>>> hawking.save()
>>> history_of_time = Book(name="history of time", author=hawking)
>>> history_of_time.save()

lub użyj funkcji tworzenia, aby utworzyć obiekty modelu i zapisać w jednym wierszu kodu

>>> wings_of_fire = Book.objects.create(name="Wings of Fire", author="APJ Abdul Kalam")

Teraz uruchommy zapytanie

>>> Book.objects.all()
[<Book: Book object>]
>>> book = Book.objects.first() #getting the first book object
>>> book.name
u'history of time'

Dodajmy klauzulę where do naszego wybranego zapytania

>>> Book.objects.filter(name='nothing')
[]
>>> Author.objects.filter(name__startswith='Ste')
[<Author: Author object>]

Aby uzyskać szczegółowe informacje o autorze danej książki

>>> book = Book.objects.first() #getting the first book object
>>> book.author.name # lookup on related model
u'Stephen hawking'

Aby uzyskać wszystkie książki opublikowane przez Stephena Hawkinga (książka odnośnika autora)

>>> hawking.book_set.all()
[<Book: Book object>]

_set to notacja używana do „wyszukiwania wstecznego”, tzn. gdy pole wyszukiwania znajduje się w modelu Book, możemy użyć book_set na obiekcie autora, aby uzyskać wszystkie jego / jej książki.

Podstawowy niezarządzany stół.

W pewnym momencie korzystania z Django możesz chcieć wchodzić w interakcje z już utworzonymi tabelami lub z widokami bazy danych. W takich przypadkach nie chcesz, aby Django zarządzał tabelami podczas migracji. Aby to skonfigurować, musisz dodać tylko jedną zmienną do klasy Meta modelu swojego modelu: managed = False .

Oto przykład, w jaki sposób można utworzyć niezarządzany model do interakcji z widokiem bazy danych:

class Dummy(models.Model):
    something = models.IntegerField()

    class Meta:
       managed = False

Można to odwzorować na widok zdefiniowany w SQL w następujący sposób.

CREATE VIEW myapp_dummy AS 
SELECT id, something FROM complicated_table 
WHERE some_complicated_condition = True

Po utworzeniu tego modelu można go używać tak, jak każdego innego modelu:

>>> Dummy.objects.all()
[<Dummy: Dummy object>, <Dummy: Dummy object>, <Dummy: Dummy object>]
>>> Dummy.objects.filter(something=42)
[<Dummy: Dummy object>]

Zaawansowane modele

Model może dostarczyć znacznie więcej informacji niż tylko dane o obiekcie. Zobaczmy przykład i podzielmy go na użyteczne:

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']

Automatyczny klucz podstawowy

Możesz zauważyć użycie self.pk w metodzie get_absolute_url . Pole pk jest aliasem klucza podstawowego modelu. Ponadto django automatycznie doda klucz podstawowy, jeśli go brakuje. To o jedną rzecz mniej do zmartwienia i pozwala ustawić obcy klucz do dowolnych modeli i łatwo je zdobyć.

Bezwzględny adres URL

Pierwsza zdefiniowana get_absolute_url to get_absolute_url . W ten sposób, jeśli masz książkę, możesz uzyskać link do niej bez konieczności manipulowania tagiem url, rozdzielczością, atrybutem itp. Wystarczy zadzwonić na book.get_absolute_url a otrzymasz odpowiedni link. Jako bonus twój obiekt w admin django zyska przycisk „zobacz na stronie”.

Reprezentacja łańcucha

Metoda __str__ pozwala na użycie obiektu, gdy trzeba go wyświetlić. Na przykład w przypadku poprzedniej metody dodanie linku do książki w szablonie jest tak proste, jak <a href="{{ book.get_absolute_url }}">{{ book }}</a> . Od razu do rzeczy. Ta metoda kontroluje również to, co wyświetla się w menu administratora, na przykład dla klucza obcego.

Dekorator klas umożliwia jednokrotne zdefiniowanie metody zarówno dla __str__ jak i __unicode__ w pythonie 2, nie powodując przy tym problemu w pythonie 3. Jeśli spodziewasz się, że Twoja aplikacja będzie działała na obu wersjach, to jest właśnie ta droga.

Ślimakowe pole

Pole ślimaka jest podobne do pola char, ale akceptuje mniej symboli. Domyślnie tylko litery, cyfry, podkreślenia lub łączniki. Jest to przydatne, jeśli chcesz zidentyfikować obiekt za pomocą ładnej reprezentacji, na przykład w adresie URL.

Klasa Meta

Klasa Meta pozwala nam zdefiniować o wiele więcej informacji na temat całej kolekcji przedmiotu. Tutaj ustawia się tylko domyślne porządkowanie. Jest to przydatne na przykład w przypadku obiektu ListView. Do sortowania potrzeba idealnie krótkiej listy pól. Książka będzie sortowana najpierw według daty publikacji, a następnie według tytułu, jeśli data jest taka sama.

Inne atrybuty częstotliwości to verbose_name i verbose_name_plural . Domyślnie są one generowane na podstawie nazwy modelu i powinny być w porządku. Ale forma liczby mnogiej jest naiwna, po prostu dołącza „s” do liczby pojedynczej, więc w niektórych przypadkach możesz chcieć ustawić ją wyraźnie.

Obliczone wartości

Po pobraniu obiektu modelowego staje się on w pełni zrealizowaną instancją klasy. Jako takie, wszelkie dodatkowe metody są dostępne w formularzach i serializatorach (takich jak Django Rest Framework).

Korzystanie z właściwości Pythona to elegancki sposób reprezentowania dodatkowych wartości, które nie są przechowywane w bazie danych z powodu różnych okoliczności.

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

Podczas gdy w większości przypadków można uzupełniać dane adnotacjami w zestawach zapytań, wartości obliczone jako właściwości modelu są idealne do obliczeń, których nie można ocenić po prostu w ramach zapytania.

Ponadto właściwości, ponieważ są zadeklarowane w klasie python, a nie jako część schematu, nie są dostępne dla zapytań.

Dodanie ciągu reprezentującego model

Aby utworzyć czytelną dla człowieka prezentację obiektu modelu, należy zaimplementować metodę Model.__str__() (lub Model.__unicode__() na python2). Ta metoda będzie wywoływana za każdym razem, gdy wywołasz str() w instancji twojego modelu (włączając na przykład, kiedy model jest używany w szablonie). Oto przykład:

  1. Utwórz model książki.

    # 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. Utwórz instancję modelu i zapisz ją w bazie danych:

    >>> himu_book = Book(name='Himu Mama', author='Humayun Ahmed')
    >>> himu_book.save()
    
  3. Uruchom print() na instancji:

    >>> print(himu_book)
    <Book: Book object>
    

<Book: Book object> , domyślne wyjście, nam nie pomaga. Aby to naprawić, __str__ metodę __str__ .

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)

Uwaga: dekorator python_2_unicode_compatible z python_2_unicode_compatible jest potrzebny tylko, jeśli chcesz, aby kod był zgodny z python 2. Ten dekorator kopiuje metodę __str__ , aby utworzyć metodę __unicode__ . Zaimportuj go z django.utils.encoding .

Teraz, jeśli ponownie wywołamy funkcję drukowania wystąpieniem książki:

>>> print(himu_book)
Himu Mama by Humayun Ahmed

Dużo lepiej!

Reprezentacja ciągu jest również używana, gdy model jest używany w ModelForm dla pól ForeignKeyField i ManyToManyField .

Modelowe miksy

W tych samych przypadkach różne modele mogą mieć te same pola i te same procedury w cyklu życia produktu. Aby obsłużyć te podobieństwa bez dziedziczenia powtórzeń kodu, można zastosować dziedziczenie. Zamiast dziedziczenia całej klasy, wzorzec projektowania mixin oferuje nam odziedziczenie ( lub niektórzy twierdzą, że obejmują ) niektóre metody i atrybuty. Zobaczmy przykład:

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)

Aby przekształcić model w klasę abstrakcyjną, musisz wspomnieć abstract=True w wewnętrznej klasie Meta . Django nie tworzy żadnych tabel dla modeli abstrakcyjnych w bazie danych. Jednak w przypadku modeli Envelope i Package odpowiednie tabele zostałyby utworzone w bazie danych.

Ponadto w polach niektóre metody modelowe będą potrzebne w więcej niż jednym modelu. Tak więc metody te można dodać do mixin, aby zapobiec powtórzeniu kodu. Na przykład, jeśli stworzymy metodę ustawiania daty dostawy na PostableMixin , będzie ona dostępna dla obu jej dzieci:

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()

Metodę tę można zastosować w następujący sposób w przypadku dzieci:

>> envelope = Envelope.objects.get(pk=1)
>> envelope.set_delivery_datetime()

>> pack = Package.objects.get(pk=1)
>> pack.set_delivery_datetime()

UUID Klucz podstawowy

Model domyślnie używa klucza podstawowego z automatycznym zwiększaniem (liczby całkowitej). To da ci sekwencję klawiszy 1, 2, 3.

Różne typy kluczy głównych można ustawić w modelu z niewielkimi zmianami w modelu.

UUID jest uniwersalnym unikalnym identyfikatorem, jest to 32-znakowy losowy identyfikator, którego można użyć jako identyfikatora. Jest to dobra opcja do użycia, gdy nie chcesz, aby sekwencyjne identyfikatory były przypisywane do rekordów w bazie danych. Gdy jest używane w PostgreSQL, przechowuje to typ danych UUID, w przeciwnym razie char (32).

import uuid
from django.db import models

class ModelUsingUUID(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

Wygenerowany klucz będzie miał format 7778c552-73fc-4bc4-8bf9-5a2f6f7b7f47

Dziedzictwo

Dziedziczenie między modelami można wykonać na dwa sposoby:

  • wspólna klasa abstrakcyjna (patrz przykład „Model mixins”)
  • wspólny model z wieloma tabelami

Dziedziczenie wielu tabel utworzy jedną tabelę dla wspólnych pól i jedną na przykład modelu potomnego:

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)

utworzy 2 tabele, jedną dla Place i jedną dla Restaurant z ukrytym polem OneToOne do Place dla wspólnych pól.

zwróć uwagę, że będzie to wymagało dodatkowego zapytania do tabel miejsc za każdym razem, gdy pobierasz Obiekt restauracji.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow