Как отфильтровать повторяющиеся строки из дочерней модели перед отображением в Django ListView - PullRequest
0 голосов
/ 22 февраля 2020

Я использую две связанные модели в моем приложении Django. Объекты, созданные таким образом в моделях, отображаются с использованием класса listview. В дочерней модели я могу создать несколько строк на основе определенной контрольной даты. Когда я пытаюсь отобразить значения из обеих моделей (связанных с полем FK), отображаются все дочерние объекты для соответствующих полей FK (там, где имеется более одной записи).

Есть ли способ, которым Я могу использовать select distinct для фильтрации дублирующихся строк. Я попытался:

myModel.objects.distinct().order_by('id')

, но все еще получаю все дочерние строки для родителя id.

В моем шаблоне я использую:

{% for obj in object_list %}
    {{ obj.<field1> }}     <!-- field1: Parent model field -->
    {% for item in obj.<child_model>_set.all %}
        {{ item.<field2> }}     <!-- field2: Child model field -->
    {% endfor %}
{% endfor %}

My вопрос:

Как отфильтровать повторяющиеся строки перед отображением данных?

Бэкэнд sqlite3 для Django 2.0.6 / Python 3,6

Редактировать

Вот как генерируется текущий список:

enter image description here

Первый столбец pk родительской записи модели, а следующий столбец - для дочерних записей ' pk .

Что я пытается получить:

Вариант 1: Получить только последнюю (по дате) запись для комбинации родитель / ребенок по c числам (то есть для номера родительской записи 32 , должна отображаться только комбинация 32 | 156 , а также со значениями для дочерних записей 149 и 148 не должно отображаться).

ИЛИ * 10 59 *

Вариант 2: Получить всю комбинацию записей, сгруппированных по полю ParentModel pk и полю ChildModel pk, которые будут показаны отдельно в последовательных строках (как вы можете видеть, несколько значений для родительской записи (где бы она ни существовала) отображается в той же строке , последовательные столбцы ).

PS. Я сожалею, что дела здесь становятся довольно плотными.

Edit 2

Это представление класса, которое я использую для отображения данных:

class myRateListView(ListView):
    template_name = "rate_list.html"
    context_object_name = 'ratelists'
    model = ParentModel

    def get_context_data(self, **kwargs):
        context = super(myRateListView, self).get_context_data(**kwargs)
        context.update({
            'rate_item_list': ChildModel.objects.order_by('field3'),

        })
        return context

    def get_queryset(self):
       return ParentModel.objects.values('field1', 'childmodel__field2').distinct()

Здесь я получаю ошибку :

Невозможно разрешить ключевое слово childmodel в поле. Варианты выбора ....

Я думаю, что мой классный вид неверен ??

Редактировать 3

Модели и детали просмотра:

модели .py

class TptRateDoc(models.Model):
    tpt_rate_doc_number = models.IntegerField(null=True, blank=True.....)
    loc_from = models.ForeignKey(Location, related_name='locn_from', on_delete=.......)
    loc_to = models.ForeignKey(Location, related_name='locn_to', on_delete=.......)
    create_date = models.DateField(default=timezone.now,...)

class TptRateItems(models.Model):
    tpt_doc_header = models.ForeignKey(TptRateDoc, on_delete=...)
    tpt_rate_item_num = models.CharField(max_length=3, default=10,...)
    tpt_rate_valid_from_date = models.DateField(null=True, verbose_name='From date')
    tpt_rate_valid_to_date = models.DateField(null=True, verbose_name='To date')
    tpt_rate = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True,...)

views.py

class TptRateListView(ListView):
    template_name = "tpt_rate_list.html"
    context_object_name = 'tptrates'
    model = TptRateDoc

    def get_context_data(self, **kwargs):
        context = super(TptRateListView, self).get_context_data(**kwargs)
        context.update({
            'tpt_rate_item_list': TptRateItems.objects.order_by('tpt_rate_valid_to_date'),  # .distinct()
        })
        return context

    def get_queryset(self):
#        return TptRateDoc.objects.order_by('loc_from')
        return TptRateDoc.objects.values('tpt_rate_doc_number', 'tptrateitems__tpt_rate_item_num').distinct()

Примечание: Закомментированные части - это то, что я пробовал ранее.

Ответы [ 2 ]

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

Вы не указали, когда считаете объекты «отличными». Если вы делаете что-то вроде

queryset = MyModel.objects.distinct()

, ваш набор запросов будет содержать все экземпляры MyModel. Почему? Потому что каждый экземпляр будет иметь различный id (или pk), даже если все остальные поля идентичны. Таким образом, чтобы distinct() работал, вам нужно указать поля для рассмотрения, т.е. вам нужно использовать values(). Поэтому, чтобы получить набор запросов, содержащий различные значения field2 в вашей ChildModel, вам нужно сделать что-то вроде

queryset = ChildModel.objects.values('field2').distinct()

Так что, если я вас правильно понимаю, вы хотите отобразить все значения "field1" и связанные с ними " field2 "values ​​где значения" field2 "должны быть уникальными. Я бы рекомендовал двухэтапный подход.

Сначала создайте набор запросов, содержащий различные комбинации field1 и field2, например:

queryset = ParentModel.objects.values('field1', 'childmodel__field2').distinct()

, а затем передайте этот набор запросов вашему шаблону.

return render(request, 'parent_child.html', {'objects': queryset})

Затем для иерархического рендеринга вы можете использовать шаблонный тег {% regroup%}, как описано в документах :

{% regroup objects by field1 as obj_list %}

<ul>
    {% for obj in obj_list %}
    <li>
        {{ obj.grouper }}
        <ul>
            {% for child in obj.list %}
            <li>
                {{ child.childmodel__field2 }}
            </li>
            {% endfor %}
        </ul>
    </li>
    {% endfor %}
</ul>

Поскольку ОП не опубликовал свои модели, это модели, использованные для этого ответа

class ParentModel(models.Model):

    field1 = models.CharField(max_length=100)

class ChildModel(models.Model):

    parentmodel = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
    field2 = models.CharField(max_length=100)
    field3 = models.IntegerField()
0 голосов
/ 22 февраля 2020

Вы пытались перехватить возвращенный набор запросов отдельного фильтра в новый набор запросов? Я имею в виду так: (* в соответствии с документами, отличные придут после order_by ())

queryset = myModel.objects.order_by('id').distinct()

и затем передадут этот обновленный набор запросов в шаблон.

return render(request, "html_file.html", { "objects": queryset})

Только PostgreSQL Вы можете передать позиционные аргументы (* fields), чтобы указать имена полей, к которым должен применяться DISTINCT. Это переводит в запрос SELECT DISTINCT ON SQL. Вот в чем разница. Для обычного вызова Different () база данных сравнивает каждое поле в каждой строке, определяя, какие строки различны. Для вызова Different () с указанными именами полей база данных будет сравнивать только указанные имена полей.

...