Kuidas Django administraatorisse tekstifiltrit lisada

Kuidas asendada Django otsing konkreetsete väljade tekstifiltritega

Parema lugemiskogemuse saamiseks lugege seda artiklit minu veebisaidil.

Uue Django administraatori lehe loomisel võib arendaja ja tugiteenuse pakkuja ühine vestlus kõlada järgmiselt:

Arendaja: Hei, ma lisan tehingute jaoks uue administraatori lehe. Kas oskate öelda, kuidas soovite tehinguid otsida?
Tugi: Muidugi, tavaliselt otsin ma lihtsalt kasutajanime järgi.
Arendaja: Lahe.
otsinguväljad = (
    kasutaja__ kasutajanimi
)
Veel midagi?
Tugi: mõnikord tahan otsida ka kasutaja e-posti aadressi järgi.
Arendaja: OK.
otsinguväljad = (
   kasutaja__ kasutajanimi
   kasutaja__post,
)
Tugi: Ja muidugi ees- ja perekonnanimi.
Arendaja: Jah, olgu.
otsinguväljad = (
    kasutaja__ kasutajanimi
    kasutaja__post,
    kasutaja__ esimene_nimi,
    kasutaja__last_nimi,
)
Kas see on kõik?
Tugi: Noh, mõnikord pean ma otsima maksekviitungi numbri järgi.
Arendaja: OK.
otsinguväljad = (
    kasutaja__ kasutajanimi
    kasutaja__post,
    kasutaja__ esimene_nimi,
    kasutaja__last_nimi,
    makse__voucher_number,
)
Veel midagi?
Tugi: mõned kliendid saadavad oma arved ja esitavad küsimusi, nii et otsin ka arve numbri järgi.
Arendaja: FINE!
otsinguväljad = (
    kasutaja__ kasutajanimi
    kasutaja__post,
    kasutaja__ esimene_nimi,
    kasutaja__last_nimi,
    makse__voucher_number,
    arve__invo_number,
)
OK, kas olete kindel, et see on nii?
Tugi: Noh, arendajad edastavad mõnikord meile pileteid ja nad kasutavad neid pikki juhuslikke stringe. Kunagi pole ma kindel, mis need on, otsin ja loodan parimat.
Arendaja: neid nimetatakse UUID-deks.
otsinguväljad = (
    kasutaja__ kasutajanimi
    kasutaja__post,
    kasutaja__ esimene_nimi,
    kasutaja__last_nimi,
    makse__voucher_number,
    arve__invo_number,
    uid,
    kasutaja__uid,
    makse__uid,
    arve__uid,
)
Nii see siis on?
Tugi: Jah, praegu ...

Probleem otsinguväljadega

Django Admini otsinguväljad on suurepärased - visake hunnik põlde otsinguväljadele ja Django saab ülejäänutega hakkama.

Probleem otsinguväljaga algab siis, kui neid on liiga palju.

Kui administraatori kasutaja soovib otsida UID või e-posti teel, pole Djangol aimugi, mida see kasutaja kavandas, nii et ta peab otsima kõigil otsinguväljadel loetletud väljadel. Nendel „sobib mis tahes” päringutel on tohutud WHERE klauslid ja palju liitumisi ning need võivad kiiresti muutuda väga aeglaseks.

Tavalise ListFilteri kasutamine pole valik - ListFilter kuvab väljade konkreetsete väärtuste hulgast valikute loendi. Mõned väljad, mille me ülal loetlesime, on ainulaadsed ja teistel on palju eristatavaid väärtusi - valikute näitamine pole valik.

Django ja kasutaja vahelise lõhe ületamine

Hakkasime mõtlema, kuidas saaksime luua mitu otsinguvälja - ühe iga välja või põllurühma jaoks. Arvasime, et kui kasutaja soovib otsida e-posti või UID-i järgi, pole põhjust otsida muult väljalt.

Pärast mõningast mõtlemist jõudsime lahenduseni - kohandatud SimpleListFilter:

  • ListFilter võimaldab kohandatud filtreerimisloogikat.
  • ListFilteril võib olla kohandatud mall.
  • Django toetab juba mitut ListFiltrit.

Tahtsime, et see näeks välja selline:

Tekstiloendi filter

InputFilteri juurutamine

Mida me teha tahame, on valikute asemel loendifilter, millel on tekstisisestus.

Enne kui me rakendusse sukeldume, alustame otsast. Nii tahame kasutada oma InputFiltrit ModelAdminis:

klassi UIDFilter (InputFilter):
    parameetri_nimi = 'uid'
    pealkiri = _ ('UID')
 
    def queryset (ise, päring, queryset):
        kui self.value () ei ole Puudub:
            uid = self.value ()
            tagasta queryset.filter (
                Q (uid = uid) |
                Q (makse__uid = uid) |
                Q (kasutaja__uid = uid)
            )

Ja kasutage seda nagu mõnda muud ModelAdmini loendifiltrit:

