3

簡単な例として、Productクラスがあるとします。

class Product(models.Model):
    tags = models.ManyToManyField('Tag',blank=True,null=True)

私のTagクラスは次のようになります

class Tag(models.Model):
    name = models.CharField(max_length=50, unique=True, db_index=True)

1つの製品がある場合、他のすべての製品の結果セットを最も一般的なタグで並べ替えるにはどうすればよいですか?

たとえば、私は次のようにしています。

タグA、B、およびCを含む
P1タグB、Cを含むP2、タグBを
含むP3
タグA、B、およびCを含むP4

結果セットからP1を除外すると仮定すると、P1の結果セットをP4、P2、P3の順にしたいと思います。

4

2 に答える 2

1

これは典型的な自己結合の使用法であり、SQLは次のようになります。

SELECT t3.*, count(t2.tag_id) as similar_tags_count
FROM m2m_tbl t1 INNER JOIN m2m_tbl t2 
     ON (t1.tag_id = t2.tag_id and t1.product_id != t2.product_id and t1.product_id = pk_of_the_given_product)
     INNER JOIN product_tbl t3 ON (t2.product_id = t3.id)
GROUP BY t3.id, t3.name
ORDER BY similar_tags_count DESC;

次に、クエリを次の宛先にフィードできます.raw()

Product.objects.raw("""
SELECT t3.*, count(t2.tag_id) as similar_tags_count
FROM {m2m_tbl} t1 INNER JOIN {m2m_tbl} t2 
     ON (t1.tag_id = t2.tag_id and t1.product_id != t2.product_id and t1.product_id = %s)
     INNER JOIN {product_tbl} t3 ON (t2.product_id = t3.id)
GROUP BY t3.id, t3.name
ORDER BY similar_tags_count DESC;
""".format(m2m_tbl=Product.tags.through._meta.db_table, product_tbl=Product._meta.db_table),
    [the_given_product.pk])

または、本当に:が必要な場合は、 UNDOCUMENTED query.join()のdocstringにもあります)を使用して結合を処理します。query.join()QuerySet

m2m_tbl = Product.tags.through._meta.db_table
qs = Product.objects.exclude(pk=the_given_product.pk)
alias_1 = qs.query.get_initial_alias()
alias_2 = qs.query.join((alias_1, m2m_tbl, 'id', 'product_id'))
alias_3 = qs.query.join((alias_2, m2m_tbl, 'tag_id', 'tag_id'))
qs = qs.annotate(similar_tags_count=models.Count('tags__id')).extra(where=[
    '{alias_2}.product_id != {alias_3}.product_id'.format(alias_2=alias_2, alias_3=alias_3),
    '{alias_3}.product_id = %s'.format(alias_3=alias_3)
], params=[the_given_product.pk])
于 2013-02-21T08:34:03.487 に答える
0

両方のターンリストを仮定すると、あなたはそのようなことをすることができます

P1 = ['A', 'B', 'C'] # these being products
P3 = ['B']
P4 = ['A', 'B', 'C']

P1 = set(P1)
P3_INTERSECT = len(P1.intersection(P3))
P4_INTERSECT = len(P1.intersection(P4))

それらはそれぞれ1と3を返します、それから私はあなたの結果を注文するためにそれを使用します。これを行う必要が生じた場合は、この順序付けを行うための独自のマネージャーを定義することをお勧めします。

于 2013-02-21T03:26:38.790 に答える