加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

python – 复杂的Django查询

发布时间:2020-12-20 11:37:00 所属栏目:Python 来源:网络整理
导读:我的大杂烩应用程序的查询超出了我对Django的ORM如何工作的了解. 这是我当前(不正确)的尝试: queryset = Mentor.objects.filter( shift__session = session,jobs_desired = job).exclude( shift__session = session,shift__jobs__time = job.time) 如果您想
我的大杂烩应用程序的查询超出了我对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__session = session),
>和一个(可能是不同的)相关联的Shift符合第二组标准shift__jobs__time = job.time.

我只想过滤出与其相关联的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)……
>如果您需要排除多个因子(AND)的项目,只需多次调用排除过滤器即可.

现在,这是您的新查询:

queryset = Mentor.objects.filter(
    shift__session = session,jobs_desired = job
).exclude(
    shift__session = session
).exclude(
    shift__jobs__time = job.time
)

如果我们“扁平化”您的要求,您需要:

>属于会话的记录:filter(shift__session = session)
>但也……不属于该会话.exclude(shift__session = session)

生成的SQL将是:

SELECT [...] WHERE shift__session = session AND [...] AND NOT(shift__session = session)

但是A∧?A(A AND NOT [A])是空集.所以问题在于查询的语义.

从你的帖子我读到:

excluding […] an associated Shift which meets the conditions specified (shift__session = session) AND a (possibly different) associated Shift that meets the second set of criteria

您使用的过滤器已经保证shift__session = session,因此您不应将其放在排除过滤器中.

根据我的猜测(但告诉我,如果我错了),你想要的是:

queryset = Mentor.objects.filter(
    shift__session = session,jobs_desired = job
).exclude(
    shift__jobs__time = job.time
)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读