Django: Как мне создать вторичное поле ID, которое группируется (ранжируется) по заданному внешнему ключу?

Вывод может выглядеть, например, так:

id secondary_id fk
1 1 1
2 2 1
3 3 1
4 1 2
5 2 2

Для контекста:

(см. модели ниже)

У меня есть структура комиссионных, которая будет иметь скобки в зависимости от того, сколько пользователь зарабатывает в месяц. В идеале мне нужно знать в моей модели комиссионных скобок индекс скобок для данной структуры.

Вот мои модели.

class CommissionStructure(APIBaseModel):
    advisor = models.ManyToManyField(AdviserDetail)
    name = models.CharField(max_length=20, blank=True, null=True, default='default')
    company = models.ForeignKey(Company, on_delete=models.CASCADE)
    start_dt = models.DateTimeField(auto_now_add=True)
    end_dt = models.DateTimeField(default=timezone.datetime.max)

    objects = CommissionStructureManager()



class CommissionBracket(APIBaseModel):
    <secondary_id ???>
    commission_structure = models.ForeignKey(CommissionStructure, on_delete=models.CASCADE, related_name="brackets")
    lower_bound = models.DecimalField(decimal_places=2, default=0.00, max_digits=20, null=True, blank=True)
    upper_bound = models.DecimalField(decimal_places=2, default=0.00, max_digits=20, null=True, blank=True)

Обратите внимание, я могу не хранить его в моей модели, если я могу добавить аннотацию к агрегатному набору, но я предпочитаю следовать DRY.

Спасибо

Я нашел способ аннотировать queryset, но ради интереса мой первоначальный вопрос все еще остается: как мне добавить еще одно поле, разделенное по внешнему ключу?

brackets = CommissionBracket.objects.select_related("commission_structure")\
            .prefetch_related(
            'commission_structure__advisor',
            'commission_structure__start_dt__gte',
            'commission_structure__end_dt__lte',
            'commission_structure__company',
            'bracket_values'
            ).filter(
                commission_structure__advisor=advisor,
                commission_structure__start_dt__lte=date,
                commission_structure__end_dt__gte=date,
                commission_structure__company=advisor.user.company,
            ).annotate(index=Window(
                    expression=Count('id'),
                    partition_by="commission_structure",
                    order_by=F("lower_bound").asc()))

Моим предложением будет выполнять пользовательский SQL напрямую. Вы можете добавить вторичный идентификатор как целочисленное поле в CommissionBracket. Затем вы можете реализовать следующее:

from django.db import connection

def sample_view(request):
   ...

   with connection.cursor() as cursor:
      cursor.execute('''
         INSERT INTO appname_commissionbracket (
            secondary_id, 
            commission_structure_id
         )
         SELECT CASE 
            WHEN MAX(secondary_id)
               THEN MAX(secondary_id) + 1
               ELSE 1
            END AS new_secid, %s
         FROM appname_commissionbracket 
         WHERE commission_structure_id = %s''',
         [1, 1] # Sample foreign key value
      )

   return render(...)

Здесь мы используем INSERT INTO SELECT, поскольку мы берем secondary_id новую запись из той же таблицы. Мы также добавляем CASE, чтобы иметь запасное значение, если не будет возвращено ни одной записи. Если вам нужно заполнить другие колонки во время создания, вы можете просто включить их так:

INSERT INTO (secondary_id, commission_structure_id, lower_bound, upper_bound)
SELECT CASE ... END AS new_secid, <fk_value>, <lower_bound_value>, <upper_bound_value>
Вернуться на верх