2010-02-04 6 views
11

Django'da özel field lookups nasıl oluşturulur? benzeri __contains, __iexact, __in ve: Sorgu kümelerini filtre uygulanırkenDjango'da özel Alan Aramaları oluşturma

, django bir kullanabileceğiniz aramalarının kümesi sağlar. Ben alt sınıfı gerekir mi

twentysomethings = Person.objects.filter(age__within5=25) 

ve 20 ila 30 arası bir yaş tüm Person nesneleri geri almak: Ben örneğin, birinin söyleyebiliriz, benim yöneticisi için yeni bir arama sağlamak üzere mümkün istiyorum Bunu yapmak için QuerySet veya Manager sınıfı? Nasıl uygulanacak?

+3

Bu cevaplar onun örneği için yararlıdır (bu sadece kendi noktası yapmak için attığı bir şey olabilir ya da olmayabilir) .. ama birisi sorulan soruya cevap verse çok sevinirim. – royal

+1

@royal Sanırım cevabım bunu kapsamaktadır - Ben bunun üzerinde çalıştığım bir kütüphanede geldim. –

cevap

1

Django 1.7'den itibaren, onu uygulamak için basit bir yol var. Sizin örnek aslında the documentation den birine çok benzer:

from django.db.models import Lookup 

class AbsoluteValueLessThan(Lookup): 
    lookup_name = 'lt' 

    def as_sql(self, qn, connection): 
     lhs, lhs_params = qn.compile(self.lhs.lhs) 
     rhs, rhs_params = self.process_rhs(qn, 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) 

kayıt yaparken, sadece yerine Field.register_lookup(AbsoluteValueLessThan) kullanabilirsiniz.

+0

hangi dosyada yapmalıyım? – user1735921

+0

@ user1735921 artık hatırlayamıyorum. Models.py'ye ne dersin? – d33tah

+0

hey adam, şu soruya göz atabilir misiniz: http://stackoverflow.com/questions/41186414/how-to-put-in-string-in-django, kimse bunu çözemiyor – user1735921

6

Aksine bir saha araması oluşturmak yerine, en iyi uygulama bir yönetici yöntemi oluşturmak olacaktır, yani böyle biraz görünebilir:

class PersonManger(models.Manager): 
    def in_age_range(self, min, max): 
     return self.filter(age__gte=min, age__lt=max) 

class Person(models.Model): 
    age = #... 

    objects = PersonManager() 

sonra kullanım şöyle olacaktır:

twentysomethings = Person.objects.in_age_range(20, 30) 
12

Bunu yapmanın daha esnek bir yolu, özel bir QuerySet'in yanı sıra özel bir yönetici yazmaktır. Ozan kodundan çalışma: Bu, özel sorgunuzu zincirlemenizi sağlar. ,

Person.objects.in_age_range(20,30) 

Person.objects.exclude(somefield = some_value).in_age_range(20, 30) 
+0

Mükemmel! Hâlâ arabuluculuk anlaşması mantığından yararlanmak için arama alanı söz dizimine göz atmak için bazı API'ler olduğunu umuyorum. Kazmaya devam edeceğim. Bu arada, bence bu, parçaların nasıl birleştiğini anlamak için bana bir adım daha yaklaştırıyor. Teşekkürler! – jcdyer

+0

Bunu [django-qmethod] ile daha kolay/temiz bir şekilde yapabilirsiniz (https://github.com/zacharyvoase/django-qmethod). Bir süredir güncellenmemiş gibi görünüyor ama yıllardır kullanıyorum ve hiç sorun yaşamadım. – Dave

6

Öncelikle beni alenen ne istiyorsunuz kolaylaştırmak için yaratılmış bir yerde hiçbir Django makine olduğunu varsayalım: Yani her iki sorguları geçerli olacaktır.

(Düzenleme - aslında Django 1.7 beri vardır: https://docs.djangoproject.com/en/1.7/howto/custom-lookups/) Eğer gerçekten bu, alt sınıf QuerySet başarmak ve _filter_or_exclude() yöntemi geçersiz kılmak istiyorsanız, söz konusu

. Ardından, yalnızca özel QuerySet (veya maymun eki Django'nun QuerySet, yuck) öğesini döndüren özel bir yönetici oluşturun. Neo4j'ye özgü Query nesneleri oluştururken mümkün olduğunca Django ORM sorgulama kodunun çoğunu yeniden kullanmak için neo4django içinde bunu yapıyoruz.

Zach'in yanıtından uyarlanmış bir şeyi (kabaca) deneyin. Ben okuyucuya örnek :)

class PersonQuerySet(models.query.QuerySet): 
    def _filter_or_exclude(self, negate, *args, **kwargs): 
     cust_lookups = filter(lambda s: s[0].endswith('__within5'), kwargs.items()) 
     for lookup in cust_lookups: 
      kwargs.pop(lookup[0]) 
      lookup_prefix = lookup[0].rsplit('__',1)[0] 
      kwargs.update({lookup_prefix + '__gte':lookup[1]-5, 
          lookup_prefix + '__lt':lookup[1]+5}) 
     return super(PersonQuerySet, self)._filter_or_exclude(negate, *args, **kwargs) 

class PersonManager(models.Manager): 
    def get_query_set(self): 
     return PersonQuerySet(self.model) 

class Person(models.Model): 
    age = #... 

    objects = PersonManager() 

Final sözler saha arama ayrıştırma için işleme gerçek hatayı bıraktım - açıkça, sen zincir özel alan aramalarının istiyorsanız, bu oldukça kıllı olsun gidiyor. Ayrıca, normalde bunu biraz daha işlevsel olarak yazıyor ve performans için itertools kullanıyorum, ama onu dışarıda bırakmanın daha açık olduğunu düşündüm. İyi eğlenceler!

+1

Teşekkürler dostum, bu yardımcı oldu. – nisc

+0

Birinin onu kullanmasına sevindim! –

+1

Sadece cevabınızı buldum! Bunun için çok teşekkürler. Aradığım şey bu. – jcdyer