Django: executing UPDATE query always returns rowcount 0

I'm new to programming and I'm not sure, whether the problem is in me or in the Django code. I call link method from my view and update field MatchId on Record model. Database is SQL Server 2017.

My view:

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)

For some reason matchedSuccessfully always returns zero. Relevant Django code:

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

I rewrote execute_sql as follows:

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

and now it works, but I'm unsure if there is a more elegant way to resolve this since now I have to ship this exact code everywhere. Source code at: https://github.com/django/django/blob/main/django/db/models/sql/compiler.py

I've faced the same issue and came to the same point in django's depths. In my case — the problem was in trigger configured for UPDATE. It should have return @@ROWCOUNT as a result, but in my case it didn't. Btw, the thing I did (due to restriction on editing triggers) — overrided save method in base model for such models to 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
Back to Top