Django'da dinamik alan aramalarıyla bir QuerySet nasıl filtrelenir?


161

Bir sınıf verildi:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=20)

Dinamik bağımsız değişkenlere dayanan filtreler içeren bir QuerySet'e sahip olmak mümkün mü ve eğer öyleyse? Örneğin:

 # Instead of:
 Person.objects.filter(name__startswith='B')
 # ... and:
 Person.objects.filter(name__endswith='B')

 # ... is there some way, given:
 filter_by = '{0}__{1}'.format('name', 'startswith')
 filter_value = 'B'

 # ... that you can run the equivalent of this?
 Person.objects.filter(filter_by=filter_value)
 # ... which will throw an exception, since `filter_by` is not
 # an attribute of `Person`.

Yanıtlar:


311

Bu sorunu çözmek için Python'un argüman genişletmesi kullanılabilir:

kwargs = {
    '{0}__{1}'.format('name', 'startswith'): 'A',
    '{0}__{1}'.format('name', 'endswith'): 'Z'
}

Person.objects.filter(**kwargs)

Bu çok yaygın ve kullanışlı bir Python deyimidir.


6
Sadece hızlı bir gotcha head-up: kwargs dizeleri unicode değil str türü olduğundan emin olun, aksi takdirde filter () homurdayacaktır.
Steve Jalim

1
@santiagobasulto Ayrıca ambalajlama / ambalajdan çıkarma parametresi ve bunların varyasyonları ile de ilgilidir.
Daniel Naab

7
güzel, güzel ve güzel !
Oscar Mederos

5
@DanielNaab ama bu sadece VEYA filtreleme, VEYA koşulu için herhangi bir alternatif üzerinde çalışan kwargs üzerinde çalışacaktır.
Prateek099

3
@prateek her zaman Q nesnelerini kullanabilirsiniz: stackoverflow.com/questions/13076822/…
deecodameeko

6

Basitleştirilmiş bir örnek:

Bir Django anket uygulamasında, kayıtlı kullanıcıları gösteren bir HTML seçim listesi istedim. Ancak 5000 kayıtlı kullanıcımız olduğundan, bu listeyi sorgu ölçütlerine göre filtrelemenin bir yoluna ihtiyacım vardı (sadece belirli bir çalıştayı tamamlayan kişiler gibi). Anket öğesinin yeniden kullanılabilir olması için, anket sorusunu oluşturan kişinin bu ölçütleri bu soruya ekleyebilmesi için gerekliydi (sorguyu uygulamaya kodlamak istemiyorum).

Geldiğim çözüm% 100 kullanıcı dostu değil (sorguyu oluşturmak için bir teknik kişinin yardımını gerektirir) ama sorunu çözüyor. Soruyu oluştururken, editör özel bir alana bir sözlük girebilir, örn:

{'is_staff':True,'last_name__startswith':'A',}

Bu dize veritabanında saklanır. Görünüm kodunda, olarak geri gelir self.question.custom_query. Bunun değeri, sözlüğe benzeyen bir dizedir . Onu eval () ile gerçek bir sözlüğe dönüştürüyoruz ve sonra ** kwargs ile queryset'e dolduruyoruz:

kwargs = eval(self.question.custom_query)
user_list = User.objects.filter(**kwargs).order_by("last_name")   

Kullanıcı, GUI tarafında temelde bir sorgu oluşturmak, ancak gerçek metni görmeden, ancak bir arabirim kullanarak kullanıcıya izin vermek için davranışı uygulayan özel bir ModelField / FormField / WidgetField oluşturmak için ne olacağını merak ediyorum böyle yap. Düzgün bir proje gibi geliyor ...
T. Stone

1
T. Stone - Sorgulamaya ihtiyaç duyan modeller basit, ancak mümkün olan tüm seçenekleri ortaya koyan kapsamlı bir şekilde, özellikle modeller, kompleksi.
shacker

5
eval()Kullanıcılarınıza tamamen güveniyor olsanız bile, kullanıcı içe aktarma işleminde arama yapmak kötü bir fikirdir. JSON alanı burada daha iyi bir fikir olacaktır.
John Carter

5

Django.db.models.Q tam olarak Django tarzında istediğiniz şeydir.


7
Siz (veya birileri) Q nesnelerini dinamik alan adlarını kullanmada nasıl kullanacağınıza ilişkin bir örnek verebilir misiniz?
jackdbernier

3
Bu, Daniel Naab'ın cevabı ile aynıdır Tek fark, argümanları Q nesne yapıcısına iletmenizdir. Q(**filters), Q nesnelerini dinamik olarak oluşturmak istiyorsanız, bunları bir listeye ekleyebilir .filter(*q_objects)ve Q nesnelerini birleştirmek için bitsel işleçlerini kullanabilir veya kullanabilirsiniz.
Will S

5
Bu cevap gerçekten OP'nin problemini çözmek için Q kullanma örneğini içermelidir.
pdoherty926

-2

Gerçekten karmaşık bir arama formu genellikle daha basit bir modelin çıkış yolunu araştırmaya çalıştığını gösterir.

Sütun adı ve işleminin değerlerini tam olarak nasıl almayı umuyorsunuz? Nereye değerlerini alabilirim 'name'bir 'startswith'?

 filter_by = '%s__%s' % ('name', 'startswith')
  1. Bir "arama" formu mu? Sen ne yapacaksın? - isim listesinden isim seçilsin mi? İşlem listesinden işlem seçilsin mi? Açık uçlu olsa da, çoğu insan bunu kafa karıştırıcı ve kullanımı zor buluyor.

    Bu tür filtrelerde kaç sütun var? 6? 12? 18?

    • Birkaç? Karmaşık bir seçim listesi mantıklı değil. Birkaç alan ve birkaç if ifadesi anlamlıdır.
    • Büyük bir sayı? Modeliniz doğru gelmiyor. "Alan" aslında bir sütun değil, başka bir tablodaki bir satırın anahtarıdır.
  2. Özel filtre düğmeleri. Bekle ... Django yöneticisinin işleyişi böyle. Belirli filtreler düğmelere dönüştürülür. Yukarıdaki analiz de geçerlidir. Birkaç filtre mantıklı. Çok sayıda filtre genellikle bir tür ilk normal form ihlali anlamına gelir.

Birçok benzer alan genellikle daha fazla satır ve daha az alan olması gerektiği anlamına gelir.


9
Saygılarımızla, tasarım hakkında hiçbir şey bilmeden önerilerde bulunmak küstahtır. "Basitçe uygulamak" için bu uygulama gereksinimleri karşılamak için astronomik (> 200 uygulamalar ^ 21 foos) fonksiyonları başlayacaktır. Örneğe amaç ve niyet okuyorsunuz; yapmamalısın. :)
Brian M. Hunt

2
Sadece (a) daha genel ve (b) hayal ettikleri şekilde çalışsaydı sorunlarının çözülmesinin önemsiz olacağını düşünen birçok insanla tanıştım. Bu şekilde sonsuz hayal kırıklığı yatar çünkü işler hayal ettikleri gibi değildir. Ben çok fazla başarısızlık gördüm "çerçeve sabitleme".
S.Lott

2
Daniel'in tepkisine göre işler beklendiği ve arzu edildiği gibi çalışıyor. Benim sorum tasarımla değil sözdizimi ile ilgiliydi. Tasarımı yazmak için zamanım olsaydı, bunu yapardım. Eminim girdileriniz yardımcı olacaktır, ancak bu pratik bir seçenek değildir.
Brian M. Hunt

8
S.Lott, cevabınız bu soruyu uzaktan bile yanıtlamıyor. Bir cevap bilmiyorsanız, lütfen soruyu yalnız bırakın. Tasarım hakkında kesinlikle sıfır bilgi sahibi olduğunuzda, istenmeyen tasarım tavsiyelerine cevap vermeyin!
slypete

2
@slypete: Tasarımda yapılan bir değişiklik sorunu çözerse, sorun çözülür. Kötü bir tasarıma dayanan yol boyunca devam etmek gerekenden daha pahalı ve karmaşıktır. Kök neden problemlerini çözmek, kötü tasarım kararlarından kaynaklanan diğer problemleri çözmekten daha iyidir. Kök neden analizini sevmediğin için üzgünüm. Ama bir şey gerçekten zor olduğunda, bu genellikle başlamak için yanlış şeyi denediğiniz anlamına gelir.
S.Lott
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.