Apakah mungkin untuk memfilter queryset Django berdasarkan properti model?
saya memiliki metode dalam model saya:
@property
def myproperty(self):
[..]
dan sekarang saya ingin memfilter berdasarkan properti ini seperti:
MyModel.objects.filter(myproperty=[..])
apakah ini mungkin?
Jawaban:
Nggak. Filter Django beroperasi pada tingkat basis data, menghasilkan SQL. Untuk memfilter berdasarkan properti Python, Anda harus memuat objek ke Python untuk mengevaluasi properti - dan pada titik itu, Anda sudah melakukan semua pekerjaan untuk memuatnya.
sumber
Saya mungkin salah memahami pertanyaan awal Anda, tetapi ada filter bawaan python.
Tetapi lebih baik menggunakan pemahaman daftar :
filtered = [x for x in MyModel.objects if x.myproperty()]
atau bahkan lebih baik, ekspresi generator :
filtered = (x for x in MyModel.objects if x.myproperty())
sumber
Berdasarkan solusi yang disarankan @ TheGrimmScientist, Anda dapat membuat "properti sql" ini dengan menentukannya di Manajer atau QuerySet, dan menggunakan kembali / rantai / buat mereka:
Dengan Manajer:
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)
Dengan 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()
Lihat https://docs.djangoproject.com/en/1.9/topics/db/managers/ untuk selengkapnya. Perhatikan bahwa saya akan menonaktifkan dokumentasi dan belum menguji yang di atas.
sumber
Sepertinya menggunakan F () dengan penjelasan akan menjadi solusi saya untuk ini.
Ini tidak akan difilter
@property
, karenaF
berbicara ke databse sebelum objek dibawa ke python. Tapi tetap meletakkannya di sini sebagai jawaban karena alasan saya ingin memfilter berdasarkan properti sebenarnya ingin memfilter objek berdasarkan hasil aritmatika sederhana pada dua bidang berbeda.jadi, sesuatu di sepanjang baris:
companies = Company.objects\ .annotate(chairs_needed=F('num_employees') - F('num_chairs'))\ .filter(chairs_needed__lt=4)
daripada mendefinisikan properti menjadi:
@property def chairs_needed(self): return self.num_employees - self.num_chairs
lalu melakukan pemahaman daftar di semua objek.
sumber
Saya memiliki masalah yang sama, dan saya mengembangkan solusi sederhana ini:
objects_id = [x.id for x in MyModel.objects.all() if x.myProperty == [...]] MyModel.objects.filter(id__in=objects_id)
Saya tahu ini bukan solusi yang paling berkinerja, tetapi dapat membantu dalam kasus sederhana seperti saya
sumber
TOLONG seseorang mengoreksi saya, tetapi saya rasa saya telah menemukan solusi, setidaknya untuk kasus saya sendiri.
Saya ingin mengerjakan semua elemen yang propertinya sama persis dengan ... apa pun.
Tapi saya punya beberapa model, dan rutinitas ini seharusnya bekerja untuk semua model. Dan memang:
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)
Dengan subrutin universal ini, saya dapat memilih semua elemen yang sama persis dengan kamus saya tentang kombinasi 'spesifik' (nama properti, nilai properti).
Parameter pertama mengambil (model.Model),
kamus kedua seperti: {"property1": "77", "property2": "12"}
Dan itu menciptakan pernyataan SQL seperti
SELECT * from appname_modelname WHERE property1 = '77' AND property2 = '12'
dan mengembalikan QuerySet pada elemen tersebut.
Ini adalah fungsi uji:
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
Dan? Bagaimana menurut anda?
sumber
AttributeError: 'RawQuerySet' object has no attribute 'values'
Saya tahu ini adalah pertanyaan lama, tetapi demi mereka yang melompat ke sini saya pikir ada gunanya membaca pertanyaan di bawah ini dan jawaban relatifnya:
Bagaimana menyesuaikan filter admin di Django 1.4
sumber
Hal ini juga mungkin untuk menggunakan anotasi queryset yang menduplikasi mendapatkan properti / set-logika, seperti yang disarankan misalnya oleh @rattray dan @thegrimmscientist , dalam hubungannya dengan yang
property
. Ini bisa menghasilkan sesuatu yang berfungsi baik pada level Python maupun pada level database.Tidak yakin tentang kekurangannya, bagaimanapun: lihat pertanyaan SO ini sebagai contoh.
sumber