Zum Inhalt

Das Signal

Ein Signal ist ein Mechanismus , der Ihren Code (Funktion/Methode) auslöst , wenn ein bestimmtes Ereignis in ormar auftritt .

Dazu müssen Sie einen Empfänger für einen bestimmten Signaltyp des ausgewählten Modells registrieren .

Definition der Empfänger

Geben Sie folgende Beispielmodelle :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
Import von Datenbanken
Import von Sqlalchemy

Der Import von Ormar


Die Abbildung zeigt die Konfidenzintervalle für die Konfidenzintervalle (
    Datenbank = Datenbank . Datenbank (" sqlite ://db . sqlite ") ,
    metadata = sqlalchemy . metadata () , oder
)


Klasse Album (ormar . Modell) :
    ormar _ config = base _ ormar _ config . copy () (= Grundeinheit von ormar _ config . copy)

    id : int = ormar . Integer (primary _ key = true) (nicht bekannt)
    name : str = ormar . String (max _ length = 100)
    is _ best _ seller : bool = ormar . Boolean (default = False) [ Bearbeiten | Quelltext bearbeiten ]
    play _ count : int = ormar . Integer (default = 0) [ Bearbeiten | Quelltext bearbeiten ]

Zum Beispiel können Sie einen Trigger definieren , der gesetzt wird , wenn das Album mehr als 50 Mal abgespielt wird .album.isDer _ _ best _ seller Zustand .

Importieren Sie den pre _ update-Dekorator , um die folgende Liste der derzeit verfügbaren Dekoratoren/Signale zu sehen .

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import asyncio

import databases
import ormar
import sqlalchemy
from examples import create_drop_database
from ormar import pre_update

DATABASE_URL = "sqlite:///test.db"

ormar_base_config = ormar.OrmarConfig(
    database=databases.Database(DATABASE_URL),
    metadata=sqlalchemy.MetaData(),
)


class Album(ormar.Model):
    ormar_config = ormar_base_config.copy(
        tablename="albums",
    )

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    is_best_seller: bool = ormar.Boolean(default=False)
    play_count: int = ormar.Integer(default=0)


@pre_update(Album)
async def before_update(sender, instance, **kwargs):
    if instance.play_count > 50 and not instance.is_best_seller:
        instance.is_best_seller = True


@create_drop_database(base_config=ormar_base_config)
async def run_query():
    # here album.play_count ans is_best_seller get default values
    album = await Album.objects.create(name="Venice")
    assert not album.is_best_seller
    assert album.play_count == 0

    album.play_count = 30
    # here a trigger is called but play_count is too low
    await album.update()
    assert not album.is_best_seller

    album.play_count = 60
    await album.update()
    assert album.is_best_seller


asyncio.run(run_query())

Definieren Sie Ihre Funktionen .

Beachten Sie , dass jede Empfängerfunktion :

  • Es muss abgeschickt werden .
  • Sie müssen den ersten Senderparameter der sendenden Objektklasse akzeptieren .
  • muss den Parameter **kwargs als Parameter akzeptieren , die in jedem Ormar gesendet werden , und daher muss Ihre Funktion diese unterstützen .
  • Es muss asynchron sein , da die Rückrufe gesammelt und gewartet werden .

pre_update sendet derzeit nur einen anderen Parameter als den Absender, und es ist Instanz 1.

Beachten Sie, wie der pre_update-Dekorator den senders-Parameter akzeptiert, bei dem es sich um ein einzelnes Modell oder eine Liste von Modellen handelt, für die Sie den Signalempfänger ausführen möchten.

Derzeit ist es nicht möglich, alle Modelle sofort zu signalisieren, ohne explizit alle Modelle in die Empfängerregistrierung zu übergeben.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import asyncio

import databases
import ormar
import sqlalchemy
from examples import create_drop_database
from ormar import pre_update

DATABASE_URL = "sqlite:///test.db"

ormar_base_config = ormar.OrmarConfig(
    database=databases.Database(DATABASE_URL),
    metadata=sqlalchemy.MetaData(),
)


class Album(ormar.Model):
    ormar_config = ormar_base_config.copy(
        tablename="albums",
    )

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    is_best_seller: bool = ormar.Boolean(default=False)
    play_count: int = ormar.Integer(default=0)


