prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Админка: по-умолчанию показывать только включенные промокоды
  У нас накопилась огромная гора промокодов, и теперь при первом входе в админку сложно ориентироваться. Нужно сделать, чтобы по-умолчанию в админке показывались только включенные промокоды.
  
  </issue>
  <code>
  [start of src/app/admin/filters.py]
  1 from django.contrib import admin
  2 from django.utils.translation import gettext_lazy as _
  3 
  4 
  5 class BooleanFilter(admin.SimpleListFilter):
  6     """
  7     Abstract base class for simple boolean filter in admin. You should define only
  8     `title`, unique `parameter_name` and two methods: `t` and `f`, returning a queryset
  9     when filter is set to True and False respectively:
  10         class HasClassesFilter(BooleanFilter):
  11             title = _('Has classes')
  12             parameter_name = 'has_classes'
  13             def t(self, request, queryset):
  14                 return queryset.filter(classes__isnull=False).distinct('pk')
  15             def n(self, request, queryset):
  16                 return queryset.filter(classes__isnull=True)
  17     """
  18     def lookups(self, request, model_admin):
  19         return (
  20             ('t', _('Yes')),
  21             ('f', _('No')),
  22         )
  23 
  24     def queryset(self, request, queryset):
  25         if not self.value():
  26             return queryset
  27         else:
  28             if self.value() == 't':
  29                 return self.t(request, queryset)
  30             else:
  31                 return self.f(request, queryset)
  32
  [end of src/app/admin/filters.py]
  [start of src/orders/admin/promocodes/admin.py]
  1 from django.urls import reverse
  2 from django.utils.safestring import mark_safe
  3 from django.utils.translation import gettext_lazy as _
  4 
  5 from app.admin import ModelAdmin, admin
  6 from orders.admin.promocodes import actions
  7 from orders.models import PromoCode
  8 
  9 
  10 @admin.register(PromoCode)
  11 class PromoCodeAdmin(ModelAdmin):
  12     list_display = [
  13         'id',
  14         'name',
  15         'discount_percent',
  16         'discount_value',
  17         'order_count',
  18         'comment',
  19         'active',
  20     ]
  21 
  22     list_editable = [
  23         'active',
  24     ]
  25 
  26     list_filter = [
  27         'active',
  28     ]
  29 
  30     actions = [actions.deactivate]
  31 
  32     def get_queryset(self, request):
  33         return super().get_queryset(request) \
  34             .with_order_count()
  35 
  36     @mark_safe
  37     @admin.display(description=_('Order count'), ordering='order_count')
  38     def order_count(self, obj=None):
  39         if hasattr(obj, 'order_count') and obj.order_count:
  40             orders_url = reverse('admin:orders_order_changelist')
  41             return f'<a href="{orders_url}?is_paid=t&promocode_id={obj.id}">{obj.order_count}</a>'
  42 
  43         return '—'
  44
  [end of src/orders/admin/promocodes/admin.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/src/app/admin/filters.py b/src/app/admin/filters.py
  --- a/src/app/admin/filters.py
  +++ b/src/app/admin/filters.py
  @@ -12,7 +12,7 @@
               parameter_name = 'has_classes'
               def t(self, request, queryset):
                   return queryset.filter(classes__isnull=False).distinct('pk')
  -            def n(self, request, queryset):
  +            def f(self, request, queryset):
                   return queryset.filter(classes__isnull=True)
       """
       def lookups(self, request, model_admin):
  @@ -24,8 +24,22 @@
       def queryset(self, request, queryset):
           if not self.value():
               return queryset
  -        else:
  -            if self.value() == 't':
  -                return self.t(request, queryset)
  -            else:
  -                return self.f(request, queryset)
  +
  +        if self.value() == 't':
  +            return self.t(request, queryset)
  +
  +        return self.f(request, queryset)
  +
  +
  +class DefaultTrueBooleanFilter(BooleanFilter):
  +    def queryset(self, request, queryset):
  +        if not self.value() or self.value() == 't':
  +            return self.t(request, queryset)
  +
  +        return self.f(request, queryset)
  +
  +
  +__all__ = [
  +    'BooleanFilter',
  +    'DefaultTrueBooleanFilter',
  +]
  diff --git a/src/orders/admin/promocodes/admin.py b/src/orders/admin/promocodes/admin.py
  --- a/src/orders/admin/promocodes/admin.py
  +++ b/src/orders/admin/promocodes/admin.py
  @@ -1,31 +1,45 @@
  -from django.urls import reverse
  -from django.utils.safestring import mark_safe
   from django.utils.translation import gettext_lazy as _
   
   from app.admin import ModelAdmin, admin
  +from app.admin.filters import DefaultTrueBooleanFilter
   from orders.admin.promocodes import actions
   from orders.models import PromoCode
   
   
  +class PromodeActiveFilter(DefaultTrueBooleanFilter):
  +    title = _('Active')
  +    parameter_name = 'is_active'
  +
  +    def t(self, request, queryset):
  +        return queryset.filter(active=True)
  +
  +    def f(self, request, queryset):
  +        return queryset.filter(active=False)
  +
  +
   @admin.register(PromoCode)
   class PromoCodeAdmin(ModelAdmin):
  -    list_display = [
  +    list_display = (
           'id',
           'name',
  -        'discount_percent',
  -        'discount_value',
  +        'discount',
           'order_count',
           'comment',
           'active',
  -    ]
  +    )
   
       list_editable = [
           'active',
       ]
   
  -    list_filter = [
  -        'active',
  -    ]
  +    list_filter = (
  +        PromodeActiveFilter,
  +    )
  +
  +    list_display_links = (
  +        'id',
  +        'name',
  +    )
   
       actions = [actions.deactivate]
   
  @@ -33,11 +47,19 @@
           return super().get_queryset(request) \
               .with_order_count()
   
  -    @mark_safe
       @admin.display(description=_('Order count'), ordering='order_count')
  -    def order_count(self, obj=None):
  +    def order_count(self, obj: PromoCode | None = None) -> str:
           if hasattr(obj, 'order_count') and obj.order_count:
  -            orders_url = reverse('admin:orders_order_changelist')
  -            return f'<a href="{orders_url}?is_paid=t&promocode_id={obj.id}">{obj.order_count}</a>'
  +            return str(obj.order_count)
   
           return '—'
  +
  +    @admin.display(description=_('Discount'), ordering='discount_percent')
  +    def discount(self, obj: PromoCode | None = None) -> str:
  +        if not obj:
  +            return '—'
  +
  +        if obj.discount_value is not None:
  +            return f'{obj.discount_value} ₽'
  +
  +        return f'{obj.discount_percent} %'
  
verification_info: {"golden_diff": "diff --git a/src/app/admin/filters.py b/src/app/admin/filters.py\n--- a/src/app/admin/filters.py\n+++ b/src/app/admin/filters.py\n@@ -12,7 +12,7 @@\n             parameter_name = 'has_classes'\n             def t(self, request, queryset):\n                 return queryset.filter(classes__isnull=False).distinct('pk')\n-            def n(self, request, queryset):\n+            def f(self, request, queryset):\n                 return queryset.filter(classes__isnull=True)\n     \"\"\"\n     def lookups(self, request, model_admin):\n@@ -24,8 +24,22 @@\n     def queryset(self, request, queryset):\n         if not self.value():\n             return queryset\n-        else:\n-            if self.value() == 't':\n-                return self.t(request, queryset)\n-            else:\n-                return self.f(request, queryset)\n+\n+        if self.value() == 't':\n+            return self.t(request, queryset)\n+\n+        return self.f(request, queryset)\n+\n+\n+class DefaultTrueBooleanFilter(BooleanFilter):\n+    def queryset(self, request, queryset):\n+        if not self.value() or self.value() == 't':\n+            return self.t(request, queryset)\n+\n+        return self.f(request, queryset)\n+\n+\n+__all__ = [\n+    'BooleanFilter',\n+    'DefaultTrueBooleanFilter',\n+]\ndiff --git a/src/orders/admin/promocodes/admin.py b/src/orders/admin/promocodes/admin.py\n--- a/src/orders/admin/promocodes/admin.py\n+++ b/src/orders/admin/promocodes/admin.py\n@@ -1,31 +1,45 @@\n-from django.urls import reverse\n-from django.utils.safestring import mark_safe\n from django.utils.translation import gettext_lazy as _\n \n from app.admin import ModelAdmin, admin\n+from app.admin.filters import DefaultTrueBooleanFilter\n from orders.admin.promocodes import actions\n from orders.models import PromoCode\n \n \n+class PromodeActiveFilter(DefaultTrueBooleanFilter):\n+    title = _('Active')\n+    parameter_name = 'is_active'\n+\n+    def t(self, request, queryset):\n+        return queryset.filter(active=True)\n+\n+    def f(self, request, queryset):\n+        return queryset.filter(active=False)\n+\n+\n @admin.register(PromoCode)\n class PromoCodeAdmin(ModelAdmin):\n-    list_display = [\n+    list_display = (\n         'id',\n         'name',\n-        'discount_percent',\n-        'discount_value',\n+        'discount',\n         'order_count',\n         'comment',\n         'active',\n-    ]\n+    )\n \n     list_editable = [\n         'active',\n     ]\n \n-    list_filter = [\n-        'active',\n-    ]\n+    list_filter = (\n+        PromodeActiveFilter,\n+    )\n+\n+    list_display_links = (\n+        'id',\n+        'name',\n+    )\n \n     actions = [actions.deactivate]\n \n@@ -33,11 +47,19 @@\n         return super().get_queryset(request) \\\n             .with_order_count()\n \n-    @mark_safe\n     @admin.display(description=_('Order count'), ordering='order_count')\n-    def order_count(self, obj=None):\n+    def order_count(self, obj: PromoCode | None = None) -> str:\n         if hasattr(obj, 'order_count') and obj.order_count:\n-            orders_url = reverse('admin:orders_order_changelist')\n-            return f'<a href=\"{orders_url}?is_paid=t&promocode_id={obj.id}\">{obj.order_count}</a>'\n+            return str(obj.order_count)\n \n         return '\u2014'\n+\n+    @admin.display(description=_('Discount'), ordering='discount_percent')\n+    def discount(self, obj: PromoCode | None = None) -> str:\n+        if not obj:\n+            return '\u2014'\n+\n+        if obj.discount_value is not None:\n+            return f'{obj.discount_value} \u20bd'\n+\n+        return f'{obj.discount_percent} %'\n", "issue": "\u0410\u0434\u043c\u0438\u043d\u043a\u0430: \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u043c\u043e\u043a\u043e\u0434\u044b\n\u0423 \u043d\u0430\u0441 \u043d\u0430\u043a\u043e\u043f\u0438\u043b\u0430\u0441\u044c \u043e\u0433\u0440\u043e\u043c\u043d\u0430\u044f \u0433\u043e\u0440\u0430 \u043f\u0440\u043e\u043c\u043e\u043a\u043e\u0434\u043e\u0432, \u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u0432\u0445\u043e\u0434\u0435 \u0432 \u0430\u0434\u043c\u0438\u043d\u043a\u0443 \u0441\u043b\u043e\u0436\u043d\u043e \u043e\u0440\u0438\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f. \u041d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043f\u043e-\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432 \u0430\u0434\u043c\u0438\u043d\u043a\u0435 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0438\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u043c\u043e\u043a\u043e\u0434\u044b.\n", "before_files": [{"content": "from django.contrib import admin\nfrom django.utils.translation import gettext_lazy as _\n\n\nclass BooleanFilter(admin.SimpleListFilter):\n    \"\"\"\n    Abstract base class for simple boolean filter in admin. You should define only\n    `title`, unique `parameter_name` and two methods: `t` and `f`, returning a queryset\n    when filter is set to True and False respectively:\n        class HasClassesFilter(BooleanFilter):\n            title = _('Has classes')\n            parameter_name = 'has_classes'\n            def t(self, request, queryset):\n                return queryset.filter(classes__isnull=False).distinct('pk')\n            def n(self, request, queryset):\n                return queryset.filter(classes__isnull=True)\n    \"\"\"\n    def lookups(self, request, model_admin):\n        return (\n            ('t', _('Yes')),\n            ('f', _('No')),\n        )\n\n    def queryset(self, request, queryset):\n        if not self.value():\n            return queryset\n        else:\n            if self.value() == 't':\n                return self.t(request, queryset)\n            else:\n                return self.f(request, queryset)\n", "path": "src/app/admin/filters.py"}, {"content": "from django.urls import reverse\nfrom django.utils.safestring import mark_safe\nfrom django.utils.translation import gettext_lazy as _\n\nfrom app.admin import ModelAdmin, admin\nfrom orders.admin.promocodes import actions\nfrom orders.models import PromoCode\n\n\n@admin.register(PromoCode)\nclass PromoCodeAdmin(ModelAdmin):\n    list_display = [\n        'id',\n        'name',\n        'discount_percent',\n        'discount_value',\n        'order_count',\n        'comment',\n        'active',\n    ]\n\n    list_editable = [\n        'active',\n    ]\n\n    list_filter = [\n        'active',\n    ]\n\n    actions = [actions.deactivate]\n\n    def get_queryset(self, request):\n        return super().get_queryset(request) \\\n            .with_order_count()\n\n    @mark_safe\n    @admin.display(description=_('Order count'), ordering='order_count')\n    def order_count(self, obj=None):\n        if hasattr(obj, 'order_count') and obj.order_count:\n            orders_url = reverse('admin:orders_order_changelist')\n            return f'<a href=\"{orders_url}?is_paid=t&promocode_id={obj.id}\">{obj.order_count}</a>'\n\n        return '\u2014'\n", "path": "src/orders/admin/promocodes/admin.py"}]}