Как построить Django QuerySet для проверки условий на двух полях manyToMany
У меня есть следующие модели (упрощенно):
class Resource(models.Model):
name = models.CharField(max_length=64, unique=True)
class ResourceFlow(models.Model):
resource = models.ForeignKey(Resource, related_name="flow")
amount = models.IntegerField()
class Workflow(models.Model):
inputs = models.ManyToManyField(ResourceFlow, related_name="workflow")
class Stock(models):
resource = models.ForeignKey(Resource, related_name="stock")
amount = models.IntegerField()
class Producer(models.Model):
workflow = models.ForeignKey(Workflow, related_name="location")
stocks = models.ManyToManyField(Stock, related_name="location")
Я хотел бы протестировать с вычислениями, выполняемыми движком БД, если я могу начать производство.
Производство может начаться, если у меня достаточно запасов: для рабочего процесса Производителя, все входы ResourcesFlow amount должны присутствовать в запасах Производителя
Так что набор запросов может быть одним из таких результатов:
- для данного производителя вернуть все запасы ресурсов, которые не удовлетворяют условиям количества входов рабочего процесса
- для данного производителя вернуть ресурсы, необходимые для рабочего процесса, которые не находятся в достаточном количестве в его запасах .
Возможно ли это сделать в Django? И если да, то как это сделать?
Не уверен, что вы нашли ответ, но в любом случае, надеюсь, я правильно понял ваш вопрос.
Предположим, что у нас есть следующие ресурсы:
head = Resource.objects.create(name="head")
neck = Resource.objects.create(name="neck")
body = Resource.objects.create(name="body")
arm = Resource.objects.create(name="arm")
leg = Resource.objects.create(name="leg")
У нас есть build_a_robot
рабочий процесс:
build_a_robot = Workflow.objects.create()
build_a_robot.inputs.add(ResourceFlow.objects.create(resource=head, amount=1))
build_a_robot.inputs.add(ResourceFlow.objects.create(resource=neck, amount=1))
build_a_robot.inputs.add(ResourceFlow.objects.create(resource=body, amount=1))
build_a_robot.inputs.add(ResourceFlow.objects.create(resource=arm, amount=2))
build_a_robot.inputs.add(ResourceFlow.objects.create(resource=leg, amount=2))
Наконец, у нас есть producer
:
producer = Producer.objects.create(workflow=build_a_robot)
producer.stocks.add(Stock.objects.create(resource=head, amount=0))
producer.stocks.add(Stock.objects.create(resource=neck, amount=3))
producer.stocks.add(Stock.objects.create(resource=body, amount=1))
producer.stocks.add(Stock.objects.create(resource=arm, amount=10))
producer.stocks.add(Stock.objects.create(resource=leg, amount=1))
Мы хотим найти список ресурсов, которые закончились для создания робота, заданного producer
.
Я думаю, что вот один из способов сделать это:
from django.db.models import OuterRef, Subquery
required_resources = ResourceFlow.objects.filter(pk__in=producer.workflow.inputs.values("pk")).values("resource")
required_amount = producer.workflow.inputs.filter(resource=OuterRef("resource")).values("amount")[:1]
missing_stocks = Stock.objects.filter(resource_id__in=required_resources).filter(amount__lt=required_amount)
В данном примере missing_stocks
будет равно:
<QuerySet [<Stock: Stock [Resource [head], 0]>, <Stock: Stock [Resource [leg], 1]>]>
Итак, нам нужны еще голова и ноги, чтобы построить робота.