@pre_update(Album)
async def before_update(sender, instance, **kwargs):
    if instance.play_count > 50 and not instance.is_best_seller:
        instance.is_best_seller = True


@create_drop_database(base_config=ormar_base_config)
async def run_query():
    # here album.play_count ans is_best_seller get default values
    album = await Album.objects.create(name="Venice")
    assert not album.is_best_seller
    assert album.play_count == 0

    album.play_count = 30
    # here a trigger is called but play_count is too low
    await album.update()
    assert not album.is_best_seller

    album.play_count = 60
    await album.update()
    assert album.is_best_seller


asyncio.run(run_query())

!!!note Beachten Sie, dass der Empfänger auf der Klassenebene-> definiert ist, so dass er alle Operationen für diese ormar. Model-Klasse ausführt/stoppt, selbst wenn Sie über eine Instance-Funktion verbunden/getrennt haben.

Beachten Sie, dass unsere neu erstellte Funktion über Instances und Instance-Klassen verfügt, sodass Sie auf Wunsch problemlos Datenbankabfragen innerhalb des Empfängers ausführen können.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import asyncio

import databases
import ormar
import sqlalchemy
from examples import create_drop_database
from ormar import pre_update

DATABASE_URL = "sqlite:///test.db"

ormar_base_config = ormar.OrmarConfig(
    database=databases.Database(DATABASE_URL),
    metadata=sqlalchemy.MetaData(),
)


class Album(ormar.Model):
    ormar_config = ormar_base_config.copy(
        tablename="albums",
    )

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    is_best_seller: bool = ormar.Boolean(default=False)
    play_count: int = ormar.Integer(default=0)


@pre_update(Album)
async def before_update(sender, instance, **kwargs):
    if instance.play_count > 50 and not instance.is_best_seller:
        instance.is_best_seller = True


@create_drop_database(base_config=ormar_base_config)
async def run_query():
    # here album.play_count ans is_best_seller get default values
    album = await Album.objects.create(name="Venice")
    assert not album.is_best_seller
    assert album.play_count == 0

    album.play_count = 30
    # here a trigger is called but play_count is too low
    await album.update()
    assert not album.is_best_seller

    album.play_count = 60
    await album.update()
    assert album.is_best_seller


asyncio.run(run_query())

Sie können denselben Empfänger für mehrere Modelle gleichzeitig definieren, indem Sie die Modellliste an den Signaldekorator weitergeben.

1
2
3
4
Definieren einer Dummy Debug-Funktion
@ pre_update ([Album, Track])(Englisch)
async def before_update (sender, instance, ** kwargs):
    für{sender.get_name()}:{instance.model_dump_json()}:{kwargs}

Natürlich können Sie auch mehrere Funktionen für das gleiche Signal und Modell erstellen, von denen jeder zu jedem Zeitpunkt ausgeführt wird.

1
2
3
4
5
6
7
@ pre_update (Übersicht)
async def before_update (sender, instance, ** kwargs):
    Zeichen (f){sender.get_name()}: {instance.model_dump_json()}: {kwargs}")

@ pre_update (Übersicht)
async def before_update2 (sender, instance, ** kwargs):
    print (f'About to update{sender.get_name()}with pk:{instance.pk}') Übersetzung

