Conas cuardaigh saincheaptha a scríobhLink to this heading

Cuireann Django <field-lookups>réimse leathan de: ref: cuardaigh ionsuite `ar fáil le haghaidh scagadh (mar shampla, ``cruth` agus ``icontains`). Míníonn an doiciméadú seo conas cuardaigh saincheaptha a scríobh agus conas obair na gcuardaigh atá ann cheana a athrú. Le haghaidh tagairtí API de chuardaigh, féach an:doc: /ref/models/lookups.

Sampla cuardaighLink to this heading

Tosaímid le cuardach beag saincheaptha. Scríobhfaimid cuardach saincheaptha ne a oibríonn os coinne ``cruinn `. Aistreoidh ``Author.Objects.Filter (name__ne='Jack') ``go dtí an SQL:

SQL
"author"."name" <> 'Jack'

Tá an SQL seo neamhspleách ar chúltaca, mar sin ní gá dúinn a bheith buartha faoi bhunachair sonraí éagsúla.

Tá dhá chéim ann chun an obair seo a dhéanamh. Ar dtús ní mór dúinn an cuardach a chur i bhfeidhm, ansin ní mór dúinn a insint do Django faoi:

Code
from django.db.models import Lookup


class NotEqual(Lookup):
    lookup_name = "ne"

    def as_sql(self, compiler, connection):
        lhs, lhs_params = self.process_lhs(compiler, connection)
        rhs, rhs_params = self.process_rhs(compiler, connection)
        params = lhs_params + rhs_params
        return "%s <> %s" % (lhs, rhs), params

Chun an cuardach NoteQual a chlárú beidh orainn glaoch ar register_lookup` ar an rang réimse a theastaíonn uainn go mbeadh an cuardach ar fáil dó. Sa chás seo, bíonn ciall ag an cuardach ar gach fo-aicme ``Field`, mar sin cláraímid é le ``Field` go díreach:

Code
from django.db.models import Field

Field.register_lookup(NotEqual)

Is féidir clárú cuardaigh a dhéanamh freisin ag baint úsáide as patrún maisitheora:

Code
from django.db.models import Field


@Field.register_lookup
class NotEqualLookup(Lookup): ...

Is féidir linn foo__ne a úsáid anois le haghaidh aon réimse foo. Beidh ort a chinntiú go dtarlaíonn an clárú seo sula ndéanann tú iarracht aon cheisteanna a chruthú ag baint úsáide as. D'fhéadfá an cur i bhfeidhm a chur i gcomhad models.py`, an cuardach a chlárú sa mhodh ``ready () ``de `AppConfig.

Ag breathnú níos dlúithe ar an gcur i bhfeidhm, is é lookup_name` an chéad tréith riachtanach. Ligeann sé seo don ORM tuiscint a fháil ar conas name__ne a léirmhíniú agus NoteQual a úsáid chun an SQL a ghiniúint. De réir choinbhinsiúin, is teaghráin bheaga iad na hainmneacha seo i gcónaí nach bhfuil ach litreacha ann, ach is é an t-aon cheanglas crua ná nach gcaithfidh an teaghrán __ a bheith ann.

Ansin ní mór dúinn an modh as_sql a shainiú. Tógann sé seo réad SQLCompiler, ar a dtugtar compiler, agus an nasc gníomhach bunachar sonraí. Ní dhéantar rudaí SQLCompiler` a dhoiciméadú, ach is é an t-aon rud a chaithfimid a bheith ar eolas fúthu ná go bhfuil modh compileáil () ``acu a thugann tuple ina bhfuil teaghrán SQL, agus na paraiméadair atá le hidirphóladh isteach sa sreang sin. I bhformhór na gcásanna, duit é a úsáid go díreach agus is féidir leat é a chur ar aghaidh chuig ``process_lhs () ``agus ``process_rhs ().

Oibríonn Lookup i gcoinne dhá luach, lhs` agus rhs, ag seasamh ar thaobh na láimhe clé agus ar dheis. <query-expression>Is tagairt réimse é an taobh na láimhe clé de ghnáth, ach is féidir é a bheith ina rud ar bith a chur i bhfeidhm an:ref: abairt fiosraithe API `. Is é an lámh dheis an luach a thugann an t-úsáideoir. Sa sampla ``Author.Objects.Filter (name__ne='Jack') `, is tagairt é an taobh clé don réimse ainm den tsamhail Author ``, agus ``Jack' is é an taobh na láimhe deise.

