Pengelola

class Manager

Sebuah manager adalah antarmuka melalui mana tindakan permintaan basisdata disediakan pada model Django. Setidaknya satu Manager ada untuk setiap model dalam sebuah apliaksi Django.

Cara kelas-kelas Manager bekerja didokumentasikan dalam Membuat query; dokumen ini secara khusus menyentuh pada pilihan model yang menyesuaikan perilaku Manager.

Nama pengelola

Secara awalan, Django menambah sebuah Manager dengan nama objects pada setiap kelas model Django. Bagaimanapun, jika anda ingin menggunakan objects sebagai sebuah nama bidang, atau jika anda ingin menggunakan sebuah nama selain dari objects untuk Manager, anda dapat menamai kembali itu pada berdasarkan per-model. Untuk menamai kembali Manager untuk kelas diberikan, tentukan sebuah atribut kelas dari jenis models.Manager() pada model itu. Sebagai contoh:

from django.db import models


class Person(models.Model):
    # ...
    people = models.Manager()

Menggunakan model contoh ini, Person.objects akanmembangkitkan sebuah pengecualian AttributeError, tetapi Person.people.all() akan menyediakan daftar dari semua obyek Person.

Pengelolaan penyesuaian

Anda dapat menggunakan sebuah penyesuaian Manager dalam model tertentu dengan memperpanjang kelas Manager dasar dan menginstansiasi penyesuaian Manager anda dalam model anda.

Ada dua alasan anda mungkin ingin menyesuaikan sebuah Manager: untuk menambah metode Manager tambahan, dan/atau merubah QuerySet awal kembalian Manager.

Menambahkan metode pengelolaan tambahan

Menambahkan metode Manager tambahan adalah cara disukai untuk menambah fungsionalitas "table-level" pada model anda. (Untuk fungsionalitas "row-level" -- yaitu yang bertindak pada sebuah instance tunggal dari sebuah obyek model -- gunakan Model methods, bukan penyesuaian metode Manager.)

Sebagai contoh,``Manager`` penyesuaian ini menambahkan sebuah metode with_counts():

from django.db import models
from django.db.models.functions import Coalesce


class PollManager(models.Manager):
    def with_counts(self):
        return self.annotate(num_responses=Coalesce(models.Count("response"), 0))


class OpinionPoll(models.Model):
    question = models.CharField(max_length=200)
    objects = PollManager()


class Response(models.Model):
    poll = models.ForeignKey(OpinionPoll, on_delete=models.CASCADE)
    # ...

With this example, you'd use OpinionPoll.objects.with_counts() to get a QuerySet of OpinionPoll objects with the extra num_responses attribute attached.

Sebuah metode Manager penyesuaian dapat mengembalikan apapun anda inginkan. Itu tidak harus mengembalikan sebuah QuerySet.

Another thing to note is that Manager methods can access self.model to get the model class to which they're attached.

Merubah QuerySet awal pengelolaan

Dasar Manager QuerySet mengembalikan semua obyek-obyek di sistem. Sebagai contoh, menggunakan model ini:

from django.db import models


class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)

...pernyataan Book.objects.all() akan mengembalikan semua buku-buku di basisdata.

Anda dapat menimpa QuerySet dasar Manager dengan menimpa metode Manager.get_queryset(). get_queryset() harus mengembalikan sebuah QuerySet dengan sifat-sifat anda butuhkan.

Sebagai contoh, model berikut mempunyai dua Manager -- satu yang mengembalikan semua obyek, dan satu yang mengembalikan hanya buku-buku oleh Roald Dahl:

# First, define the Manager subclass.
class DahlBookManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(author="Roald Dahl")


# Then hook it into the Book model explicitly.
class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)

    objects = models.Manager()  # The default manager.
    dahl_objects = DahlBookManager()  # The Dahl-specific manager.

Dengan model contoh ini, Book.objects.all() akan mengembalikan semua buku-buku di basisdata, tetapi Book.dahl_objects.all() akan hanya mengembalikan satu yang ditulis oleh Roald Dahl.

Because get_queryset() returns a QuerySet object, you can use filter(), exclude() and all the other QuerySet methods on it. So these statements are all legal:

Book.dahl_objects.all()
Book.dahl_objects.filter(title="Matilda")
Book.dahl_objects.count()

This example also pointed out another interesting technique: using multiple managers on the same model. You can attach as many Manager() instances to a model as you'd like. This is a non-repetitive way to define common "filters" for your models.

Sebagai contoh:

class AuthorManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(role="A")


class EditorManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(role="E")


class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    role = models.CharField(max_length=1, choices={"A": _("Author"), "E": _("Editor")})
    people = models.Manager()
    authors = AuthorManager()
    editors = EditorManager()

