Django: выполнение запроса UPDATE всегда возвращает rowcount 0

Я новичок в программировании и не уверен, во мне ли проблема или в коде Django. Я вызываю метод link из представления и обновляю поле MatchId на модели Record. База данных - SQL Server 2017.

Мое мнение:

class RecordViewSet(viewsets.ModelViewSet):
    """
    API for everything that has to do with Records.
    Additionally we provide an extra `link` action.
    """

    queryset = Record.objects.all().order_by("Id")
    serializer_class = RecordSerializer
    permission_classes = [permissions.IsAuthenticated]

    @action(methods=["post"], detail=False)
    def link(self, request, *args, **kwargs):
        idToMatch = request.POST.getlist("Id")
        recordsToMatch = Record.objects.filter(Id__in=idToMatch)
        lastMatchId = Record.objects.latest("MatchId").MatchId
        matchedSuccesfully = recordsToMatch.update(MatchId=lastMatchId + 1)
        if matchedSuccesfully > 1:
            return Response(data=matchedSuccesfully, status=status.HTTP_200_OK)
        else:
            return Response(data=matchedSuccesfully, status=status.HTTP_404_NOT_FOUND)

По какой-то причине matchedSuccessfully всегда возвращает ноль. Соответствующий код Django:

def execute_sql(self, result_type):
    """
    Execute the specified update. Return the number of rows affected by
    the primary update query. The "primary update query" is the first
    non-empty query that is executed. Row counts for any subsequent,
    related queries are not available.
    """
    cursor = super().execute_sql(result_type)
    try:
        rows = cursor.rowcount if cursor else 0
        is_empty = cursor is None
    finally:
        if cursor:
            cursor.close()
    for query in self.query.get_related_updates():
        aux_rows = query.get_compiler(self.using).execute_sql(result_type)
        if is_empty and aux_rows:
            rows = aux_rows
            is_empty = False
    return rows

Я переписал execute_sql следующим образом:

def execute_sql(self, result_type):
    """
    Execute the specified update. Return the number of rows affected by
    the primary update query. The "primary update query" is the first
    non-empty query that is executed. Row counts for any subsequent,
    related queries are not available.
    """
    cursor = super().execute_sql(result_type)
    try:
        if cursor:
            cursor.execute("select @@rowcount")
            rows = cursor.fetchall()[0][0]
        else:
            rows = 0
        is_empty = cursor is None
    finally:
        if cursor:
            cursor.close()
    for query in self.query.get_related_updates():
        aux_rows = query.get_compiler(self.using).execute_sql(result_type)
        if is_empty and aux_rows:
            rows = aux_rows
            is_empty = False
    return rows

и теперь он работает, но я не уверен, есть ли более элегантный способ решить эту проблему, так как теперь мне придется отправлять этот код повсюду. Исходный код на: https://github.com/django/django/blob/main/django/db/models/sql/compiler.py

Я столкнулся с той же проблемой и пришел к той же точке в глубинах django. В моем случае - проблема была в триггере, настроенном for UPDATE. Он должен был возвращать @@ROWCOUNT в качестве результата, но в моем случае этого не произошло. Кстати, что я сделал (из-за ограничения на редактирование триггеров) - переопределил метод save в базовой модели для таких моделей на force_update=True:

class BaseModel(models.Model):
    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        if self._state.adding:
            super().save(force_insert=force_insert, force_update=force_update, using=using, update_fields=update_fields)
        else:
            try:
                super().save(force_insert=force_insert, force_update=True, using=using, update_fields=update_fields)
            except DatabaseError as e:
                if str(e) == 'Forced update did not affect any rows.':
                    pass
                else:
                    raise e

    class Meta:
        managed = False
        abstract = True
Вернуться на верх