prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Uncaught 404s in record viewsets and pagination classes
  ## Description
  The record viewset, column viewset and paignation classes regularly call `Table.objects.get(id=table_pk)`, which throws a `mathesar.models.Table.DoesNotExist: Table matching query does not exist.` when an invalid table id is passed.
  
  To recreate, run `client.get(f'/api/v0/tables/3000/records/')`.
  
  
  ## Expected behavior
  We should ensure that the table exists before querying, or catch the `DoesNotExist` error after querying. We should also include tests for table 404s. 
  
  This is probably best done after  #488 is merged, as it includes a function to do exactly this.
  
  </issue>
  <code>
  [start of mathesar/api/pagination.py]
  1 from collections import OrderedDict
  2 
  3 from rest_framework.pagination import LimitOffsetPagination
  4 from rest_framework.response import Response
  5 
  6 
  7 class DefaultLimitOffsetPagination(LimitOffsetPagination):
  8     default_limit = 50
  9     max_limit = 500
  10 
  11     def get_paginated_response(self, data):
  12         return Response(OrderedDict([
  13             ('count', self.count),
  14             ('results', data)
  15         ]))
  16 
  17 
  18 class ColumnLimitOffsetPagination(DefaultLimitOffsetPagination):
  19 
  20     def paginate_queryset(self, queryset, request, table_id):
  21         self.limit = self.get_limit(request)
  22         if self.limit is None:
  23             self.limit = self.default_limit
  24         self.offset = self.get_offset(request)
  25         table = queryset.get(id=table_id)
  26         self.count = len(table.sa_columns)
  27         self.request = request
  28         return list(table.sa_columns)[self.offset:self.offset + self.limit]
  29 
  30 
  31 class TableLimitOffsetPagination(DefaultLimitOffsetPagination):
  32 
  33     def paginate_queryset(self, queryset, request, table_id,
  34                           filters=[], order_by=[]):
  35         self.limit = self.get_limit(request)
  36         if self.limit is None:
  37             self.limit = self.default_limit
  38         self.offset = self.get_offset(request)
  39         # TODO: Cache count value somewhere, since calculating it is expensive.
  40         table = queryset.get(id=table_id)
  41         self.count = table.sa_num_records(filters=filters)
  42         self.request = request
  43 
  44         return table.get_records(
  45             self.limit, self.offset, filters=filters, order_by=order_by,
  46         )
  47 
  48 
  49 class TableLimitOffsetGroupPagination(TableLimitOffsetPagination):
  50     def get_paginated_response(self, data):
  51         return Response(OrderedDict([
  52             ('count', self.count),
  53             ('group_count', self.group_count),
  54             ('results', data)
  55         ]))
  56 
  57     def paginate_queryset(self, queryset, request, table_id,
  58                           filters=[], order_by=[], group_count_by=[]):
  59         records = super().paginate_queryset(
  60             queryset, request, table_id, filters=filters, order_by=order_by
  61         )
  62 
  63         table = queryset.get(id=table_id)
  64         if group_count_by:
  65             group_count = table.get_group_counts(
  66                 group_count_by, self.limit, self.offset,
  67                 filters=filters, order_by=order_by
  68             )
  69             # Convert the tuple keys into strings so it can be converted to JSON
  70             group_count = [{"values": list(cols), "count": count}
  71                            for cols, count in group_count.items()]
  72             self.group_count = {
  73                 'group_count_by': group_count_by,
  74                 'results': group_count,
  75             }
  76         else:
  77             self.group_count = {
  78                 'group_count_by': None,
  79                 'results': None,
  80             }
  81 
  82         return records
  83
  [end of mathesar/api/pagination.py]
  [start of mathesar/api/utils.py]
  1 from rest_framework.exceptions import NotFound
  2 
  3 from mathesar.models import Table
  4 
  5 
  6 def get_table_or_404(pk):
  7     try:
  8         table = Table.objects.get(id=pk)
  9     except Table.DoesNotExist:
  10         raise NotFound
  11     return table
  12
  [end of mathesar/api/utils.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/mathesar/api/pagination.py b/mathesar/api/pagination.py
  --- a/mathesar/api/pagination.py
  +++ b/mathesar/api/pagination.py
  @@ -3,6 +3,8 @@
   from rest_framework.pagination import LimitOffsetPagination
   from rest_framework.response import Response
   
  +from mathesar.api.utils import get_table_or_404
  +
   
   class DefaultLimitOffsetPagination(LimitOffsetPagination):
       default_limit = 50
  @@ -22,7 +24,7 @@
           if self.limit is None:
               self.limit = self.default_limit
           self.offset = self.get_offset(request)
  -        table = queryset.get(id=table_id)
  +        table = get_table_or_404(pk=table_id)
           self.count = len(table.sa_columns)
           self.request = request
           return list(table.sa_columns)[self.offset:self.offset + self.limit]
  @@ -37,7 +39,7 @@
               self.limit = self.default_limit
           self.offset = self.get_offset(request)
           # TODO: Cache count value somewhere, since calculating it is expensive.
  -        table = queryset.get(id=table_id)
  +        table = get_table_or_404(pk=table_id)
           self.count = table.sa_num_records(filters=filters)
           self.request = request
   
  @@ -60,7 +62,7 @@
               queryset, request, table_id, filters=filters, order_by=order_by
           )
   
  -        table = queryset.get(id=table_id)
  +        table = get_table_or_404(pk=table_id)
           if group_count_by:
               group_count = table.get_group_counts(
                   group_count_by, self.limit, self.offset,
  diff --git a/mathesar/api/utils.py b/mathesar/api/utils.py
  --- a/mathesar/api/utils.py
  +++ b/mathesar/api/utils.py
  @@ -4,6 +4,13 @@
   
   
   def get_table_or_404(pk):
  +    """
  +    Get table if it exists, otherwise throws a DRF NotFound error.
  +    Args:
  +        pk: id of table
  +    Returns:
  +        table: return the table based on a specific id
  +    """
       try:
           table = Table.objects.get(id=pk)
       except Table.DoesNotExist:
  
verification_info: {"golden_diff": "diff --git a/mathesar/api/pagination.py b/mathesar/api/pagination.py\n--- a/mathesar/api/pagination.py\n+++ b/mathesar/api/pagination.py\n@@ -3,6 +3,8 @@\n from rest_framework.pagination import LimitOffsetPagination\n from rest_framework.response import Response\n \n+from mathesar.api.utils import get_table_or_404\n+\n \n class DefaultLimitOffsetPagination(LimitOffsetPagination):\n     default_limit = 50\n@@ -22,7 +24,7 @@\n         if self.limit is None:\n             self.limit = self.default_limit\n         self.offset = self.get_offset(request)\n-        table = queryset.get(id=table_id)\n+        table = get_table_or_404(pk=table_id)\n         self.count = len(table.sa_columns)\n         self.request = request\n         return list(table.sa_columns)[self.offset:self.offset + self.limit]\n@@ -37,7 +39,7 @@\n             self.limit = self.default_limit\n         self.offset = self.get_offset(request)\n         # TODO: Cache count value somewhere, since calculating it is expensive.\n-        table = queryset.get(id=table_id)\n+        table = get_table_or_404(pk=table_id)\n         self.count = table.sa_num_records(filters=filters)\n         self.request = request\n \n@@ -60,7 +62,7 @@\n             queryset, request, table_id, filters=filters, order_by=order_by\n         )\n \n-        table = queryset.get(id=table_id)\n+        table = get_table_or_404(pk=table_id)\n         if group_count_by:\n             group_count = table.get_group_counts(\n                 group_count_by, self.limit, self.offset,\ndiff --git a/mathesar/api/utils.py b/mathesar/api/utils.py\n--- a/mathesar/api/utils.py\n+++ b/mathesar/api/utils.py\n@@ -4,6 +4,13 @@\n \n \n def get_table_or_404(pk):\n+    \"\"\"\n+    Get table if it exists, otherwise throws a DRF NotFound error.\n+    Args:\n+        pk: id of table\n+    Returns:\n+        table: return the table based on a specific id\n+    \"\"\"\n     try:\n         table = Table.objects.get(id=pk)\n     except Table.DoesNotExist:\n", "issue": "Uncaught 404s in record viewsets and pagination classes\n## Description\r\nThe record viewset, column viewset and paignation classes regularly call `Table.objects.get(id=table_pk)`, which throws a `mathesar.models.Table.DoesNotExist: Table matching query does not exist.` when an invalid table id is passed.\r\n\r\nTo recreate, run `client.get(f'/api/v0/tables/3000/records/')`.\r\n\r\n\r\n## Expected behavior\r\nWe should ensure that the table exists before querying, or catch the `DoesNotExist` error after querying. We should also include tests for table 404s. \r\n\r\nThis is probably best done after  #488 is merged, as it includes a function to do exactly this.\n", "before_files": [{"content": "from collections import OrderedDict\n\nfrom rest_framework.pagination import LimitOffsetPagination\nfrom rest_framework.response import Response\n\n\nclass DefaultLimitOffsetPagination(LimitOffsetPagination):\n    default_limit = 50\n    max_limit = 500\n\n    def get_paginated_response(self, data):\n        return Response(OrderedDict([\n            ('count', self.count),\n            ('results', data)\n        ]))\n\n\nclass ColumnLimitOffsetPagination(DefaultLimitOffsetPagination):\n\n    def paginate_queryset(self, queryset, request, table_id):\n        self.limit = self.get_limit(request)\n        if self.limit is None:\n            self.limit = self.default_limit\n        self.offset = self.get_offset(request)\n        table = queryset.get(id=table_id)\n        self.count = len(table.sa_columns)\n        self.request = request\n        return list(table.sa_columns)[self.offset:self.offset + self.limit]\n\n\nclass TableLimitOffsetPagination(DefaultLimitOffsetPagination):\n\n    def paginate_queryset(self, queryset, request, table_id,\n                          filters=[], order_by=[]):\n        self.limit = self.get_limit(request)\n        if self.limit is None:\n            self.limit = self.default_limit\n        self.offset = self.get_offset(request)\n        # TODO: Cache count value somewhere, since calculating it is expensive.\n        table = queryset.get(id=table_id)\n        self.count = table.sa_num_records(filters=filters)\n        self.request = request\n\n        return table.get_records(\n            self.limit, self.offset, filters=filters, order_by=order_by,\n        )\n\n\nclass TableLimitOffsetGroupPagination(TableLimitOffsetPagination):\n    def get_paginated_response(self, data):\n        return Response(OrderedDict([\n            ('count', self.count),\n            ('group_count', self.group_count),\n            ('results', data)\n        ]))\n\n    def paginate_queryset(self, queryset, request, table_id,\n                          filters=[], order_by=[], group_count_by=[]):\n        records = super().paginate_queryset(\n            queryset, request, table_id, filters=filters, order_by=order_by\n        )\n\n        table = queryset.get(id=table_id)\n        if group_count_by:\n            group_count = table.get_group_counts(\n                group_count_by, self.limit, self.offset,\n                filters=filters, order_by=order_by\n            )\n            # Convert the tuple keys into strings so it can be converted to JSON\n            group_count = [{\"values\": list(cols), \"count\": count}\n                           for cols, count in group_count.items()]\n            self.group_count = {\n                'group_count_by': group_count_by,\n                'results': group_count,\n            }\n        else:\n            self.group_count = {\n                'group_count_by': None,\n                'results': None,\n            }\n\n        return records\n", "path": "mathesar/api/pagination.py"}, {"content": "from rest_framework.exceptions import NotFound\n\nfrom mathesar.models import Table\n\n\ndef get_table_or_404(pk):\n    try:\n        table = Table.objects.get(id=pk)\n    except Table.DoesNotExist:\n        raise NotFound\n    return table\n", "path": "mathesar/api/utils.py"}]}