Contoh ini mengizinkan anda meminta Person.authors.all()`, Person.editors.all(), dan Person.people.all(), menghasilkan hasil dapat diramalkan.

Pengelola awal

Model._default_manager

Jika anda menggunakan obyek Manager penyesuaian, ambil catatan bahwa Manager Django pertama hadapi (dalam urutan dimana mereka ditentukan dalam model) mempunyai sebuah keadaan khusus. Django menafsirkan Manager pertama ditentukan dalam sebuah kelas sebagai Manager "default", dan beberapa bagian dari Django (termasuk dumpdata) akan menggunakan yang Manager khusus untuk model itu. Sebagai sebuah hasil, itu adalah ide bagus untuk hati-hati dalam pilihan anda dari pengelola awalan untuk menghindari keadan dimana menimpa hasil get_queryset() dalam sebuah ketidakmampuan mengambil obyek-obyek anda sukai bekerja dengannya.

Anda dapat menentukan sebuah penyesuaian pengelolaan awalan menggunakan Meta.default_manager_name.

Jika anda sedang menulis beberapa kode yang harus menangani sebuah model tidak dikenal, sebagai contoh, dalam sebuah aplikasi pihak-ketiga yang menerapkan sebuah tampilan umum, gunakan pengelola ini (atau _base_manager) daripada beranggapan model mempunyai sebuah pengelola objects.

Pengelolaan dasar

Model._base_manager

Jangan menyaring hasil apapun dalam jenis ini dari pengelola subkelas

Pengelola ini digunakan untuk mengakses obyek yang terkait pada dari beberapa model lain. Dalam keadaan tersebut, Django harus dapat melihat semua obyek untuk model itu sedang diambil, sehingga apapun yang mengacu dapat diambil.

Therefore, you should not override get_queryset() to filter out any rows. If you do so, Django will return incomplete results.

Memanggil metode QuerySet penyesuaian dari pengelola

Selagi kebanyakan metode dari QuerySet standar dapat diakses langsung dari Manager, ini hanya kasus untuk metode tambahan ditentukan pada sebuah penyesuaian QuerySet jika anda juga menerapkan mereka pada Manager:

class PersonQuerySet(models.QuerySet):
    def authors(self):
        return self.filter(role="A")

    def editors(self):
        return self.filter(role="E")


class PersonManager(models.Manager):
    def get_queryset(self):
        return PersonQuerySet(self.model, using=self._db)

    def authors(self):
        return self.get_queryset().authors()

    def editors(self):
        return self.get_queryset().editors()


class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    role = models.CharField(max_length=1, choices={"A": _("Author"), "E": _("Editor")})
    people = PersonManager()

Contoh ini mengizinkan anda memanggil kedua authors() dan editors() secara langsung dari pengelola Person.people.

Membuat pengelola dengan cara QuerySet

Sebagai pengganti dari pendekatan diatas yang membutuhkan metode penggandaan pada kedua QuerySet dan Manager, QuerySet.as_manager() dapat digunakan untuk membuat sebuah instance dari Manager dengan salinan dari sebuah metode QuerySet penyesuaian:

class Person(models.Model):
    ...
    people = PersonQuerySet.as_manager()

Instance Manager dibuat oleh QuerySet.as_manager() akan secara virtual mirip pada PersonManager dari contoh sebelumnya.

Tidak setiap metode QuerySet masuk akal pada tingkat Manager; sebagai contoh kami sengaja mencegah metode QuerySet.delete() dari menjadi disalin ke atas kelas Manager.

Cara disalin berdasarkan aturan berikut:

  • Cara umum disalin secara awal.
  • Metode pribadi (mulai dengan sebuah garis bawah) tidak disalin secara awalan.
  • Metode dengan atribut queryset_only disetel menjadi False adalah selalu disalin.
  • Metode dengan atribut queryset_only disetel menjadi True adalah tidak pernah disalin.

Sebagai contoh:

class CustomQuerySet(models.QuerySet):
    # Available on both Manager and QuerySet.
    def public_method(self):
        return

    # Available only on QuerySet.
    def _private_method(self):
        return

    # Available only on QuerySet.
    def opted_out_public_method(self):
        return

    opted_out_public_method.queryset_only = True

    # Available on both Manager and QuerySet.
    def _opted_in_private_method(self):
        return

    _opted_in_private_method.queryset_only = False

from_queryset()

classmethod from_queryset(queryset_class)

Untuk penggunaan lanjutan anda mungkin ingin kedua penyesuaian Manager dan penyesuaian QuerySet. Anda dapat melakukan itu dengan memanggil Manager.from_queryset() yang mengembalikan sebuah subkelas dari dasar Manager anda dengan salinan dari metode QuerySet penyesuaian:

class CustomManager(models.Manager):
    def manager_only_method(self):
        return


class CustomQuerySet(models.QuerySet):
    def manager_and_queryset_method(self):
        return


class MyModel(models.Model):
    objects = CustomManager.from_queryset(CustomQuerySet)()

Anda mungkin juga menyimpan kelas dibangkitkan kedalam sebuah variabel:

MyManager = CustomManager.from_queryset(CustomQuerySet)


class MyModel(models.Model):
    objects = MyManager()

Pengelolaan penyesuaian dan warisan model

Ini adalah bagaimana Django menangani pengelolaan penyesuaian dan model inheritance:

  1. Pengelola dari kelas-kelas dasar selalu diwarisi oleh anak kelas, menggunakan urutan resolusi nama biasa Python (nama pada kelas anan menimpa semua lainnya; kemudian datang nama pada kelas induk pertama, dan seterusnya).
  2. Jika tidak ada pengelola dinyatakan pada model dan/atau induknya, Django secara otomatis membuat pengelola objects.
  3. Pengelola awalan pada sebuah kelas adalah antara satu dipilih dengan Meta.default_manager_name, atau pengelola pertama dinyatakan pada model, atau pengelola awalan dari model induk pertama.

Aturan-aturan ini menyediakan keluwesan yang dibutuhkan jika anda ingin memasang sebuah kumpulan dari penyesuaian pengelola pada sekelompok model, melalui sebuah kelas dasar, tetapi masih menyesuaikan pengelola awalan. Sebagai contoh, misalkan anda mempunyai kelas dasar ini:

class AbstractBase(models.Model):
    # ...
    objects = CustomManager()

    class Meta:
        abstract = True

If you use this directly in a child class, objects will be the default manager if you declare no managers in the child class:

class ChildA(AbstractBase):
    # ...
    # This class has CustomManager as the default manager.
    pass

Jika anda ingin mewarisi dari AbstractBase, tetapi menyediakan pengelola awalan berbeda, anda dapat menyediakan pengelola awalan pada kelas anak:

class ChildB(AbstractBase):
    # ...
    # An explicit default manager.
    default_manager = OtherManager()

Here, default_manager is the default. The objects manager is still available, since it's inherited, but isn't used as the default.

Akhirnya untuk contoh ini, misalkan anda ingin menambah pengelola tambahan pada kelas anak, tetapi masih menggunakan awalan dari AbstractBase. Anda tidak dapat menambah pengelola baru langsung dalam kelas anak, seperti itu akan menimpa awalan dan anda akan juga jelas menyertakan semua pengelola dari kelas dasar abstrak. Pemecahannya adalah menaruh pengelola tambahan dalam kelas dasar lain dan memperkenalkan itu kedalam hirarki warisan setelah awalan:

class ExtraManager(models.Model):
    extra_manager = OtherManager()

    class Meta:
        abstract = True


class ChildC(AbstractBase, ExtraManager):
    # ...
    # Default manager is CustomManager, but OtherManager is
    # also available via the "extra_manager" attribute.
    pass

Catat bahwa selagi anda dapat menentukan pengelolaan penyesuaian pada model abstrak, anda tidak dapat meminta metode apapun menggunakan model abstrak. Yaitu:

ClassA.objects.do_something()

legal, tetapi:

AbstractBase.objects.do_something()

akan memunculkan sebuah pengecualian. Ini karena pengelola bermaksud untuk mengenkapsulasi logika untuk mengelola kumpulan dari obyek. Sejak anda tidak dapat mempunyai sebuah kumpulan dari obyek-obyek abstrak, itu tidak masuk akal untuk mengelola mereka. Jika anda mempunyai fungsionalitas yang berlaku pada model abstrak, anda harus menaruh fungsionalitas itu dalam sebuah staticmethod atau classmethod pada model abstrak.

Perhatian penerapan

Whatever features you add to your custom Manager, it must be possible to make a shallow copy of a Manager instance; i.e., the following code must work:

>>> import copy
>>> manager = MyManager()
>>> my_copy = copy.copy(manager)

Django membuat salinan dangkal dari obyek-obyek pengelola selama permintaan tertentu; jika Manager anda tidak dapat disalin, permintaan itu akan gagal.

Ini tidak akan menjadi sebuah masalah untuk kebanyakan pengelola penyesuaian. Jika anda hanya menambahkan metode sederhana ke Manager anda, itu tidak mungkin bahwa anda akan secara tidak sengaja membuat instance-instance dari tidak dapat disalin Manager anda. Bagaimanapun, jika anda menimpa __getattr__ atau beberapa metode pribadi lain dari obyek Manager anda yang mengendalikan keadaan obyek, anda harus memastikan bahwa anda tidak mempengaruhi kemampuan dari Manager anda untuk disalin.