Perbandingan berbagai filter Django pada contoh demo basis data PostgreSQL

Alih-alih kata pengantar



Semuanya dimulai dengan fakta bahwa saya ditawari untuk berpartisipasi dalam proyek dalam kerangka subjek "Dasar-dasar Pemrograman Web", alih-alih melakukan pekerjaan laboratorium dan kursus, karena saya menyatakan bahwa saya ingin melakukan sesuatu yang jauh dari kursus umum (sehingga sudah ada cukup pengetahuan pada sekelompok DRF + Vue, saya ingin sesuatu yang baru). Jadi di salah satu PR saya di github, saya memutuskan untuk menggunakan pencarian teks lengkap (tugas ini mengisyaratkan) untuk memfilter konten, yang membuat saya beralih ke dokumentasi Djangomencari cara terbaik untuk mengimplementasikan bisnis ini. Saya pikir Anda tahu sebagian besar metode yang disarankan di sana (berisi, icontains, trigram_similar). Semuanya cocok untuk beberapa tugas tertentu, tetapi tidak terlalu bagus, yaitu pencarian teks lengkap. Menggulir ke bawah sedikit, saya menemukan bagian yang berbicara tentang interaksi Django dan Pgsql untuk mengimplementasikan pencarian berbasis dokumen, yang menarik saya, karena postgre memiliki alat bawaan untuk mengimplementasikan pencarian [teks lengkap] ini. Dan saya memutuskan bahwa kemungkinan besar, Django hanya menyediakan API untuk pencarian ini, atas dasar mana solusi seperti itu harus bekerja dan lebih akurat dan lebih cepat daripada opsi lain. Guru itu tidak terlalu mempercayaiku, kami berdebat dengannya, dan ia menawarkan untuk melakukan penelitian tentang topik ini. Dan inilah saya.



Awal pekerjaan



Masalah pertama yang muncul sebelum saya adalah mencari mockup basis data, agar tidak muncul sendiri hal-hal yang tidak dapat dipahami, dan saya pergi ke google dan membaca postgres wiki . Akibatnya, saya menetap di pangkalan demo mereka tentang penerbangan di seluruh Rusia.



, . , . , , , search django.contrib.postgres.search. — contains ( ) icontains ( , , : "Helen" : <Author: Helen Mirren>, <Author: Helena Bonham Carter>, <Author: Hélène Joy>), django. postgresql. tickets small 366733 . passenger_name, , , . .



django



β€” django . django , , :



$ python manage.py inspectdb > models.py


, , settings.py. . , . , ( ), , 300+ , 10, , . , , curl. .





, , , curl, , . , ( ).



django



, β€” , queryset - . .



:



QuerySet dapat diubah, dan menjalankan kueri basis datanya saat pertama kali Anda mengulanginya. Misalnya, ini akan mencetak judul semua entri dalam database:



for e in Entry.objects.all():
       print(e.headline)```




Tampilan akhir untuk berisi
class TicketListView(g.ListAPIView):
    serializer_class = TicketSerializer

    def get_queryset(self):
        queryset = ''
        params = self.request.query_params

        name = params.get('name', None)

        if name:
            start_time = d.datetime.now()

            queryset = queryset.filter(passenger_name__contains=name)
            print('len of result is {} rows'.format(len(queryset)))

            end_time = d.datetime.now()

            time_diff = (end_time - start_time)
            execution_time = time_diff.total_seconds() * 1000

            print("Filter execution time {} ms".format(execution_time))

        return queryset


Mengandung



Mari kita mulai dengan berisi, pada dasarnya berfungsi seperti SEPERTI WHERE.



Permintaan dalam Django ORM / Permintaan dalam sql untuk berisi
queryset = queryset.filter(passenger_name__contains=name)


SELECT "tickets"."ticket_no", "tickets"."book_ref", "tickets"."passenger_id", "tickets"."passenger_name", "tickets"."contact_data" FROM "tickets" WHERE "tickets"."passenger_name"::text LIKE %IVAN%


Untuk mendapatkan hasil dari curl, saya menjalankan permintaan sebagai berikut (dihitung dalam detik):



$ curl -w "%{time_total}\n" -o /dev/null -s http://127.0.0.1:8000/api/tickets/?name=IVAN
1,242888


Saya meletakkan semuanya di atas meja di lembar yang sesuai.



β€” , 140 1400 . , . ORM 73 600 , 55 100 .



Icontains



Icontains - ( , ). , contains β€” icontains. .



Django ORM/ sql icontains
queryset = queryset.filter(passenger_name__icontains=name)


SELECT "tickets"."ticket_no", "tickets"."book_ref", "tickets"."passenger_id", "tickets"."passenger_name", "tickets"."contact_data" FROM "tickets" WHERE UPPER("tickets"."passenger_name"::text) LIKE UPPER(%IVAN%)


, , ( 300 ), 200 1500 . ORM β€” 200 700 .



Full text search ( django.contrib.postgres)



, full text search . 1300 , 1000 1700 . , ORM β€” 1000 1450 .



class TicketListView(g.ListAPIView):
    serializer_class = TicketSerializer

    def get_queryset(self):
        # queryset = Tickets.objects.all()
        queryset = ''

        params = self.request.query_params

        name = params.get('name', None)

        if name:

            start_time = d.datetime.now()

            queryset = Tickets.objects.filter(passenger_name__search=name)

            end_time = d.datetime.now()

            time_diff = (end_time - start_time)
            execution_time = time_diff.total_seconds() * 1000

            print("Filter execution time {} ms".format(execution_time))

            f = open('results.txt', 'a')

            f.write('{}'.format(execution_time))
            f.write('\n')

            f.close()

        return queryset


Full text search ( rest_framework.filters, β€” SearchFilter)



FTS, FTS , , contains icontains. 200 1710 .



FTS , . , 800 1120 .



...
from rest_framework import filters as f

class TicketListView(g.ListAPIView):
    queryset = Tickets.objects.all()
    serializer_class = TicketSerializer
    filter_backends = [f.SearchFilter]
    search_fields = ['@passenger_name']


django-filter



contains icontains, . , django-filter - Django ORM.



?



β€” (, , ) , . β€” . , ( , , contains/icontains) , , , , .



Secara keseluruhan, pemahaman saya tentang beberapa pekerjaan batin Django telah pulih berkat penelitian ini. Dan akhirnya muncul realisasi perbedaan antara pencarian substring dan pencarian teks lengkap. Perbedaan implementasi mereka melalui Django ORM.




All Articles