(ROOT / “shop” / “admin.py”).write_text(”’ de django.contrib import admin, mensajes de django.contrib.auth.admin import (UserAdmin como DjangoUserAdmin, GroupAdmin como DjangoGroupAdmin) de django.contrib.auth.models import Usuario, Grupo de django.shortcuts import redireccionamiento de django.utils.html import format_html de django.utils.translation importar gettext_lazy como _ de unfold.admin importar ModelAdmin, TabularInline de unfold.contrib.filters.admin importar (ChoicesDropdownFilter, RangeNumericFilter, RangeDateFilter, MultipleChoicesDropdownFilter,) de unfold.decorators importar visualización, acción de .models importar categoría, cliente, producto, pedido, artículo de pedido admin.site.unregister(Usuario); admin.site.unregister(Grupo) @admin.register(Usuario) clase UserAdmin(DjangoUserAdmin, ModelAdmin): pase @admin.register(Grupo) clase GroupAdmin(DjangoGroupAdmin, ModelAdmin): pase @admin.register(Categoría) clase CategoryAdmin(ModelAdmin): list_display = (“nombre”, “padre”, “show_active”, “created_at”) list_filter = ((“is_active”, ChoicesDropdownFilter),) search_fields = (“name”, “slug”) prepopulated_fields = {“slug”: (“name”,)} list_filter_submit = Verdadero campos_comprimidos = Verdadero @display(descripción=_(“Activo”), boolean=True) def show_active(self, obj): return obj.is_active @admin.register(Cliente) clase CustomerAdmin(ModelAdmin): list_display = (“name”,”email”,”show_tier”,”lifetime_value”,”joined”) list_filter = ( (“tier”, MultipleChoicesDropdownFilter), (“lifetime_value”, RangeNumericFilter), (“joined”, RangeDateFilter), ) search_fields = (“name”,”email”) list_filter_submit = True warn_unsaved_form = True list_per_page = 25 @display(description=_(“Nivel”), label={ “bronze”:”warning”,”silver”:”info”,”gold”:”success”,”platinum”:”primary”}) def show_tier(self, obj): return obj.get_tier_display(), obj.tier class OrderItemInline(TabularInline): modelo = OrderItem extra = 0 campos = (“producto”, “cantidad”, “precio_unitario”, “posición”) campo_pedido = “posición” tab = True @admin.register(Pedido) clase OrderAdmin(ModelAdmin): list_display = (“number”,”customer_link”,”show_status”,”total”,”created_at”) list_filter = ( (“status”, ChoicesDropdownFilter), (“total”, RangeNumericFilter), (“created_at”, RangeDateFilter), ) search_fields = (“número”,”nombre_cliente”,”correo_correo_cliente”) readonly_fields = (“created_at”,) autocomplete_fields = (“cliente”,) inlines = [OrderItemInline]
list_filter_submit = Conjuntos de campos verdaderos = ( (_(“Pedido”), {“clases”:[“tab”]”campos”:(“número”,”cliente”,”estado”,”total”)}), (_(“Notas”), {“clases”:[“tab”]”campos”:(“notas”,”created_at”)}), ) lista_acciones = [“mark_paid_bulk”]
fila_acciones = [“mark_paid_row”]
detalles_acciones = [“duplicate_order”]
action_submit_line = [“save_and_ship”]
@display(descripción=_(“Estado”), etiqueta={ “pendiente”:”advertencia”,”pagado”:”info”,”enviado”:”primario”, “entregado”:”éxito”,”cancelado”:”peligro”}) def show_status(self, obj): regresar obj.get_status_display(), obj.status @display(descripción=_(“Cliente”)) def enlace_cliente(self, obj): regresar format_html(\'{}\’, obj.customer_id, obj.customer.name) @action(description=_(“Marcar pendiente → PAGADO (todos)”), icon=”pagos”) def mark_paid_bulk(self, request, queryset=Ninguno): n = Order.objects.filter(status=”pending”).update(status=”paid”) self.message_user(solicitud, f”Marcado {n} pedidos como pagados.”, nivel=messages.SUCCESS) @action(description=_(“Marcar como pagado”), icon=”pagos”, url_path=”mark-paid-row”) def mark_paid_row(self, request, object_id): Order.objects.filter(pk=object_id).update(status=”paid”) self.message_user(request, “Pedido marcado como pagado.”, nivel=messages.SUCCESS) return redirección(request.META.get(“HTTP_REFERER”,”/admin/”)) @action(description=_(“Duplicate”), icon=”content_copy”, url_path=”duplicate”) def duplicado_order(self, request, object_id): o = Order.objects.get(pk=object_id) o.pk = Ninguno; o.número = o.número + “-COPIAR”; o.status = “pendiente”; o.save() self.message_user(solicitud, “Pedido duplicado.”, nivel=messages.SUCCESS) return redirección(f”/admin/shop/order/{o.pk}/change/”) @action(description=_(“Guardar y enviar”)) def save_and_ship(self, request, obj): obj.status = “enviado”; obj.save() self.message_user(solicitud, f”Orden {obj.number} enviado.”, nivel=messages.SUCCESS) @admin.register(Producto) clase ProductAdmin(ModelAdmin): list_display = (“name”,”sku”,”category”,”show_status”, “price_display”,”stock_badge”,”featured”) list_editable = (“destacado”,) list_filter = ( (“status”, ChoicesDropdownFilter), (“categoría”, admin.RelatedFieldListFilter), (“precio”, RangeNumericFilter), (“destacado”, ChoicesDropdownFilter), ) search_fields = (“nombre”, “sku”) autocomplete_fields = (“categoría”,) list_filter_submit = Verdadero list_per_page = 20 save_on_top = Conjuntos de campos verdaderos = ( (_(“Conceptos básicos”), {“clases”:[“tab”]”campos”:(“nombre”,”sku”,”categoría”,”estado”,”destacado”)}), (_(“Precios”), {“clases”:[“tab”]”campos”:(“precio”,”tiene_descuento”,”descuento_porcentaje”,”stock”)}), (_(“Contenido”), {“clases”:[“tab”]”fields”:(“description”,)}), ) conditional_fields = {“discount_percent”: “has_discount == true”} @display(description=_(“Status”), label={ “draft”:”info”,”active”:”success”,”archived”:”warning”}) def show_status(self, obj): return obj.get_status_display(), obj.status @display(descripción=_(“Precio”)) def price_display(self, obj): si obj.has_discount y obj.discount_percent: devuelve format_html( \’${} \’ \’${}\’, obj.price, obj.final_price) return f”${obj.price}” @display(description=_(“Stock”), ordering=”stock”, label={“out”:”peligro”,”low”:”warning”,”ok”:”success”}) def stock_badge(self, obj): if obj.stock == 0: return “Agotado”, “out” if obj.stock < 10: return f"Bajo ({obj.stock})", "bajo" return f"{obj.stock} en stock", "ok" ''') (ROOT / "templates" / "admin" / "index.html").write_text(''''{% extends "admin/index.html" %} {% load i18n %} {% block content %}
list_filter_submit = Conjuntos de campos verdaderos = ( (_(“Pedido”), {“clases”:[“tab”]”campos”:(“número”,”cliente”,”estado”,”total”)}), (_(“Notas”), {“clases”:[“tab”]”campos”:(“notas”,”created_at”)}), ) lista_acciones = [“mark_paid_bulk”]
fila_acciones = [“mark_paid_row”]
detalles_acciones = [“duplicate_order”]
action_submit_line = [“save_and_ship”]
@display(descripción=_(“Estado”), etiqueta={ “pendiente”:”advertencia”,”pagado”:”info”,”enviado”:”primario”, “entregado”:”éxito”,”cancelado”:”peligro”}) def show_status(self, obj): regresar obj.get_status_display(), obj.status @display(descripción=_(“Cliente”)) def enlace_cliente(self, obj): regresar format_html(\'{}\’, obj.customer_id, obj.customer.name) @action(description=_(“Marcar pendiente → PAGADO (todos)”), icon=”pagos”) def mark_paid_bulk(self, request, queryset=Ninguno): n = Order.objects.filter(status=”pending”).update(status=”paid”) self.message_user(solicitud, f”Marcado {n} pedidos como pagados.”, nivel=messages.SUCCESS) @action(description=_(“Marcar como pagado”), icon=”pagos”, url_path=”mark-paid-row”) def mark_paid_row(self, request, object_id): Order.objects.filter(pk=object_id).update(status=”paid”) self.message_user(request, “Pedido marcado como pagado.”, nivel=messages.SUCCESS) return redirección(request.META.get(“HTTP_REFERER”,”/admin/”)) @action(description=_(“Duplicate”), icon=”content_copy”, url_path=”duplicate”) def duplicado_order(self, request, object_id): o = Order.objects.get(pk=object_id) o.pk = Ninguno; o.número = o.número + “-COPIAR”; o.status = “pendiente”; o.save() self.message_user(solicitud, “Pedido duplicado.”, nivel=messages.SUCCESS) return redirección(f”/admin/shop/order/{o.pk}/change/”) @action(description=_(“Guardar y enviar”)) def save_and_ship(self, request, obj): obj.status = “enviado”; obj.save() self.message_user(solicitud, f”Orden {obj.number} enviado.”, nivel=messages.SUCCESS) @admin.register(Producto) clase ProductAdmin(ModelAdmin): list_display = (“name”,”sku”,”category”,”show_status”, “price_display”,”stock_badge”,”featured”) list_editable = (“destacado”,) list_filter = ( (“status”, ChoicesDropdownFilter), (“categoría”, admin.RelatedFieldListFilter), (“precio”, RangeNumericFilter), (“destacado”, ChoicesDropdownFilter), ) search_fields = (“nombre”, “sku”) autocomplete_fields = (“categoría”,) list_filter_submit = Verdadero list_per_page = 20 save_on_top = Conjuntos de campos verdaderos = ( (_(“Conceptos básicos”), {“clases”:[“tab”]”campos”:(“nombre”,”sku”,”categoría”,”estado”,”destacado”)}), (_(“Precios”), {“clases”:[“tab”]”campos”:(“precio”,”tiene_descuento”,”descuento_porcentaje”,”stock”)}), (_(“Contenido”), {“clases”:[“tab”]”fields”:(“description”,)}), ) conditional_fields = {“discount_percent”: “has_discount == true”} @display(description=_(“Status”), label={ “draft”:”info”,”active”:”success”,”archived”:”warning”}) def show_status(self, obj): return obj.get_status_display(), obj.status @display(descripción=_(“Precio”)) def price_display(self, obj): si obj.has_discount y obj.discount_percent: devuelve format_html( \’${} \’ \’${}\’, obj.price, obj.final_price) return f”${obj.price}” @display(description=_(“Stock”), ordering=”stock”, label={“out”:”peligro”,”low”:”warning”,”ok”:”success”}) def stock_badge(self, obj): if obj.stock == 0: return “Agotado”, “out” if obj.stock < 10: return f"Bajo ({obj.stock})", "bajo" return f"{obj.stock} en stock", "ok" ''') (ROOT / "templates" / "admin" / "index.html").write_text(''''{% extends "admin/index.html" %} {% load i18n %} {% block content %}
{% para k en kpis %}
{{ k.título }}
{{ k.valor }}
{{ k.pie de página }}
{% final de %}
{% trans “Categorías principales” %}
{% para c en top_cats %}{{ c.nombre }}{{ cn }}{% final de %}
{% trans “Pedidos por estado” %}
{% para s en by_status %}{{ s.status }}{{ sc }}{% final de %}
{{ block.super }} {% endblock %} ”’)