Django Exists() / ~Exists() вернуть, если нет совпадающих данных?

РЕДАКТИРОВАТЬ:

В соответствии с ответом Шиллингта ниже я переключился на использование Case/When:

        context['db_orders'] = Order.objects.filter(
            retailer_code=self.object.retailer_code).annotate(
            in_db=Case(When(Q(Subquery(self.object.suppliers.filter(
                supplier_code=(OuterRef('supplier_code')))
            ), then=Value(True), default=Value(False), output_field=NullBooleanField()))))

Однако теперь я борюсь с ошибкой:

FieldError at /retailers/A001/

Cannot resolve expression type, unknown output_field

Исходный вопрос:

У меня есть DetailView ниже с запросом / подзапросом, который проверяет, существует ли supplier_code в экземплярах второй модели, настроенной для представления заказов на покупку, полученных в базе данных реальных запасов.

Намерение состоит в том, чтобы это функционировало как контрольный список / контрольный лист, который будет возвращать, был ли получен заказ для каждого поставщика, который должен его отправить.

Получение от него возврата, что есть совпадение, похоже, работает нормально, и если есть значение, которое оно не распознает (я намеренно создал недопустимый порядок, который не будет соответствовать списку), он вернет, что совпадения нет..

Однако мне нужно это также, чтобы сказать мне, что данных просто нет, но, похоже, я не могу этого добиться.

Например, ниже показан вывод шаблона; G001 - это "поддельный" код, который я установил, а G002 - действительный код, который существует в списке поставщиков. Однако, если на G002 нет заказа, он ничего не вернет.

    Order not received: G001
    Order received: G002

Я попытался написать второй запрос для контекста, который является зеркалом контекста ['db_orders'], но с использованием ~Exists(), а затем вложением операторов if в шаблон, но это просто скажет мне, что заказы существуют и не выполняются. не существует или наоборот.

 context['not_db_orders'] = Order.objects.filter(
            retailer_code=self.object.retailer_code).annotate(in_db=~Exists(squery))

Я также пытался сделать это в шаблоне, используя 'is not' или 'is None' или 'is False', но не могу получить нужный мне результат.

В конечном итоге предполагаемый результат представляет собой таблицу, в которой перечислены все поставщики, ожидаемые в конкретном розничном торговце, с каким-то образом "Да" или "Нет" рядом с ними в зависимости от того, существует ли заказ среди экземпляров Order. (HTML-код шаблона в настоящее время не отражает этого, но проблема не в этом)

Шаблон:

{% extends 'tick_sheet/base.html' %}

{% block content %}

<h1>{{ object.retailer_name }}</h1>
<ul>
    {% for supplier in object.get_supplier_values %}
    <li>{{ supplier }}</li>
    {% endfor %}
</ul>

<ul>
{% for item in db_orders %}
        {% if item.in_db %}
            <li>Order received: {{ item.supplier_code }} - {{ item.supplier_name }}</li>
        {% elif not item.in_db or item.in_db is None %}
            <li>Order not received: {{ item.supplier_code }} - {{item.supplier_name}}</li>
        {% endif %}
{% endfor %}
</ul>
{% endblock content %}

Подробный просмотр:

class RetailerDetailView(DetailView):

    model = Retailer
    slug_field = 'retailer_code'
    slug_url_kwarg = 'retailer_code'

    def get_context_data(self, **kwargs):

        context = super().get_context_data(**kwargs)
        context['now'] = timezone.now()
        context['title'] = 'Order Checklist'

        squery = self.object.suppliers.filter(
            supplier_code=OuterRef('supplier_code'))

        context['db_orders'] = Order.objects.filter(
            retailer_code=self.object.retailer_code).annotate(in_db=Exists(squery))

        return context

Models.py

from django.db import models
from django.utils import timezone


class Order(models.Model):

    ''' To simulate connection to main stock db '''

    retailer_code = models.CharField(max_length=4)
    retailer_name = models.CharField(max_length=100)
    supplier_code = models.CharField(max_length=4)
    supplier_name = models.CharField(max_length=100)
    order_reference = models.CharField(max_length=20)
    despatch_date = models.DateTimeField(default=timezone.now)

    def __str__(self):

        return f"< {self.order_reference}', {self.supplier_name}, {self.retailer_name} >"


# -------------------------------------------------------------------------------------

class Retailer(models.Model):

    retailer_code = models.CharField(max_length=4)
    retailer_name = models.CharField(max_length=100)
    suppliers = models.ManyToManyField('Supplier')
    slug = models.SlugField(unique=True, null=True)

    def get_supplier_values(self):

        return [(suppliers.supplier_code + ' - ' + suppliers.supplier_name) for suppliers in self.suppliers.all()]

    def save(self, *args, **kwargs):

        self.slug = self.slug or slugify(self.retailer_code)
        super().save(*args, **kwargs)

    def __str__(self):

        return f"< {self.retailer_code} - {self.retailer_name} >"


class Supplier(models.Model):

    supplier_code = models.CharField(max_length=4)
    supplier_name = models.CharField(max_length=100)

    def __str__(self):

        return f"< {self.supplier_code}, {self.supplier_name} >"

1 ответ

Если есть разница между False и None, вы не можете использовать Exists. Это строго логическая операция. Вам нужно будет использоватьSubquery который возвращает NullableBooleanFieldрезультат которого вычисляется с помощью When и Case

Другие вопросы по тегам