Coverage for src/products/admin.py: 87%
84 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-08-04 12:59 +0300
« prev ^ index » next coverage.py v7.9.2, created at 2025-08-04 12:59 +0300
1from django.utils.html import format_html
2from django.utils.translation import gettext_lazy as _
3from django.contrib import admin
4from django.contrib.contenttypes.admin import GenericTabularInline
6from src.products.models import (
7 Earwear,
8 Fingerwear,
9 Neckwear,
10 Wristwear,
11 Collection,
12 Color,
13 Metal,
14 Stone,
15 Size,
16 Inventory,
17)
18from src.products.models.review import Review
21@admin.register(Collection)
22class CollectionAdmin(admin.ModelAdmin):
23 pass
26@admin.register(Color)
27class ColorAdmin(admin.ModelAdmin):
28 pass
31@admin.register(Metal)
32class MetalAdmin(admin.ModelAdmin):
33 pass
36@admin.register(Stone)
37class StoneAdmin(admin.ModelAdmin):
38 pass
41@admin.register(Size)
42class SizeAdmin(admin.ModelAdmin):
43 pass
46@admin.register(Inventory)
47class InventoryAdmin(admin.ModelAdmin):
48 pass
51class StoneListFilter(admin.SimpleListFilter):
52 title = _('Stone')
53 parameter_name = 'stone'
55 def lookups(self, request, model_admin):
56 return [(s.id, s.name) for s in Stone.objects.all()]
58 def queryset(self, request, queryset):
59 return (
60 queryset.filter(stone__id=self.value())
61 if self.value()
62 else queryset
63 )
66class ColorListFilter(admin.SimpleListFilter):
67 title = _('Color')
68 parameter_name = 'color'
70 def lookups(self, request, model_admin):
71 return [(c.id, c.name) for c in Color.objects.all()]
73 def queryset(self, request, queryset):
74 return (
75 queryset.filter(color__id=self.value())
76 if self.value()
77 else queryset
78 )
81class InventoryInline(GenericTabularInline):
82 model = Inventory
83 ct_field = "content_type"
84 ct_fk_field = "object_id"
85 min_num = 1
86 max_num = 3
87 validate_min = True
90class BaseProductAdmin(admin.ModelAdmin):
91 list_display = (
92 'first_picture',
93 'second_picture',
94 'collection',
95 'created_at',
96 )
98 list_filter = (StoneListFilter, ColorListFilter, 'collection', 'metal')
100 ordering = (
101 'created_at',
102 'collection',
103 'metal',
104 )
106 search_fields = (
107 'collection__name',
108 'metal__name',
109 'color__name',
110 'stone__name',
111 )
113 fieldsets = (
114 ('Images', {'fields': ('first_image', 'second_image')}),
115 (
116 'Material and Design',
117 {
118 'fields': (
119 'collection',
120 'metal',
121 'stone',
122 'color',
123 )
124 },
125 ),
126 )
128 def first_picture(self, obj):
129 return format_html(
130 '<img src="{}" width="100" height="100" style="object-fit: cover;" />',
131 obj.first_image,
132 )
134 def second_picture(self, obj):
135 return format_html(
136 '<img src="{}" width="100" height="100" style="object-fit: cover;" />',
137 obj.second_image,
138 )
141@admin.register(Earwear)
142class EarwearAdmin(BaseProductAdmin):
143 inlines = [InventoryInline]
146@admin.register(Neckwear)
147class NeckwearAdmin(BaseProductAdmin):
148 inlines = [InventoryInline]
151@admin.register(Wristwear)
152class WristwearAdmin(BaseProductAdmin):
153 inlines = [InventoryInline]
156@admin.register(Fingerwear)
157class FingerwearAdmin(BaseProductAdmin):
158 inlines = [InventoryInline]
161@admin.register(Review)
162class ReviewAdmin(admin.ModelAdmin):
163 list_display = [
164 '__str__',
165 'user',
166 'rating',
167 'approved',
168 'created_at',
169 'product_link',
170 ]
171 list_filter = [
172 'approved',
173 'rating',
174 'created_at',
175 ]
176 search_fields = [
177 'user__email',
178 'user__userprofile__first_name',
179 'user__userprofile__last_name',
180 'comment',
181 ]
182 list_editable = ['approved']
183 readonly_fields = [
184 'user',
185 'rating',
186 'comment',
187 'created_at',
188 'content_type',
189 'object_id',
190 'product',
191 ]
192 ordering = ['-created_at']
194 def product_link(self, obj):
195 if obj.product:
196 return format_html(
197 '<a href="/admin/products/{}/{}/change/">{}</a>',
198 obj.content_type.model,
199 obj.object_id,
200 str(obj.product),
201 )
202 return '-'
204 product_link.short_description = 'Product'
206 def has_add_permission(self, request):
207 return False
209 def has_delete_permission(self, request, obj=None):
210 return request.user.is_superuser