Glaoimid ar process_lhs agus process_rhs chun iad a thiontú ina luachanna a theastaíonn uainn le haghaidh SQL ag baint úsáide as an réad compiler a thuairiscítear roimhe seo. Tugann na modhanna seo tuples ina bhfuil roinnt SQL agus na paraiméadair atá le hidirphóladh isteach sa SQL sin, díreach mar is gá dúinn filleadh ónár modh as_sql`. Sa sampla thuas, filleann process_lhs ('"údar”. ainm"', []) ``agus ``process_rhs filleann`` ('"%s"', ['Jack']) ``. Sa sampla seo ní raibh aon pharaiméadair ann don taobh clé, ach bheadh sé seo ag brath ar an réad atá againn, mar sin ní mór dúinn iad a áireamh sna paraiméadair a fhilleann muid fós.

Faoi dheireadh, déanaimid na codanna a chomhcheangal i abairt SQL le <>`, agus soláthraímid na paraiméadair go léir don cheist. Ansin cuirimid tuple ar ais ina bhfuil an teaghrán SQL a ghintear agus na paraiméadair.

Sampla claochladáinLink to this heading

Tá an cuardach saincheaptha thuas iontach, ach i gcásanna áirithe b'fhéidir gur mhaith leat a bheith in ann cuardaigh a shlánú le chéile. Mar shampla, is dóigh linn go bhfuilimid ag tógáil feidhmchlár áit ar mhaith linn úsáid a bhaint as an oibreoir abs () ``. samhail ``Turgnamh againn a thaifeadann luach tosaigh, luach deiridh, agus an t-athrú (tús - deireadh). Ba mhaith linn gach turgnamh a fháil nuair a bhí an t-athrú cothrom le méid áirithe (Experiment.Objects.filter (change__abs = 27) `), nó nuair nár sháraigh sé méid áirithe (Experiment.Objects.Filter (change__abs__lt=27)).

Tosóimid trí chlaochladán Absolutevalue a scríobh. Úsáidfidh sé seo an fheidhm SQL ``ABS () ``chun an luach a athrú roimh chomparáid:

Code
from django.db.models import Transform


class AbsoluteValue(Transform):
    lookup_name = "abs"
    function = "ABS"

Ansin, déanaimis é a chlárú le haghaidh IntegerField:

Code
from django.db.models import IntegerField

IntegerField.register_lookup(AbsoluteValue)

Is féidir linn anois na ceisteanna a bhí againn roimhe seo a rith. Ghinfidh ``Experiment.Objects.Filter (change__abs = 27) ``an SQL seo a leanas:

SQL
SELECT ... WHERE ABS("experiments"."change") = 27

Trí Transform a úsáid in ionad Lookup ciallaíonn sé go bhfuilimid in ann cuardaigh breise a shlánú ina dhiaidh sin. Mar sin, ginfidh ``Experiment.Objects.filter (change__abs__lt = 27) ``an SQL seo a leanas:

SQL
SELECT ... WHERE ABS("experiments"."change") < 27

Tabhair faoi deara, i gcás nach bhfuil aon chuardach eile sonraithe ann, léirmhíníonn Django change__abs = 27 mar change__abs__exact=27.

Ligeann sé seo freisin an toradh a úsáid i gclásail ORDER BY agus DISTINCT ON`. Mar shampla ``Experiment.Objects.Order_by ('change__abs') ``gineann:

SQL
SELECT ... ORDER BY ABS("experiments"."change") ASC

Agus ar bhunachair sonraí a thacaíonn le réimsí ar leith (mar shampla PostgreSQL), gineann ``Experiment.Objects.Distinct ('change__abs') ``:

SQL
SELECT ... DISTINCT ON ABS("experiments"."change")

Agus tú ag lorg cé na cuardaigh atá incheadaithe tar éis an Transform` `a chur i bhfeidhm, úsáideann Django an tréith ``output_field`. raibh dúinn é seo a shonrú anseo mar níor athraigh sé, ach ag glacadh go raibh “AbsoluteValue” á chur i bhfeidhm ar réimse éigin a léiríonn cineál níos casta (mar shampla pointe i gcoibhneas le bunús, uimhir chasta) ansin b'fhéidir gur theastaigh uainn a shonrú go dtugann an claochlú cineál `Floatfield` le haghaidh tuilleadh cuardaigh. Is féidir é seo a dhéanamh trí thréith ``output_field a chur leis an gclaochlú:

Code
from django.db.models import FloatField, Transform


class AbsoluteValue(Transform):
    lookup_name = "abs"
    function = "ABS"

    @property
    def output_field(self):
        return FloatField()

