Kerangka sistem pemeriksaan

Kerangka sistem pemeriksaan adalah kumpulan dari pemeriksaan tetap untuk memeriksa kebenaran proyek Django. Dia menemukan masalah umum dan menyediakan petunjuk untuk bagaimana memperbaiki mereka. Kerangka ini dapat diperpanjang sehingga anda dapat dengan mudah menambahkan pemeriksaan anda sendiri.

Pemeriksaan dapat dibangkitkan jelas melalui perintah check. Pemeriksaan dipicu tidak langsung sebelum kebanyakan perintah, termasuk runserver dan migrate. Untuk alasan penampilan, pemeriksaan tidak berjalan sebagai bagian dari tumpukan WSGI yang digunakan dalam pengembangan. Jika anda butuh menjalankan pemeriksaan sistem pada peladen pengembangan anda, picu mereka dengan jelas menggunakan check.

Kesalahan-kesalahan serius akan mencegah perintah Django (seperti runserver) dari menjalankan sama sekali. Masalah-masalah dilaporkan ke konsol. Jika anda telah memeriksa penyebab dari peringatan dan senang mengabaikan itu, anda dapat memyembunyikan peringatan khusus menggunakan pengaturan SILENCED_SYSTEM_CHECKS di berkas pengaturan proyek anda.

Sebuah daftar penuh dari semua pemeriksaan yang dapat dimunculkan oleh Django dapat ditemukan di System check reference.

Menulis pemeriksaan anda sendiri

Kerangka kerja fleksibel dan mengizinkan anda menulis fungsi-fungsi yang melakukan jenis lain pemeriksaan anda mungkin butuhkan. Berikut adalah sebuah contoh potongan fungsi pemeriksaan:

from django.core.checks import Error, register


@register()
def example_check(app_configs, **kwargs):
    errors = []
    # ... your check logic here
    if check_failed:
        errors.append(
            Error(
                "an error",
                hint="A hint.",
                obj=checked_object,
                id="myapp.E001",
            )
        )
    return errors

The check function must accept an app_configs argument; this argument is the list of applications that should be inspected. If None, the check must be run on all installed apps in the project.

The check will receive a databases keyword argument. This is a list of database aliases whose connections may be used to inspect database level configuration. If databases is None, the check must not use any database connections.

Argumen **kwargs diperlukan untuk perluasan di masa mendatang.

Pesan

Fungsi harus mengembalikan sebuah daftar pesan. Jika tidak ada masalah ditemukan sebagai hasil dari pemeriksaan, fungsi pemeriksaaan harus mengembalikan sebuah daftar kosong.

Peringatan dan kesalahan dimunculkan oleh metode pemeriksaan harus berupa instance dari CheckMessage. Sebuah instance dari CheckMessage membungkus kesalahan tunggal dilaporkan atau peringatan. Itu juga menyediakan konteks dan petunjuk dapat diterapkan ke pesan, dan penciri unik yang digunakan untuk tujuan penyaringan.

Konsep sangat mirip ke pasan dari message framework atau the logging framework. Pesan-pesan dietiket dengan level menunjukkan kekerasan pesan.

Ada juga jalan pintas untuk membuat pesan dengan tingkatan umum lebih mudah. Ketika menggunakan kelas-kelas ini anda dapat menghilangkan argumen level karena itu disisipkan oleh nama kelas.

Mendaftarkan dan melabeli pemeriksaan

Akhirnya, fungsi pemeriksaan anda harus terdaftar jelas dengan sistem pemeriksaan regristrar. Pemeriksaan harus didaftarkan dalam sebuah berkas yang dimuat ketika aplikasi anda dimuat; sebagai contoh, di metode AppConfig.ready().

register(*tags)(function)

Anda dapat melewatkan sebanyak etiket ke register seperti anda inginkan untuk melabelkan pemeriksaan anda. Pemeriksaan etiket sangat berguna sejak itu mengizinkan anda menjalankan hanya kelompok tertentu dari pemeriksaan. Sebagai contoh, untuk mendaftar pemeriksaan kesesuaian, anda akan membuat panggilan berikut:

from django.core.checks import register, Tags


@register(Tags.compatibility)
def my_check(app_configs, **kwargs):
    # ... perform compatibility checks and collect errors
    return errors

Anda dapat mendaftar "deployment checks" yang hanya bersangkutan pada berkas pengaturan produksi seperti ini:

@register(Tags.security, deploy=True)
def my_check(app_configs, **kwargs): ...

Pemeriksaan ini hanya akan dijalankan jika pilihan check --deploy digunakan.

Anda dapat juga menggunakan register sebagai sebuah fungsi daripada sebuah penghias dengan melewatkan obyek callable (biasanya sebuah fungsi) sebagai argumen pertama pada register

Kode dibawah ini setara dengan kode diatas:

def my_check(app_configs, **kwargs): ...