Beachten Sie, dass Ormar Dekoratoren syntaktisch Zucker sind und Sie die Funktion oder Methode eines bestimmten Signals in einem bestimmten Modell direkt verbinden können, indem Connect nur einen Parameter akzeptiert-Ihre Empfängerfunktion/-methode.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
Der Klassen-Albumauditor:
    def__init__(sich selbst):
        Ereignis_typ ="ALBUM_INSTANCE"

    async def before_save (self, sender, instance, ** kwargs):
        Die Prüfung der Logdatei (
            event_type = f "{self.event_type}_SAVE", event_log = instance. model_dump_json ()()(für Event-Typ = xphbafox_SAVE)
        und Save ()

Audiodatei = Audiodatei ()
pre _ save (Album) (auditor . before _ save) (Übersetzung)
# call above has same result like the one below/call above hat dasselbe Ergebnis wie das eine
Album . ormar _ config . signals . pre _ save . connect (auditor . before _ save) (Übersetzung)
# Signale werden auch auf dem Display angezeigt
Album = Album (name ='Miami ') (Übersetzung)
Album . signals . pre _ save . connect (auditor . before _ save) Bearbeiten

Warnung Beachten Sie , dass das Signal einen Verweis auf den Empfänger behält (im Gegensatz zu einem schwachen Verweis) , also denken Sie daran , um wiederkehrende Referenzen zu vermeiden .

Verbindung mit dem Empfänger trennen .

Um den Empfänger zu trennen und die Ausführung eines bestimmten Modells zu stoppen , müssen Sie ihn trennen .

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@pre _ update (Übersicht)
async def before _ update (sender , instance , * * kwargs) :
    Wenn derinstance.play> 50 und nichtinstance.is_ Beste _ Verkäufer :
        instance.is_ best _ seller = wahr

# disconnect gibt Signal vom Given-Modell
Album . ormar _ config . signals . pre _ save . disconnect (before _ save) Übersetzung
# Signale werden auch auf dem Display angezeigt
Album = Album (name ='Miami ') (Übersetzung)
pre _ save . disconnect (before _ save) [ Bearbeiten | Quelltext bearbeiten ]

Signal zur Verfügung .

!!!Bitte beachten Sie , dass keine Signale gesendet werden :

1
2
3
4
*  Bulk-Operationen (`QuerySet.bulk_create` und `QuerySet.bulk_update`) sind für Geschwindigkeit konzipiert .

*  queryset table level operations (`QuerySet.update` und `QuerySet.delete`) , wie sie auf den underlying tables laufen
(more like raw sql update/delete operations) and do not have specific instance (= SQL aktualisieren/löschen) and do not have specific instance (= keine spezifische Instanz) .

Pre-Erhaltung

pre_save(sender: Type["Model"], instance: "Model")

SendenModel.saveDie Methode Model . objects . create () wird unterstützt .

sender ist eine ormar . Model-Klasse und instance ist das zu speichernde Modell .

Nach der Erhaltung

post_save(sender: Type["Model"], instance: "Model")

SendenModel.saveDie Methode Model . objects . create () wird verwendet .

sender ist eine ormar . Model-Klasse und instance ist das gespeicherte Modell .

Vorschau aktualisiert

pre_update(sender: Type["Model"], instance: "Model")

Senden Sie an die Methode Model . update () .

sender ist eine ormar . Model-Klasse und instance ist das zu aktualisierende Modell .

Nach der Aktualisierung

post_update(sender: Type["Model"], instance: "Model")

Senden Sie an die Model . update () - Methode .

sender ist eine ormar . Model-Klasse und instance ist ein aktualisiertes Modell .

Pre-Streichung

pre_delete(sender: Type["Model"], instance: "Model")

sendenModel.saveDie Methode Model . objects . create () wird unterstützt .

sender ist eine ormar . Model-Klasse und instance ist das zu löschende Modell .

Nach Streichung

post_delete(sender: Type["Model"], instance: "Model")

Senden Sie an die Model . update () - Methode .

sender ist eine ormar . Model-Klasse und instance ist das gelöschte Modell .

Vorher-Beziehung hinzufügen

pre_relation_add(sender: Type["Model"], instance: "Model", child: "Model", relation_name: str, passed_args: Dict)

Die Model . relation \ _ name . add () - Methode , die eine Mehr-zu - Mehr-Beziehung sendet , dreht die Fremdschlüsselbeziehung um .

sender-class , instance - Hinzufügen einer Instanz des zugehörigen Modells , child - Modell , das hinzugefügt wird , relation \ _ name - Name der Beziehung , in der Unterelemente hinzugefügt werden , für das Hinzufügen von Signalen auch übergeben \ _ kwargs - Dictionary für kwargs , die an add () übergeben werden

Post-Beziehung hinzufügen

post_relation_add(sender: Type["Model"], instance: "Model", child: "Model", relation_name: str, passed_args: Dict)

Die Model . relation \ _ name . add () - Methode , die eine Mehr-zu - Mehr-Beziehung sendet , dreht die Fremdschlüsselbeziehung um .

sender-class , instance - Hinzufügen einer Instanz des zugehörigen Modells , child - Modell , das hinzugefügt wird , relation \ _ name - Name der Beziehung , in der Unterelemente hinzugefügt werden , für das Hinzufügen von Signalen wird auch übergeben \ _ kwargs - Dictionary für kwargs , die an add () übergeben werden

Vorhersage-Beziehung abgeschafft

pre_relation_remove(sender: Type["Model"], instance: "Model", child: "Model", relation_name: str)

Die Model . relation \ _ name . remove () - Methode , die eine Mehr-zu - Mehr-Beziehung sendet , ist die Umkehrung der Fremdschlüsselbeziehung .

sender-Klasse, instance-Hinzufügen einer Instanz des zugehörigen Modells, child-Das hinzugefügte Modell, relation_name-Name der Beziehung, in der das Unterelement hinzugefügt wird.

Nach Beendigung der Beziehung

post_relation_remove(sender: Type["Model"], instance: "Model", child: "Model", relation_name: str, passed_args: Dict)

Die Model. relation_name. remove ()-Methode, die eine Mehr-zu-Mehr-Beziehung sendet, ist die Umkehrung der Fremdschlüsselbeziehung.

sender-Klasse, instance-Hinzufügen einer Instanz des zugehörigen Modells, child-Das hinzugefügte Modell, relation_name-Name der Beziehung, in der das Unterelement hinzugefügt wird.

Nach der Aktualisierung der Menge

post_bulk_update(sender: Type["Model"], instances: List["Model"], **kwargs), das an die Model.objects.bulk_update(List[objects])-methode gesendet wird.

Definieren Sie Ihr eigenes Signal

Beachten Sie, dass Sie Ihre eigenen Signale erstellen können, obwohl Sie sie manuell im Code oder in einer Unterklasse von ormar. Model senden und dort das Signal auslösen müssen.

Das folgende Beispiel legt ein neues Signal mit dem Namen your_custom_signal fest.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
Importieren von Datenbanken
Import von Sqlalchemy

Der Import von Ormar


Die Abbildung zeigt die Konfidenzintervalle für die Konfidenzintervalle: (
    Datenbank = Datenbank. Datenbank ("sqlite://db. sqlite"),
    metadata = sqlalchemy. metadata (), oder
)


Klasse Album (ormar. Modell):
    ormar_config = base_ormar_config. copy ()(= Grundeinheit von ormar_config. copy)

    id: int = ormar. Integer (primary_key = true)(nicht bekannt)
    name: str = ormar. String (max_length = 100)[Bearbeiten | Quelltext bearbeiten]
    is_best_seller: bool = ormar. Boolean (default = False)[Bearbeiten | Quelltext bearbeiten]
    play_count: int = ormar. Integer (default = 0)[Bearbeiten | Quelltext bearbeiten]

Zeichen. ihr_custom_signal = ormar. signal ()
Album. ormar_config. signals. your_custom_signal. connect (your_receiver_name)(Ihr_Empfänger_Name)

In der Tat ist die zugrunde liegende Ebene des Signals eine SignalEmiter-Instanz, die das Wörterbuch der bekannten Signale speichert und Ihnen erlaubt, auf sie als Eigenschaften zuzugreifen Wenn Sie versuchen, auf ein nicht vorhandenes Signal zuzugreifen, erstellt SignalEmiter ein Signal für Sie.

So kann das obige Beispiel vereinfacht werden, um das Signal für Sie zu erstellen.

1
Album. ormar_config. signals. your_custom_signal. connect (your_receiver_name)[Bearbeiten | Quelltext bearbeiten]

Um dieses Signal jetzt auszulösen, müssen Sie die Methode zum Senden des Signals aufrufen.

1
await Album. ormar_config. signals. your_custom_signal. send (sender = Album)(Übersetzung)

Beachten Sie, dass sender der einzige erforderliche Parameter ist und die ormar-Model-Klasse sein sollte.

Die zusätzlichen Parameter müssen als Schlüsselwortparameter übergeben werden.

1
await Album. ormar_config. signals. your_custom_signal. send (sender = Album, my_param = True)(Übersetzung)