考虑这样的django模型设置:
from django.db import models
class Foo(models.Model):
field_foo = models.CharField(max_length=20,
null=False,
blank=False,
unique=True,)
class Bar(models.Model):
field_bar = models.CharField(max_length=20,
null=False,
blank=False,
unique=True,)
class Foobar(models.Model):
field_foo = models.ForeignKey(foo,on_delete=models.CASCADE)
field_bar = models.ForeignKey(bar,on_delete=models.CASCADE)
我想查找具有相同field_foo
和field_bar
值的两行。我可以手动做到这一点,但我想知道是否有一个功能的django,照顾这一点。我现在的做法是:
for f in Foo.objects.all():
for b in Bar.objects.all():
fb = Foobar.objects.filter(foo=f, bar=b)
if len(fb)>2:
something='do'
你可以同时使用annotate()和filter()方法来过滤Foo和Bar实例作为关系的FooBar实例。
试一试
duplicate_foobars = Foobar.objects.values('id', 'field_foo', 'field_bar').annotate(
count=Count('id')
).filter(
count__gt=1
).values_list('id', 'field_foo', 'field_bar')
for id, field_foo, field_bar in duplicate_foobars:
print(f"Duplicate Foobar: #{id} field_foo={field_foo}, field_bar={field_bar}")
输出Duplicate Foobar: #1, field_foo=1, field_bar=1
测试模型class Foo(models.Model):
field_foo = models.CharField(
max_length=20,
null=False,
blank=False,
unique=True,
)
class Bar(models.Model):
field_bar = models.CharField(
max_length=20,
null=False,
blank=False,
unique=True,
)
class Foobar(models.Model):
field_foo = models.ForeignKey(Foo, on_delete=models.CASCADE)
field_bar = models.ForeignKey(Bar, on_delete=models.CASCADE)
你的手工方式也是低效的。您可以在0 (n)内使用:
foo_bar_count = {}
for fb in Foobar.objects.all():
foo_bar_pair = (fb.field_foo_id, fb.field_bar_id)
if foo_bar_pair not in foo_bar_count:
foo_bar_count[foo_bar_pair] = 0
continue
foo_bar_count[foo_bar_pair] += 1
if foo_bar_count[foo_bar_pair] > 2:
# do something
您也可以尝试使用一些奇特的查询来执行此操作。检查:Django只选择字段值重复的行
假设您的问题中有错字(有f
而不是b
,您想要的是任何一对f
,b
的fb = Foobar.objects.filter(foo=f, bar=b)
替代品),这里有一个提示:
queryset = (
Foobar.objects
.values("field_foo", "field_bar")
.annotate(nb=models.Count("id"))
.filter(nb__gt=1)
)
实际上,最优的方法取决于你想要达到的目标。
(1)如果你想知道每一对值f
,b
存在多少个Foobar
实例:
foobars = queryset.values("field_foo__field_foo", "field_bar__field_bar", "nb")
(2)或者如果您想检索所有相应的实例,您可以这样做:
from django.db.models import Q
any_of = (
Q(field_foo__field_foo=x, field_bar__field_bar=y)
for x, y in queryset.values_list("field_foo__field_foo", "field_bar__field_bar")
)
criteria = Q()
for q_obj in any_of:
criteria |= q_obj
Foobar.objects.filter(criteria)
可能也有一种方法可以使用子查询来做同样的事情,请查看文档。