Django Exists () / ~ Exists () возвращает, если нет соответствующих данных? - PullRequest
0 голосов
/ 13 февраля 2020

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

В соответствии с ответом Шиллингта ниже я переключился на использование 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 ниже с запросом / подзапросом, который проверяет, существует ли код поставщика в экземплярах второй модели, настроенной для представления заказов на покупку, полученных в базе данных реальных запасов.

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

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

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

Например, ниже показано вывод шаблона; 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))

Я также пытался сделать это в шаблон, использующий «нет», «нет» или «ложно», но, похоже, не может получить нужный мне результат

В конечном итоге предполагаемый результат представляет собой таблицу, в которой перечислены все ожидаемые поставщики в конкретном розничном магазине с какой-то тип «Да» или «Нет» рядом с ними в зависимости от того, существует ли порядок среди экземпляров Ордена. (Шаблон 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 %}

DetailView:

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

Модели. 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 Ответ

0 голосов
/ 13 февраля 2020

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

...