19

フィールド (またはリスト)のすべての要素が別のフィールドに存在するかどうかを確認する Django クエリを作成する最良の方法について、私はかなり困惑しています。ManyToManyManyToMany

例として、私は複数Personの専門分野を持つことができる複数の を持っています。開始できるもありますがJob、開始するには 1 つ以上Specialtyの が適格である必要があります。

class Person(models.Model):
    name = models.CharField()
    specialties = models.ManyToManyField('Specialty')

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

class Job(models.Model):
    required_specialties = models.ManyToManyField('Specialty')

仕事に必要なすべての専門性を持っている場合にのみ、人は仕事を始めることができます。ここでも例として、3 つの専門分野があります。

  • コーディング
  • 歌う
  • ダンシング

そして、私はJob歌と踊りの専門を必要とする を持っています。歌と踊りが得意な人なら始められますが、コーディングと歌が得意な人は始められません。

そのため、人が引き受けることができるすべての仕事を見つける方法が必要です。これが私のやり方でしたが、もっとエレガントなアプローチがあると確信しています:

def jobs_that_person_can_start(person):
    # we start with all jobs
    jobs = Job.objects.all()
    # find all specialties that this person does not have
    specialties_not_in_person = Specialty.objects.exclude(name__in=[s.name for s in person.specialties])
    # and exclude jobs that require them
    for s in specialties_not_in_person:
        jobs = jobs.exclude(specialty=s)
    # the ones left should fill the criteria
    return jobs.distinct()

これは、 を使用すると、その人の専門分野のすべてではなく、いずれかJob.objects.filter(specialty__in=person.specialties.all())の専門分野に一致する仕事が返されるためです。このクエリを使用すると、歌と踊りを必要とするジョブが歌のコーダーに表示されますが、これは望ましい出力ではありません。

この例が複雑すぎないことを願っています。私がこれについて心配している理由は、システム内の専門分野がおそらくもっと多くなり、それらをループすることがこれを達成するための最良の方法とは思えないからです. 誰かこのかゆみにかすり傷をつけてくれませんか!

4

2 に答える 2

16

別のアイデア

わかりました、これを他の回答に追加する必要があったと思いますが、始めたときは別の方向になるように見えました笑

繰り返す必要はありません:

person_specialties = person.specialties.values_list('pk', flat=True)

non_specialties = Specialties.objects.exclude(pk__in=person_specialties)

jobs = Job.objects.exclude(required_specialties__in=non_specialties)

:これがどれほど速いかは正確にはわかりません。あなたは私の他の提案でより良いかもしれません.
また: このコードはテストされていません

于 2009-12-03T19:54:11.220 に答える
6

その人の専門分野を取得するには、values_listを使用することを検討する必要があると思います

交換:

[s.name for s in person.specialties]

と:

person.specialties.values_list('name', flat=True)

これにより、再度使用できるわかりやすいリスト(つまり、['spec1'、'spec2'、...])が得られます。また、bgで使用されるSQLクエリはselect *、ORMオブジェクトにデータを入力する代わりに、「名前」のみを選択するため、より高速になります。

また、その人が間違いなく実行できないジョブをフィルタリングすることで、速度が向上する場合があります。

だから交換してください:

jobs = Job.objects.all()

with(2クエリ-django 1.0以降で動作します)

person_specialties = person.specialties.values_list('id', flat=True)
jobs = Job.objects.filter(required_specialties__id__in=person_specialties)

または(1クエリ?-django1.1 +で動作します)

jobs = Job.objects.filter(required_specialties__in=person.specialties.all())

また、ジョブ/個人クエリでselect_related()を使用することで改善が得られる場合があります(使用している外部キーがあるため)

于 2009-12-03T19:10:05.553 に答える