python – 复杂的Django查询
我的大杂烩应用程序的查询超出了我对Django的ORM如何工作的了解.
这是我当前(不正确)的尝试: queryset = Mentor.objects.filter( shift__session = session,jobs_desired = job ).exclude( shift__session = session,shift__jobs__time = job.time ) 如果您想阅读它们,我的模型如下. 初始filter()工作正常.我的问题是将exclude()链接到最后. exclude()似乎排除了Mentors: >符合指定条件的关联Shift 我只想过滤出与其相关联的Shift的导师符合标准. 有任何想法吗? class DojoSession(models.Model): term = models.ForeignKey(DojoTerm,help_text = "Dojo Term") date = models.DateField( blank = False,help_text = "Date during which the session will take place." ) start = models.TimeField( blank = False,help_text = "Start Time" ) end = models.TimeField( blank = False,help_text = "End Time" ) rooms = models.ManyToManyField( Room,blank = True,help_text = "The rooms in which this session will be running." ) class Shift(models.Model): mentor = models.ForeignKey( 'mentors.Mentor',blank = False,help_text = 'The mentor unergoing this shift.' ) session = models.ForeignKey( DojoSession,help_text = 'The session during which this shift takes place.',) role = models.ForeignKey( 'mentors.Role',help_text = "The role that the mentor will be undertaking during this shift.",) room = models.ForeignKey( Room,null = True,help_text = "The room,if any,that the mentor will be undertaking the shift in." ) jobs = models.ManyToManyField( 'jobs.Job',) start = models.TimeField( blank = False,help_text = "End Time" ) class Job(models.Model): BEFORE = 'B' DURING = 'D' AFTER = 'A' TIME_CHOICES = ( (BEFORE,'Before session'),(DURING,'During session'),(AFTER,'After session'),) name = models.CharField( max_length = 50,help_text = "The job's name." ) description = models.TextField( max_length = 1024,help_text = "A description of the job." ) location = models.CharField( max_length = 50,help_text = "The job's location." ) time = models.CharField( max_length = 1,choices = TIME_CHOICES,help_text = "The time during a session at which this job can be carried out." ) class Mentor(models.Model): MALE_SMALL = "MS" MALE_MEDIUM = "MM" MALE_LARGE = "ML" MALE_EXTRA_LARGE = "MXL" FEMALE_EXTRA_SMALL = "FXS" FEMALE_SMALL = "FS" FEMALE_MEDIUM = "FM" FEMALE_LARGE = "FL" FEMALE_EXTRA_LARGE = "FXL" SHIRT_SIZE_CHOICES = ( ('Male',( (MALE_SMALL,"Male S"),(MALE_MEDIUM,"Male M"),(MALE_LARGE,"Male L"),(MALE_EXTRA_LARGE,"Male XL") )),('Female',( (FEMALE_EXTRA_SMALL,"Female XS"),(FEMALE_SMALL,"Female S"),(FEMALE_MEDIUM,"Female M"),(FEMALE_LARGE,"Female L"),(FEMALE_EXTRA_LARGE,"Female XL") )) ) ASSOCIATE = 'A' STAFF = 'S' NEITHER = 'N' CURTIN_STATUS_CHOICES = ( (ASSOCIATE,'Associate'),(STAFF,'Staff'),(NEITHER,'Neither/not sure') ) NOTHING = 'NO' SOMETHING = 'SO' EVERYTHING = 'EV' KNOWLEDGE_CHOICES = ( (NOTHING,'I know nothing but am keen to learn!'),(SOMETHING,'I know some basics'),(EVERYTHING,'I know a great deal') ) uni = models.CharField( max_length = 50,help_text = "University of study" ) uni_study = models.CharField( max_length = 256,help_text = "If you're attending university,what are you studying?" ) work = models.CharField( max_length = 256,help_text = "If you workwhat do you do?" ) shirt_size = models.CharField( max_length = 3,choices = SHIRT_SIZE_CHOICES,help_text = "T-shirt size (for uniform)" ) needs_shirt = models.BooleanField( default = True,help_text = "Does the mentor need to have a shirt provisioned for them?" ) wwcc = models.CharField( max_length = 10,verbose_name = "WWCC card number",help_text = "WWCC card number (if WWCC card holder)" ) wwcc_receipt = models.CharField( max_length = 15,verbose_name = "WWCC receipt number",help_text = "WWCC receipt number (if WWCC is processing)" ) curtin_status = models.CharField( max_length = 1,verbose_name = "Current Curtin HR status",choices = CURTIN_STATUS_CHOICES,default = NEITHER,help_text = "When possible,we recommend that all CoderDojo mentors are either Curtin University Associates or Staff members." ) curtin_id = models.CharField( max_length = 10,verbose_name = "Curtin Staff/Associate ID",help_text = "Your Curtin Staff/Associate ID (if applicable)" ) coding_experience = models.CharField( max_length = 2,default = NOTHING,choices = KNOWLEDGE_CHOICES,help_text = "How much programming experience do you have?" ) children_experience = models.CharField( max_length = 2,help_text = "How much experience do you have with children?" ) roles_desired = models.ManyToManyField(Role) jobs_desired = models.ManyToManyField('jobs.Job') shift_availabilities = models.ManyToManyField( 'planner.DojoSession',help_text = "When are you available?" ) user = models.OneToOneField(settings.AUTH_USER_MODEL,unique = True ) 解决方法
首先,我们来解释一下这里发生了什么.当你写:
set.exclude( A=arg1,B=arg2 ) 这转换为以下查询: SELECT [...] WHERE NOT (A=arg1 AND B=arg2) 在boolean algebra中,?(A∧B)(不是[A和B])实际上是(?A∨?B)(不是[A] OR而不是[B]). SELECT [...] WHERE NOT(A=arg1) OR NOT(B=arg2) 编写具有多个参数的excludefilter时,请记住这一点. 因此,如果在您的查询中,您想要排除检查BOTH标准的元素(如果您愿意,那么标准的交集),最简单和最好的方法是链排除过滤器: set.exclude(A=arg1).exclude(B=arg2) 查询集操作是惰性的,大致意味着您的排除过滤器将同时进行评估.因此,两个过滤器不会是“工作的两倍”. 过滤器将转换为: SELECT [...] WHERE NOT(A=arg1) AND NOT(B=arg2) 这正是你想要的! 编写查询有时很难,但请记住: >排除多个args转换为:not(A)OR not(B)OR not(C)…… 现在,这是您的新查询: queryset = Mentor.objects.filter( shift__session = session,jobs_desired = job ).exclude( shift__session = session ).exclude( shift__jobs__time = job.time ) 如果我们“扁平化”您的要求,您需要: >属于会话的记录:filter(shift__session = session) 生成的SQL将是: SELECT [...] WHERE shift__session = session AND [...] AND NOT(shift__session = session) 但是A∧?A(A AND NOT [A])是空集.所以问题在于查询的语义. 从你的帖子我读到:
您使用的过滤器已经保证shift__session = session,因此您不应将其放在排除过滤器中. 根据我的猜测(但告诉我,如果我错了),你想要的是: queryset = Mentor.objects.filter( shift__session = session,jobs_desired = job ).exclude( shift__jobs__time = job.time ) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |