【问题标题】:Django Queries with many2many & 'through'带有 many2many 和“通过”的 Django 查询
【发布时间】:2021-07-30 05:45:22
【问题描述】:

我对 Django 还是很陌生,在理解如何在我的数据库中获取数据时遇到了一些麻烦。 然而,我认为我的问题并不复杂:我有音乐作品和乐器。要进行,每件作品都需要一定数量的各种乐器

这是我的模型:

class Instrument(models.Model):
    name = models.CharField()


class MusicWork(models.Model):
    name = models.CharField()
    performers = models.ManyToManyField(Instrument, through='MusicWorkInstrument')


class MusicWorkInstrument(models.Model):
    work = models.ForeignKey(MusicWork, on_delete=models.CASCADE)
    instrument = models.ForeignKey(Instrument, on_delete=models.CASCADE)
    quantity = models.IntegerField()

现在我有了我的数据库结构,我想执行一些查询。 例如,我弹钢琴,我想和我的小提琴手朋友一起弹奏。

  • 我怎样才能要求所有的作品都是由 1 架钢琴和 1 把小提琴组成的?

假设我们没有找到有趣的东西,那么让我们尝试找到一些安排:

  • 我怎样才能获得使用 1 架钢琴和 1 种其他乐器的所有作品?

我们改变了主意,现在我们想找一位新的音乐家伙伴:

  • 我们需要搜索所有包含 1 架钢琴、1 把小提琴和除巴松管之外的任何其他乐器的作品(抱歉,它不适合小提琴 :()

我花了大约 3 个小时试图弄清楚如何处理这些请求,但由于我刚刚学习 Django,我不知道 QuerySet 上的所有操作,我很困惑..

拜托,你能帮我找到和我朋友一起玩的东西吗? :D

谢谢!

【问题讨论】:

    标签: python django database filter


    【解决方案1】:

    我只做了第一个,但应该都是类似的。我不能在直接查询中做到这一点,所以我不得不使用一些 python。

    数据库中的数据输入

    i1 = Instrument.objects.create(name="piano")
    i2 = Instrument.objects.create(name="violin")
    i3 = Instrument.objects.create(name="drums")
    i4 = Instrument.objects.create(name="guitar")
    i5 = Instrument.objects.create(name="bassoon")
    
    w1 = MusicWork.objects.create(name="w1") # w1 contains extra instrument
    w1.performers.add(i1, through_defaults={'quantity':1})
    w1.performers.add(i2, through_defaults={'quantity':1})
    w1.performers.add(i3, through_defaults={'quantity':1})
    
    w2 = MusicWork.objects.create(name="w2") # w2 is the required work
    w2.performers.add(i1, through_defaults={'quantity':1})
    w2.performers.add(i2, through_defaults={'quantity':1})
    
    w3 = MusicWork.objects.create(name="w3") # w3 has wrong quantities
    w3.performers.add(i1, through_defaults={'quantity':2})
    w3.performers.add(i2, through_defaults={'quantity':1})
    
    MusicWorkInstrument.objects.all()
    

    最后一行代码的输出是

    <QuerySet[
        <MusicWorkInstrument: w1-piano-1>,
        <MusicWorkInstrument: w1-violin-1>,
        <MusicWorkInstrument: w1-drums-1>,
        <MusicWorkInstrument: w2-piano-1>,
        <MusicWorkInstrument: w2-violin-1>,
        <MusicWorkInstrument: w3-piano-2>,
        <MusicWorkInstrument: w3-violin-1>
    ]>
    

    获取所有与数量为 1 的钢琴乐器的作品

    query1 = [i.work for i in MusicWorkInstrument.objects.filter(instrument__name="piano", quantity=1)]
    query1
    Out: [<MusicWork: w1>, <MusicWork: w2>]
    

    获取所有作品与数量为 1 的小提琴乐器

    query2 = [i.work for i in MusicWorkInstrument.objects.filter(instrument__name="violin", quantity=1)]
    query2
    Out: [<MusicWork: w1>, <MusicWork: w2>, <MusicWork: w3>]
    

    获取包含任何数量的任何其他乐器的所有作品

    excluding_list = [i.name for i in Instrument.objects.exclude(name__in=["piano","violin"])]
    excluding_list
    Out: ['drums', 'guitar', 'bassoon']
    
    query3 = [ i.work for i in MusicWorkInstrument.objects.filter(instrument__name__in=excluding_list) ]
    query3
    Out: [<MusicWork: w1>]
    

    前 2 个和第 3 个不同的交点会给出答案

    query_final = ( set(query1) & set(query2 ) ).difference( set(query3) )
    query_final
    Out: {<MusicWork: w2>}   # this is a set
    

    【讨论】:

    • 感谢您的回答!这与我所拥有的已经有了很大的不同,因为我试图从 Work 模型开始,这有点奇怪。我会尝试单独找到其他答案(但如果有人有想法,请随时告诉我:D)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-15
    • 1970-01-01
    • 1970-01-01
    • 2011-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多