2009-07-30 46 views
56

Có thể lọc theo thuộc tính không?Lọc theo thuộc tính

tôi có một phương pháp trong mô hình của tôi:

@property 
def myproperty(self): 
    [..] 

và bây giờ tôi muốn lọc theo thuộc tính này như:

MyModel.objects.filter(myproperty=[..]) 

là này bằng cách nào đó có thể?

+0

Đó là trong SQLAlchemy: http://docs.sqlalchemy.org/en/latest/orm/extensions/hybrid.html và bạn có thể kết nối django với SQLAlchemy qua https://pypi.python.org/pypi/aldjemy nhưng tôi nghi ngờ rằng cả hai có thể được kết nối theo cách bạn muốn họ được. – rattray

Trả lời

47

Không. Bộ lọc Django hoạt động ở cấp cơ sở dữ liệu, tạo ra SQL. Để lọc dựa trên các thuộc tính Python, bạn phải nạp đối tượng vào Python để đánh giá thuộc tính - và tại thời điểm đó, bạn đã thực hiện tất cả công việc để tải nó.

+2

may mắn rằng tính năng này không được triển khai, sẽ là một phần mở rộng thú vị cho ít nhất lọc ra các đối tượng phù hợp _after_ resultset đã được xây dựng. – schneck

+0

cách xử lý trong quản trị viên? Có cách giải quyết nào không? – andi

30

Tôi có thể hiểu sai câu hỏi ban đầu của bạn, nhưng có một nội dung được xây dựng trong python filter.

filtered = filter(myproperty, MyModel.objects) 

Nhưng nó tốt hơn để sử dụng một list comprehension:

filtered = [x for x in MyModel.objects if x.myproperty()] 

hoặc thậm chí tốt hơn, một generator expression:

filtered = (x for x in MyModel.objects if x.myproperty()) 
+8

Nó hoạt động để lọc nó một khi bạn có một đối tượng Python, nhưng anh ta hỏi về Django QuerySet.filter, nó xây dựng các truy vấn SQL. –

+0

đúng, nhưng như đã giải thích ở trên, tôi muốn thêm thuộc tính vào bộ lọc cơ sở dữ liệu của mình. lọc sau khi truy vấn đã được thực hiện chính xác là những gì tôi muốn tránh. – schneck

+0

tuyệt vời, cảm ơn rất nhiều! –

1

tôi biết nó là một câu hỏi cũ, nhưng vì lợi ích của những người nhảy ở đây tôi nghĩ hữu ích khi đọc câu hỏi bên dưới và câu trả lời tương đối:

How to customize admin filter in Django 1.4

3

XIN người nào đó sửa tôi, nhưng tôi đoán tôi đã tìm được giải pháp, ít nhất là cho trường hợp của riêng tôi.

Tôi muốn làm việc trên tất cả các yếu tố có thuộc tính chính xác bằng ... bất kỳ điều gì.

Nhưng tôi có một số mô hình và quy trình này sẽ hoạt động đối với tất cả các kiểu máy. Và điều đó có nghĩa là:

def selectByProperties(modelType, specify): 
    clause = "SELECT * from %s" % modelType._meta.db_table 

    if len(specify) > 0: 
     clause += " WHERE " 
     for field, eqvalue in specify.items(): 
      clause += "%s = '%s' AND " % (field, eqvalue) 
     clause = clause [:-5] # remove last AND 

    print clause 
    return modelType.objects.raw(clause) 

Với chương trình con phổ quát này, tôi có thể chọn tất cả các phần tử đó chính xác bằng từ điển 'xác định' (thuộc tính, giá trị thuộc tính).

Tham số đầu tiên mất một (models.Model),

thứ hai một cuốn từ điển như: { "property1": "77", "property2": "12"}

Và nó tạo ra một câu lệnh SQL như

SELECT * from appname_modelname WHERE property1 = '77' AND property2 = '12' 

và trả về một QuerySet trên các yếu tố đó.

Đây là một chức năng kiểm tra:

from myApp.models import myModel 

def testSelectByProperties(): 

    specify = {"property1" : "77" , "property2" : "12"} 
    subset = selectByProperties(myModel, specify) 

    nameField = "property0" 
    ## checking if that is what I expected: 
    for i in subset: 
     print i.__dict__[nameField], 
     for j in specify.keys(): 
      print i.__dict__[j], 
     print 

Và? Bạn nghĩ sao?

7

Có vẻ như using F() with annotations sẽ là giải pháp của tôi cho điều này.

Nó sẽ không lọc theo @property, kể từ khi F nói chuyện với databse trước khi các đối tượng được đưa vào python. Nhưng vẫn đặt nó ở đây như một câu trả lời vì lý do tôi muốn lọc theo thuộc tính thực sự muốn lọc các đối tượng bằng kết quả của phép tính số học đơn giản trên hai trường khác nhau.

như vậy, một cái gì đó dọc theo dòng:

companies = Company.objects\ 
    .annotate(chairs_needed=F('num_employees') - F('num_chairs'))\ 
    .filter(chairs_needed__lt=4) 

chứ không phải xác định tài sản là:

@property 
def chairs_needed(self): 
    return self.num_employees - self.num_chairs 

sau đó làm một sự hiểu biết danh sách trên tất cả các đối tượng.

3

Riffing off @ TheGrimmScientist ấy đề nghị khắc phục, bạn có thể làm cho những "thuộc tính sql" bằng cách định nghĩa chúng trên Manager hoặc QuerySet, và tái sử dụng/chuỗi/soạn chúng:

Với một Giám đốc:

class CompanyManager(models.Manager): 
    def with_chairs_needed(self): 
     return self.annotate(chairs_needed=F('num_employees') - F('num_chairs')) 

class Company(models.Model): 
    # ... 
    objects = CompanyManager() 

Company.objects.with_chairs_needed().filter(chairs_needed__lt=4) 

với một QuerySet:

class CompanyQuerySet(models.QuerySet): 
    def many_employees(self, n=50): 
     return self.filter(num_employees__gte=n) 

    def needs_fewer_chairs_than(self, n=5): 
     return self.with_chairs_needed().filter(chairs_needed__lt=n) 

    def with_chairs_needed(self): 
     return self.annotate(chairs_needed=F('num_employees') - F('num_chairs')) 

class Company(models.Model): 
    # ... 
    objects = CompanyQuerySet.as_manager() 

Company.objects.needs_fewer_chairs_than(4).many_employees() 

Xem https://docs.djangoproject.com/en/1.9/topics/db/managers/ để biết thêm. Lưu ý rằng tôi sẽ tắt tài liệu và chưa thử nghiệm ở trên.

Các vấn đề liên quan