Ga naar inhoud

signaal

Een signaal is een mechanisme dat uw code (functie / methode) activeert wanneer een bepaald type gebeurtenis zich voordoet in ormar.

Daarom moet u de ontvanger registreren voor het gegeven type signaal van het geselecteerde model.

Definieer de ontvanger

Het volgende voorbeeldmodel wordt gegeven:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
Databanken importeren
Sqlalchemie invoeren

Ormar importeren


basis _ ormar _ config = ormar. OrmarConfig (
    Database = databanken. Database ("sqlite: / / db.sqlite"),
    Metadata = sqlalchemie. MetaData (),
)


Klasse Album (ormar. Model):
    ormar _ config = basis _ ormar _ config kopie ()

    Id: int = ormar. Geheel getal (primaire _ sleutel = waar)
    Naam: str = ormar. String (max _ length = 100)
    is _ best _ seller: bool = ormar. Booleaans (standaard = onwaar)
    play _ count: int = ormar. Geheel getal (standaard = 0)

U kunt bijvoorbeeld een trigger definiëren die de status album.is\ _ best\ _ seller instelt als het album meer dan 50 keer wordt afgespeeld.

Importeer pre\ _ update decorateurs en bekijk de lijst met momenteel beschikbare decorateurs / signalen hieronder.

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

Definieer uw functie.

Houd er rekening mee dat elke ontvanger beschikt over:

  • Moet opvraagbaar zijn
  • Moet het eerste afzenderargument van de klasse ontvangen-verzenden accepteren
  • moet het argument**kwargs accepteren als een argument dat in elke ormar wordt verzonden. Signalen kunnen op elk moment veranderen, dus uw functie moet ze dienen.
  • Het moet asynchroon zijn omdat terugbelverzoeken worden verzameld en wachten.

Pre\ _ update verzendt momenteel slechts één parameter naast de afzender en het is instantie één.

Merk op hoe de pre\ _ update-decorateur de afzenderparameter accepteert, wat een enkel model kan zijn of een lijst met modellen waarvoor u de signaalontvanger wilt gebruiken.

Op dit moment is het niet mogelijk om signalen voor alle modellen onmiddellijk in te stellen zonder alle modellen expliciet door te geven aan het register van de ontvanger.

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

!!!Merk op dat de ontvanger is gedefinieerd op klassenniveau - >, dus zelfs als u de functie via een instantie verbindt / verbreekt, zal deze alle bewerkingen op die ormar uitvoeren / stoppen. Modelklasse.

Houd er rekening mee dat onze nieuw gemaakte functie instanties en klassen van instanties heeft, zodat u desgewenst eenvoudig databasequery 's in de sink kunt uitvoeren.

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

U kunt dezelfde ontvanger voor meerdere modellen tegelijk definiëren door een lijst met modellen door te geven aan de signaaldecorateur.

1
2
3
4
# definieer een dummy-foutopsporingsfunctie
@ voor _ update ([Album, Track])
Async def before _ update (afzender, instantie, * * kwargs):
    Afdrukken (f "{sender.get_name()}:{instance.model_dump_json()}:{kwargs}")

Natuurlijk kunt u ook meerdere functies maken voor hetzelfde signaal en model. Elk van hen wordt op elk signaal uitgevoerd.

1
2
3
4
5
6
7
@ voorbewerking (album)
Async def before _ update (afzender, instantie, * * kwargs):
    Afdrukken (f "{sender.get_name()}:{instance.model_dump_json()}:{kwargs}")

@ voorbewerking (album)
Async def before _ update2 (afzender, instantie, * * kwargs):
    Afdrukken (f 'Op het punt om{sender.get_name()}bij te werken met pk:{instance.pk}')

Houd er rekening mee dat de ormar-decorateur syntactische suiker is en dat u functies of methoden van een bepaald signaal voor een bepaald model rechtstreeks kunt verbinden. Connect heeft slechts één argument nodig: uw ontvangerfunctie / -methode.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
Klasse AlbumAuditor:
    Def _ _ init _ _ (zelf):
        Zelfgebeurtenis _ type = "ALBUM _ INSTANCE"

    Async def before _ save (zelf, afzender, instantie, * * kwargs):
        In afwachting van AuditLog (
            event _ type = f "{self.event_type}_ SAVE", event _ log = instantie. model _ dump _ json ()
        ) .opslaan ()

Auteur = AlbumAuteur ()
voor _ opslaan (Album) (auditor. voor _ opslaan)
# De bovenstaande oproep heeft hetzelfde resultaat als de onderstaande
ormar _ config signalen pre _ save connect (auditor voor _ opslaan)
# signalen worden ook weergegeven op instanties
Album = Album (naam = 'Miami')
Album.signals.pre _ save connect (auditor. voor _ opslaan)

!!! Waarschuwing Houd er rekening mee dat het signaal een verwijzing naar de ontvanger behoudt (in plaats van een zwakke referentie), dus houd hier rekening mee om cirkelvormige verwijzingen te vermijden.

Ontkoppel de ontvanger

Om de ontvanger los te koppelen en te voorkomen dat een bepaald model wordt uitgevoerd, moet u deze loskoppelen.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@ voorbewerking (album)
Async def before _ update (afzender, instantie, * * kwargs):
    Als instantie. play _ count > 50 en niet instantie. is _ best _ seller:
        Voorbeeld. is _ best _ seller = Waar

# disconnect gegeven functie van signaal voor gegeven Model
Album. ormar _ config signals. voor _ opslaan (voor _ opslaan)
# signalen worden ook weergegeven op instanties
Album = Album (naam = 'Miami')
Album.signals.pre _ save verbreken (voor _ opslaan)

beschikbaar signaal