Cinntíonn sé seo go n-iompraíonn cuardaigh breise mar abs__lte mar a dhéanfaidís do ``Floatfield ``.

Cuardach éifeachtach abs__lt a scríobhLink to this heading

Agus an cuardach 'abs' scríofa thuas á úsáid agat, ní úsáidfidh an SQL a tháirgtear innéacsanna go héifeachtúil i gcásanna áirithe. Go háirithe, nuair a úsáidimid change__abs__lt=27, tá sé seo comhionann le change__gt=-27 AGUS change__lt=27. (Maidir leis an gcás lte d'fhéadfaimis an SQL BETWEEN a úsáid).

Mar sin ba mhaith linn ``Experiment.Objects.filter (change__abs__lt = 27) ``an SQL seo a leanas a ghiniúint:

SQL
SELECT .. WHERE "experiments"."change" < 27 AND "experiments"."change" > -27

Is é seo a leanas an cur chun feidhme:

Code
from django.db.models import Lookup


class AbsoluteValueLessThan(Lookup):
    lookup_name = "lt"

    def as_sql(self, compiler, connection):
        lhs, lhs_params = compiler.compile(self.lhs.lhs)
        rhs, rhs_params = self.process_rhs(compiler, connection)
        params = lhs_params + rhs_params + lhs_params + rhs_params
        return "%s < %s AND %s > -%s" % (lhs, rhs, lhs, rhs), params


AbsoluteValue.register_lookup(AbsoluteValueLessThan)

Tá cúpla rud suntasach ar siúl. Ar dtús, níl Absolutevaluelessthan ag glaoch ar process_lhs () ``. Ina áit sin scipeann claochlú na `lhs arna dhéanamh ag AbsoluteValue agus úsáideann sé an lhs` bunaidh. Is é sin, ba mhaith linn “turgnaimh” a fháil.” athraigh “ ``ABS (“turgnaimh”.” athrú”) ``. tagairt dhíreach do `self.lhs.lhs sábháilte mar ní féidir rochtain a fháil ar AbsoluteValuelessthan ach ón gcuardach AbsoluteValue, is é sin an lhs` is sampla de AbsoluteValue` i gcónaí.

Tabhair faoi deara freisin toisc go n-úsáidtear an dá thaobh arís agus arís agus arís eile sa cheist go gcaithfidh lhs_params` agus rhs_params` a bheith sna paramaí arís agus arís eile.

Déanann an cheist deiridh an t-inbhrú (27 go -27`) go díreach sa bhunachar sonraí. Is é an chúis atá leis seo a dhéanamh ná más rud éigin eile é an self.rhs seachas luach slámhshláir simplí (mar shampla tagairt ``F () `) ní féidir linn na claochlú a dhéanamh i Python.

Sampla claochladáin déthaobhLink to this heading

Is é an sampla ``AbsoluteValue` a phléamar roimhe seo ná claochlú a bhaineann leis an taobh clé den chuardach. D'fhéadfadh go mbeadh roinnt cásanna ann inar mian leat an claochlú a chur i bhfeidhm ar an taobh clé agus ar an taobh deise araon. Mar shampla, más mian leat tacar fiosrúcháin a scagadh bunaithe ar chomhionannas an taobh clé agus na láimhe deise go neamhíogair do roinnt feidhm SQL.

Déanaimis scrúdú ar chlaochlú cás-neamh-íogair Níl an claochlú seo an-úsáideach go praiticiúil toisc go dtagann dornán cuardaigh cás-neamh-íogair ionsuite le Django cheana féin, ach beidh sé ina léiriú deas ar chlaochlú déthaobhacha ar bhealach agnasach bunachar sonraí.

Sainmhínímid claochladán Uppercase a úsáideann an fheidhm SQL UPPER () ``chun na luachanna a athrú roimh chomparáid. Sainmhínímid: attr: `déthaobhach = Fíor <django.db.models.Transform.bilateral>`chun a léiriú gur chóir go mbeadh feidhm ag an gclaochlú seo le `lhs agus rhs` araon:

Code
from django.db.models import Transform


class UpperCase(Transform):
    lookup_name = "upper"
    function = "UPPER"
    bilateral = True

Ansin, déanaimis é a chlárú:

Code
from django.db.models import CharField, TextField

CharField.register_lookup(UpperCase)
TextField.register_lookup(UpperCase)

Anois, ginfidh an tacar ceisteanna `Author.Objects.Filter (name__upper="doe”) ``ceist neamh-íogair cás mar seo:

SQL
SELECT ... WHERE UPPER("author"."name") = UPPER('doe')

Forfheidhmithe malartacha a scríobh le haghaidh cuardaigh atá annLink to this heading

Uaireanta éilíonn díoltóirí bunachar sonraí éagsúla SQL éagsúla don oibríocht chéanna. Mar shampla seo athscríobhfaimid cur i bhfeidhm saincheaptha do MySQL don oibreoir NotEqual. In ionad <> beimid ag úsáid != oibreoir. (Tabhair faoi deara i ndáiríre go dtacaíonn beagnach gach bunachar sonraí leis an dá cheann, lena n-áirítear na bunachair shonraí oifigiúla go léir a fhaigheann tacaíocht ó Django).

Is féidir linn an t-iompar ar chúltaca ar leith a athrú trí fho-aicme de NoteQual` a chruthú le modh as_mysql`:

Code
class MySQLNotEqual(NotEqual):
    def as_mysql(self, compiler, connection, **extra_context):
        lhs, lhs_params = self.process_lhs(compiler, connection)
        rhs, rhs_params = self.process_rhs(compiler, connection)
        params = lhs_params + rhs_params
        return "%s != %s" % (lhs, rhs), params


Field.register_lookup(MySQLNotEqual)

Ansin is féidir linn é a chlárú le Field`. Tógann in áit an aicme bunaidh ``NoteQual mar tá an lookup_name` céanna aige.

Agus ceist á thiomsú, féachann Django ar dtús modhanna as_%s% connection.vendor, agus ansin titeann sé ar ais chuig as_sql. Is iad na hainmneacha díoltóra do na cúltaca ionsuite ná sqlite`, postgresql`, oracle agus mysql.

Conas a chinneann Django na cuardaigh agus na hathshruithe a úsáidtearLink to this heading

I gcásanna áirithe b'fhéidir gur mhaith leat a athrú go dinimiciúil cén TransformLookup ar ais bunaithe ar an ainm a chuirtear isteach, seachas é a shocrú. Mar shampla, d'fhéadfá réimse a bheith agat a stóráilíonn comhordanáidí nó gné treallach, agus ba mhaith leat comhréir mar .filter (coords__x7=4) `a cheadú chun na rudaí a thabhairt ar ais ina bhfuil luach 4 ag an 7ú comhordú. D'fhonn é seo a dhéanamh, dhéanfá ``get_lookup` a shárú le rud éigin mar:

Code
class CoordinatesField(Field):
    def get_lookup(self, lookup_name):
        if lookup_name.startswith("x"):
            try:
                dimension = int(lookup_name.removeprefix("x"))
            except ValueError:
                pass
            else:
                return get_coordinate_lookup(dimension)
        return super().get_lookup(lookup_name)

Ansin shainmhíníodh get_coordinate_lookup go cuí chun fo-aicme Lookup a thabhairt ar ais a dhéileálann luach ábhartha tois.

Tá modh ainmnithe mar an gcéanna ar a dtugtar get_transformer () ``. Ba chóir go gcuirfeadh ``get_lookup () ``fo-aicme ``Lookup a thabhairt ar ais i gcónaí, agus get_transformer () fo-aicme Transform. Tá sé tábhachtach a mheabhrú gur féidir rudaí Transform' a scagadh tuilleadh orthu, agus ní féidir rudaí ``Lookup`.

Agus tú ag scagadh, mura bhfuil ach ainm cuardaigh amháin fágtha le réiteach, cuirfimid ag lorg Lookup. Má tá ainmneacha iolracha ann, cuardóidh sé Transform` `. Sa chás nach bhfuil ach ainm amháin ann agus nach bhfaightear ``Lookup, cuirimid ag lorg Transform agus ansin an cuardach `cruth ar an Transform` sin. Críochnaíonn gach seicheamh glaonna le Lookup i gcónaí. Chun soiléiriú:

  • Glaofar .filter (myfield__mylookup) ```myfield.get_lookup ('mylookup').

  • Tabharfaidh .filter (myfield__mytransform__mylookup) ``glaoch ar ``myfield.get_transformer ('mytransformer')`, agus ansin ``mytransform.get_lookup ('mylookup') ``.

  • Glaofar .filter (myfield__mytransformer) ``ar dtús ``myfield.get_lookup ('mytransformer'), a theipeann air, mar sin tithfidh sé ar ais ar myfield.get_transformer ('mytransformer') ``agus ansin ``mytransform.get_lookup ('éacht').