register(my_check, Tags.security, deploy=True)

Pemeriksaan bidang, model, pengelola, dan basisdata.

Dalam beberapa kasus, anda tidak butuh mendaftar fungsi pemeriksaan anda -- anda dapat mendukung pada pendaftaran yang ada.

Bidang, model, pengeloal model, dan backend basisdata semua menerapkan metode check() yang sudah terdaftar dengan kerangka kerja pemeriksaan. Jika anda ingin menambahkan pemeriksaan tambahan, anda dapat memperpanjang penerapan pada berdasarkan kelas, lakukan pemeriksaan tambahan apapun anda butuh, dan tambahkan pesan apapun ke itu dibangkitkan oleh kelas dasar. Itu dianjurkan bahwa anda menugaskan setiap pemeriksaan untuk memisahkan metode.

Pertimbangkan sebuah contoh dimana anda sedang menerapkan bidang penyesuaian bernama RangedIntegerField. Bidang ini menambahkan argumen min dan max pada pembangun dari IntegerField. Anda mungkin ingin menambah sebuah pemeriksaan untuk memastikan bahwa pengguna menyediakan nilai minimal yang kurang atau setara pada nilai maksimal. Potongan kode berikut menunjukkan anda dapat menerapkan pemeriksaan ini:

from django.core import checks
from django.db import models


class RangedIntegerField(models.IntegerField):
    def __init__(self, min=None, max=None, **kwargs):
        super().__init__(**kwargs)
        self.min = min
        self.max = max

    def check(self, **kwargs):
        # Call the superclass
        errors = super().check(**kwargs)

        # Do some custom checks and add messages to `errors`:
        errors.extend(self._check_min_max_values(**kwargs))

        # Return all errors and warnings
        return errors

    def _check_min_max_values(self, **kwargs):
        if self.min is not None and self.max is not None and self.min > self.max:
            return [
                checks.Error(
                    "min greater than max.",
                    hint="Decrease min or increase max.",
                    obj=self,
                    id="myapp.E001",
                )
            ]
        # When no error, return an empty list
        return []

Jika anda ingin menambah pemeriksaan pada pengelola model, anda akan mengambil pendekatan sama pada subkelas anda dari Manager.

Jika anda ingin menambah sebuah pemeriksaan pada kelas model, pendekatan adalah hampir sama: perbedaan hanya bahwa pemeriksaan adalah metode kelas, bukan metode instance:

class MyModel(models.Model):
    @classmethod
    def check(cls, **kwargs):
        errors = super().check(**kwargs)
        # ... your own checks ...
        return errors

Menulis percobaan

Pesan dapat dibandingkan. Itu mengizinakan anda dengan mudah menulis percobaan:

from django.core.checks import Error

errors = checked_object.check()
expected_errors = [
    Error(
        "an error",
        hint="A hint.",
        obj=checked_object,
        id="myapp.E001",
    )
]
self.assertEqual(errors, expected_errors)

Writing integration tests

Given the need to register certain checks when the application loads, it can be useful to test their integration within the system checks framework. This can be accomplished by using the call_command() function.

For example, this test demonstrates that the SITE_ID setting must be an integer, a built-in check from the sites framework:

from django.core.management import call_command
from django.core.management.base import SystemCheckError
from django.test import SimpleTestCase, modify_settings, override_settings


class SystemCheckIntegrationTest(SimpleTestCase):
    @override_settings(SITE_ID="non_integer")
    @modify_settings(INSTALLED_APPS={"prepend": "django.contrib.sites"})
    def test_non_integer_site_id(self):
        message = "(sites.E101) The SITE_ID setting must be an integer."
        with self.assertRaisesMessage(SystemCheckError, message):
            call_command("check")

Consider the following check which issues a warning on deployment if a custom setting named ENABLE_ANALYTICS is not set to True:

from django.conf import settings
from django.core.checks import Warning, register


@register("myapp", deploy=True)
def check_enable_analytics_is_true_on_deploy(app_configs, **kwargs):
    errors = []
    if getattr(settings, "ENABLE_ANALYTICS", None) is not True:
        errors.append(
            Warning(
                "The ENABLE_ANALYTICS setting should be set to True in deployment.",
                id="myapp.W001",
            )
        )
    return errors

Given that this check will not raise a SystemCheckError, the presence of the warning message in the stderr output can be asserted like so:

from io import StringIO

from django.core.management import call_command
from django.test import SimpleTestCase, override_settings


class EnableAnalyticsDeploymentCheckTest(SimpleTestCase):
    @override_settings(ENABLE_ANALYTICS=None)
    def test_when_set_to_none(self):
        stderr = StringIO()
        call_command("check", "-t", "myapp", "--deploy", stderr=stderr)
        message = (
            "(myapp.W001) The ENABLE_ANALYTICS setting should be set "
            "to True in deployment."
        )
        self.assertIn(message, stderr.getvalue())