!!!Waarschuwing, houd er rekening mee dat er geen signaal wordt verzonden.

1
2
3
4
*  bulkbewerkingen (`QuerySet.bulk_create` en `QuerySet.bulk_update`) omdat ze zijn ontworpen voor snelheid.

*  QuerySet bewerkingen op tabelniveau (`QuerySet.update` en `QuerySet.delete`) als ze draaien op de onderliggende tabellen 
(Meer als ruwe sql-update- / verwijderbewerkingen) en hebben geen specifieke instanties.

vooraf opslaan

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

Stuur Model.save () en Model.objects.create () methoden.

Afzender is een ormar. Modelklasse, een exemplaar van het model dat moet worden opgeslagen.

Na het opslaan

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

Stuur Model.save () en Model.objects.create () methoden.

Afzender is een ormar. Modelklasse, een exemplaar van een opgeslagen model.

voorupdate

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

Verstuurd naar de methode Model.update ().

Afzender is een ormar. Modelklasse, een exemplaar van het model dat moet worden bijgewerkt.

Na bijwerking

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

Verstuurd naar de methode Model.update ().

Afzender is een ormar. Modelklasse, een exemplaar van een bijgewerkt model.

vooraf verwijderen

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

Stuur Model.save () en Model.objects.create () methoden.

Afzender is een ormar. Modelklasse, een exemplaar van het te verwijderen model.

na verwijdering

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

Verstuurd naar de methode Model.update ().

Afzender is een ormar. Modelklasse, een exemplaar van het model dat wordt verwijderd.

pre-relatie toevoeging

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

Stuurt de Model.relations\ _ name () -methode van de veel-op-veel-relatie en het omgekeerde van de externe sleutelrelatie.

Afzender - afzender klasse, instantie - voeg instantie van gerelateerd model toe, kind - model wordt toegevoegd, relatie\ _ naam - naam van relatie om kind toe te voegen, ook doorgegeven voor add signaal\ _ kwargs - woordenboek van kwargs doorgegeven om toe te voegen ()

post relatie toevoegen

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

Stuurt de Model.relations\ _ name () -methode van de veel-op-veel-relatie en het omgekeerde van de externe sleutelrelatie.

Afzender - afzender klasse, instantie - voeg instantie van gerelateerd model toe, kind - model wordt toegevoegd, relatie\ _ naam - naam van relatie om kind toe te voegen, ook doorgegeven voor add signaal\ _ kwargs - woordenboek van kwargs doorgegeven om toe te voegen ()

verwijdering vóór de relatie

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

Stuurt de Model.relations\ _ name () -methode van de veel-op-veel-relatie en het omgekeerde van de externe sleutelrelatie.

Afzender - Afzenderklasse, instantie - Voeg instantie van gerelateerd model toe, kind - Model wordt toegevoegd, relatie\ _ naam - Naam van relatie om kind toe te voegen.

Na het verwijderen van de relatie

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

Stuurt de Model.relations\ _ name () -methode van de veel-op-veel-relatie en het omgekeerde van de externe sleutelrelatie.

Afzender - Afzenderklasse, instantie - Voeg instantie van gerelateerd model toe, kind - Model wordt toegevoegd, relatie\ _ naam - Naam van relatie om kind toe te voegen.

Na batch-update

post_bulk_update(sender: Type["Model"], instances: List["Model"], **kwargs), verzonden naar de Model.objects.bulk_update(List[objects])-methode.

Definieer uw eigen signalen

Houd er rekening mee dat u uw eigen signalen kunt maken, hoewel u deze handmatig in de code of subklasse ormar moet verzenden. Modelleer en activeer de signalen daar.

Het creëren van een nieuw signaal is eenvoudig. In het volgende voorbeeld wordt een nieuw signaal ingesteld met de naam uw\ _ custom\ _ signaal.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
Databanken importeren
Sqlalchemie invoeren

Ormar importeren


basis _ ormar _ config = ormar. OrmarConfig (
    Database = databanken. Database ("sqlite: / / db.sqlite"),
    Metadata = sqlalchemie. MetaData (),
)


Klasse Album (ormar. Model):
    ormar _ config = basis _ ormar _ config kopie ()

    Id: int = ormar. Geheel getal (primaire _ sleutel = waar)
    Naam: str = ormar. String (max _ length = 100)
    is _ best _ seller: bool = ormar. Booleaans (standaard = onwaar)
    play _ count: int = ormar. Geheel getal (standaard = 0)

Album. ormar _ config signalen. uw _ custom _ signaal = ormar. Signaal ()
ormar _ config geeft aan dat uw _ custom _ signaal verbinding maakt (uw _ ontvanger _ naam)

In feite is de onderliggende laag van een signaal een SignalEmitter-instantie die een woordenboek met bekende signalen bevat en u toegang geeft tot deze als eigenschappen. Wanneer u probeert toegang te krijgen tot een signaal dat niet bestaat, zal SignalEmitter een signaal voor u maken.

Het bovenstaande voorbeeld kan dus worden vereenvoudigd. Het signaal wordt voor u aangemaakt.

1
ormar _ config geeft aan dat uw _ custom _ signaal verbinding maakt (uw _ ontvanger _ naam)

Om dit signaal te activeren, moet je de verzendmethode van het signaal aanroepen.

1
Wacht op album. ormar _ config signals. uw _ custom _ signaal verzenden (afzender = album)

Houd er rekening mee dat de afzender de enige vereiste parameter is en dat dit de Ormar Model-klasse zou moeten zijn.

Extra parameters moeten worden doorgegeven als zoekwoordargumenten.

1
Wacht op album. ormar _ config-signalen. uw _ custom _ signaal verzenden (afzender = album, mijn _ param = waar)