2017-04-23 13 views
1

私は企業にサービスを提供しています(多対多はServiceCompanyの間)。私のサービスを構造化するために、私はDjangoの多対多フィールドを使って木のような構造を使います。したがって、サービスには複数の他のサービスを含めることができます。非対称の多対多のDjangoの同じモデルへの再帰的クエリ

質問:会社が持つすべてのサービスを取得するにはどうすればよいですか? company.servicesを使用して、私はその会社に直接関連するサービスを取得するだけです。私は直接関係するもの+ included_services(再帰的な方法で)が必要です。

class Company(models.Model): 
    services = models.ManyToManyField(Service) 

class Service(models.Model): 
    name = models.CharField(max_length=255) 
    included_services = models.ManyToManyField("self", blank=True, symmetrical=False) 

答えて

0

は、私はあなたがDjangoのORMフレームワークを使用したり、プレーン生SQL文を書いて、これを行うことができるとは思いません。ツリー形式の構造で表現されたモデルをより効率的に格納/検索できるようにするdjango-mpttのようなサードパーティのライブラリを見てみるとよいでしょう。

あなたは、Python経由でそれをしたい場合は、ここで何ができるかです:

def get_services(company): 
    services = list(company.services.all()) 
    result = [] 
    while services: 
     service = services.pop(0) 
     result.append(service) 
     services.extend(list(service.included_services.all())) 
    return result 

上記のアイデアがツリーにbreadth-first searchを実行すると非常によく似ています。

+0

これは素晴らしいです、ありがとうございます!再帰的な解決策がありましたが、この幅優先探索は読みやすいアプローチです。 –

+0

このアプローチでは、サービスグラフにサイクルを導入しないように注意する必要があります。そうしないと、無限ループで実行されます。 – knbk

0

戻り値としてQuerySetが必要なことを忘れていましたので、@ ozgurのexellent回答を少し修正しました。場合によっては、誰かがこれを必要とする場合もあります。

def get_services(company): 
    services = list(company.services.all()) 
    pks = [] 
    while services: 
     service = services.pop(0) 
     if service.pk not in pks: 
      pks.append(service.pk) 
      services.extend(list(service.included_services.all())) 
    return Service.objects.filter(pk__in=pks) 

EDIT:潜在的なループのチェックも追加しました。