klass TransactionAdmin (admin.ModelAdmin):
    ...
    list_filter = (
        UUIDFilter,
    )
    ...
  • Koostame uuidi välja jaoks kohandatud filtri - UIDFilter.
  • Valisime URL-is parameetri_nimi kasutatavaks. Uidi filtreeritud URL näeb välja selline / admin / app / tehing? Uid =
  • Kui kasutaja sisestas uid, otsime tehingu uid, makse uid või kasutaja uid.

Siiani on see täpselt nagu tavaline kohandatud loendifilter.

Nüüd, kui meil on parem idee sellest, mida me tahame, rakendame oma InputFilteri:

klassi InputFilter (admin.SimpleListFilter):
    mall = 'admin / input_filter.html'
    def otsingud (ise, päring, mudel_admin):
        # Mannekeen, vajalik filtri näitamiseks.
        tagasi ((),)

Me pärime saidilt SimpleListFilter ja mall üle kirjutatakse. Meil pole ühtegi otsingut ja soovime, et mall pakuks valikute asemel tekstisisestust:

// mallid / admin / input_filter.html
{% load i18n%}

{% blocktrans with filter_title = title%} Autor: {{filter_title}} {% endblocktrans%}

      
  •     
                    

Natiivseks muutmiseks kasutame Django olemasoleva loendifiltriga sarnast märgistust. Malli abil saab lihtvormi koos GET-toiminguga ja parameetri tekstiväljaga. Selle vormi esitamisel värskendatakse URL-i parameetri nime ja esitatud väärtusega.

Mängige teiste filtritega kenasti

Siiani töötab meie filter, kuid ainult siis, kui muid filtreid pole. Kui tahame teiste filtritega kenasti mängida, peame neid oma vormis arvestama. Selleks peame hankima nende väärtused.

Loendifiltril on veel üks funktsioon, mida nimetatakse valikuteks. Funktsioon aktsepteerib muutujate nimekirja objekti, mis sisaldab kogu teavet praeguse vaate kohta, ja tagastab valikute loendi.

Meil pole valikuid, nii et me kasutame seda funktsiooni kõigi filtrite jaoks, mida rakendati päringule ja nende malli kuvamiseks:

klassi InputFilter (admin.SimpleListFilter):
    mall = 'admin / input_filter.html'
    def otsingud (ise, päring, mudel_admin):
        # Mannekeen, vajalik filtri näitamiseks.
        tagasi ((),)
    def valikud (ise, Changelist):
        # Haarake ainult valik "kõik".
        all_choice = järgmine (super (). valikud (muutuste loend))
        all_choice ['query_parts'] = (
            (k, v)
            k, v jaoks changelist.get_filters_params (). üksused ()
            kui k! = iseparameetri_nimi
        )
        saagis all_choice

Filtrite lisamiseks lisame iga parameetri jaoks peidetud sisestusvälja:

// mallid / admin / input_filter.html
{% load i18n%}

{% blocktrans with filter_title = title%} Autor: {{filter_title}} {% endblocktrans%}

      
  •     {% with options.0 kui all_choice%}     
        {% k, v jaoks all_choice.query_parts%}
        
        {% endfor%}
        
    
    {% endwith%}
  

Nüüd on meil tekstisisestusfilter, mis mängib teiste filtritega kenasti. Ainuke asi, mis selleks jäi, on „selge” valiku lisamine.

Filtri puhastamiseks vajame URL-i, mis sisaldab kõiki filtreid, välja arvatud meie oma:

// mallid / admin / input_filter.html
...

    
{% kui mitte kõik_choice.selected%}
    ⨉ {% trans 'Eemalda'%}  
{% endif%}
...

Voilà!

Seda saame:

InputFilter koos teiste filtrite ja eemaldusnupuga

Täielik kood:

Boonus

Otsige mitu sõna, mis sarnaneb Django otsinguga

Võib-olla olete märganud, et mitme sõna otsimisel leiab Django tulemusi, mis sisaldavad vähemalt ühte sõna ja mitte kõiki.

Näiteks kui otsite kasutajat „John Duo”, leiab Django nii „John Foo” kui ka „Bar Due”. See on väga mugav, kui otsite selliseid asju nagu täisnimi, tootenimed ja nii edasi.

Saame sarnase tingimuse rakendada oma InputFilteri abil:

saidilt django.db.models import Q
klassi UserFilter (InputFilter):
    parameetri_nimi = 'kasutaja'
    pealkiri = _ ('kasutaja')
    def queryset (ise, päring, queryset):
        mõiste = enesehinnang ()
        kui terminit pole:
            tagasi
        any_name = Q ()
        bit for term.split ():
            suvaline_nimi & = (
                Q (kasutaja_esimesed_nimed__sisaldab = bitti) |
                Q (user__last_name__icontains = bit)
            )
        tagasta queryset.filter (suvaline_nimi)

See on see!

Vaadake minu teisi Django administraatori postitusi: