เป็นไปได้ไหมที่จะกรองชุดแบบสอบถาม Django ตามคุณสมบัติของโมเดล
ฉันมีวิธีการในแบบจำลองของฉัน:
@property
def myproperty(self):
[..]
และตอนนี้ฉันต้องการกรองตามคุณสมบัตินี้เช่น:
MyModel.objects.filter(myproperty=[..])
เป็นไปได้ไหม
เป็นไปได้ไหมที่จะกรองชุดแบบสอบถาม Django ตามคุณสมบัติของโมเดล
ฉันมีวิธีการในแบบจำลองของฉัน:
@property
def myproperty(self):
[..]
และตอนนี้ฉันต้องการกรองตามคุณสมบัตินี้เช่น:
MyModel.objects.filter(myproperty=[..])
เป็นไปได้ไหม
คำตอบ:
ไม่ ตัวกรอง Django ทำงานที่ระดับฐานข้อมูลสร้าง SQL ในการกรองตามคุณสมบัติของ Python คุณต้องโหลดออบเจ็กต์ลงใน Python เพื่อประเมินคุณสมบัติ - และเมื่อถึงจุดนั้นคุณได้ทำงานทั้งหมดเพื่อโหลดแล้ว
ฉันอาจเข้าใจผิดในคำถามเดิมของคุณ แต่มีตัวกรองใน python
filtered = filter(myproperty, MyModel.objects)
แต่จะดีกว่าถ้าใช้ความเข้าใจในรายการ :
filtered = [x for x in MyModel.objects if x.myproperty()]
หรือดีกว่านั้นคือการแสดงออกของเครื่องกำเนิดไฟฟ้า :
filtered = (x for x in MyModel.objects if x.myproperty())
วิธีแก้ปัญหาที่แนะนำของ @ TheGrimmScientist คุณสามารถสร้าง "คุณสมบัติ sql" เหล่านี้ได้โดยการกำหนดคุณสมบัติเหล่านี้ใน Manager หรือ QuerySet และใช้ซ้ำ / chain / compose:
ด้วยผู้จัดการ:
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)
ด้วย 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()
ดูhttps://docs.djangoproject.com/en/1.9/topics/db/managers/สำหรับข้อมูลเพิ่มเติม โปรดทราบว่าฉันกำลังจะปิดเอกสารและไม่ได้ทดสอบข้างต้น
ดูเหมือนว่าการใช้ F () กับคำอธิบายประกอบจะเป็นวิธีแก้ปัญหาของฉัน
จะไม่กรองตาม@property
เนื่องจากการF
พูดคุยกับฐานข้อมูลก่อนที่จะนำวัตถุเข้าสู่ python แต่ยังคงใส่ไว้ที่นี่เป็นคำตอบเนื่องจากเหตุผลของฉันที่ต้องการกรองตามคุณสมบัติคือต้องการกรองวัตถุโดยผลของการคำนวณทางคณิตศาสตร์อย่างง่ายในสองฟิลด์ที่แตกต่างกัน
ดังนั้นบางสิ่งบางอย่างตามแนวของ:
companies = Company.objects\
.annotate(chairs_needed=F('num_employees') - F('num_chairs'))\
.filter(chairs_needed__lt=4)
แทนที่จะกำหนดคุณสมบัติให้เป็น:
@property
def chairs_needed(self):
return self.num_employees - self.num_chairs
จากนั้นทำความเข้าใจรายการในวัตถุทั้งหมด
ฉันมีปัญหาเดียวกันและฉันได้พัฒนาวิธีง่ายๆนี้:
objects_id = [x.id for x in MyModel.objects.all() if x.myProperty == [...]]
MyModel.objects.filter(id__in=objects_id)
ฉันรู้ว่ามันไม่ใช่วิธีแก้ปัญหาที่มีประสิทธิภาพที่สุด แต่อาจช่วยได้ในกรณีง่ายๆเช่นเดียวกับฉัน
โปรดมีคนช่วยแก้ไขให้ฉัน แต่ฉันคิดว่าฉันพบวิธีแก้ปัญหาแล้วอย่างน้อยก็สำหรับกรณีของฉันเอง
ฉันต้องการทำงานกับองค์ประกอบทั้งหมดที่มีคุณสมบัติเท่ากับ ... อะไรก็ได้
แต่ฉันมีหลายรุ่นและกิจวัตรนี้ควรใช้ได้กับทุกรุ่น และมันทำ:
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)
ด้วยรูทีนย่อยสากลนี้ฉันสามารถเลือกองค์ประกอบเหล่านั้นทั้งหมดซึ่งเท่ากับพจนานุกรมของชุดค่าผสม 'ระบุ' (ชื่อคุณสมบัติ, ค่าคุณสมบัติ)
พารามิเตอร์แรกใช้เวลา a (models.Model)
อันที่สองพจนานุกรมเช่น: {"property1": "77", "property2": "12"}
และสร้างคำสั่ง SQL เช่น
SELECT * from appname_modelname WHERE property1 = '77' AND property2 = '12'
และส่งคืน QuerySet บนองค์ประกอบเหล่านั้น
นี่คือฟังก์ชั่นทดสอบ:
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
และ? คุณคิดอย่างไร?
AttributeError: 'RawQuerySet' object has no attribute 'values'
ฉันรู้ว่ามันเป็นคำถามเก่า แต่เพื่อประโยชน์ของผู้ที่กระโดดมาที่นี่ฉันคิดว่าการอ่านคำถามด้านล่างและคำตอบที่เกี่ยวข้องมีประโยชน์:
มันก็อาจจะเป็นไปได้ที่จะใช้คำอธิบายประกอบชุดข้อความค้นหาที่ซ้ำกันสถานที่ให้บริการรับ / ชุดตรรกะเป็นเช่นแนะนำโดย@rattrayและ@thegrimmscientist , ร่วมกับ property
สิ่งนี้อาจให้ผลบางอย่างที่ใช้ได้ทั้งในระดับ Python และในระดับฐานข้อมูล
อย่างไรก็ตามไม่แน่ใจเกี่ยวกับข้อเสียโปรดดูตัวอย่างคำถาม SO นี้