add bulk update subcategory action and form for ProductVariant; simplify delete permission logic
This commit is contained in:
@@ -10,8 +10,9 @@ from django.contrib.postgres.fields import ArrayField
|
||||
from unfold.widgets import UnfoldAdminColorInputWidget
|
||||
from unfold.decorators import action, display
|
||||
from utils.admin import ModelAdmin
|
||||
from django.shortcuts import redirect
|
||||
from django.shortcuts import redirect, render
|
||||
from .permissions import ProductDetailCategoryPermission, ProductAdminPermission, ProductVariantAdminPermission, ProductVariantInlineAdminPermission, InPackItemsAdminPermission, AttributeTypeAdminPermission, AttributeValueAdminPermission
|
||||
from django import forms
|
||||
|
||||
@admin.register(ProductDetailCategory)
|
||||
class ProductDetailCategoryAdmin(ProductDetailCategoryPermission, ModelAdmin, ImportExportModelAdmin):
|
||||
@@ -227,6 +228,18 @@ class ProductVariantInLine(ProductVariantInlineAdminPermission, StackedInline):
|
||||
|
||||
|
||||
from unfold.contrib.filters.admin import RelatedDropdownFilter
|
||||
|
||||
|
||||
class BulkSubCategoryForm(forms.Form):
|
||||
"""فرم برای انتخاب زیر دستهبندی برای محصولات"""
|
||||
subcategory = forms.ModelChoiceField(
|
||||
queryset=SubCategoryModel.objects.all(),
|
||||
required=True,
|
||||
label='زیر دستهبندی',
|
||||
help_text='زیر دستهبندی جدید را برای محصولات انتخاب شده انتخاب کنید'
|
||||
)
|
||||
|
||||
|
||||
@admin.register(ProductVariant)
|
||||
class ProductVariantAdmin(ProductVariantAdminPermission, ModelAdmin, ImportExportModelAdmin):
|
||||
import_form_class = ImportForm
|
||||
@@ -252,6 +265,7 @@ class ProductModelAdmin(ProductAdminPermission, ModelAdmin, ImportExportModelAdm
|
||||
autocomplete_fields = ['related_products', 'shop']
|
||||
# compressed_fields = True
|
||||
warn_unsaved_form = True
|
||||
list_per_page = 2
|
||||
actions_list = ['redirect_to_learn', 'update_products_price']
|
||||
list_display = ['display_image', 'shop__shop_name','display_price', 'view', 'show', 'rating', 'category', 'created_at']
|
||||
fieldsets = (
|
||||
@@ -301,6 +315,46 @@ class ProductModelAdmin(ProductAdminPermission, ModelAdmin, ImportExportModelAdm
|
||||
messages.success(request, f"قیمت {ProductVariant.objects.all().count()} تنوع محصول اپدیت شد")
|
||||
return redirect("admin:product_productmodel_changelist")
|
||||
|
||||
def bulk_update_subcategory_action(self, request, queryset):
|
||||
"""اکشن برای تغییر دستهبندی چند محصول همزمان"""
|
||||
|
||||
# اگر فرم ارسال شده است
|
||||
if 'apply' in request.POST:
|
||||
form = BulkSubCategoryForm(request.POST)
|
||||
|
||||
if form.is_valid():
|
||||
subcategory = form.cleaned_data['subcategory']
|
||||
count = queryset.count()
|
||||
|
||||
# بهروزرسانی تمام محصولات انتخاب شده
|
||||
queryset.update(category=subcategory)
|
||||
|
||||
messages.success(
|
||||
request,
|
||||
f'دستهبندی {count} محصول به "{subcategory.name}" تغییر یافت.'
|
||||
)
|
||||
return redirect('admin:product_productmodel_changelist')
|
||||
else:
|
||||
form = BulkSubCategoryForm()
|
||||
|
||||
# نمایش صفحه تأیید
|
||||
context = {
|
||||
'form': form,
|
||||
'products': queryset,
|
||||
'selected_ids': list(queryset.values_list('pk', flat=True)),
|
||||
'action_name': 'bulk_update_subcategory_action',
|
||||
'title': 'تغییر دستهبندی محصولات',
|
||||
}
|
||||
|
||||
return render(
|
||||
request,
|
||||
'admin/product/bulk_subcategory_form.html',
|
||||
context
|
||||
)
|
||||
|
||||
bulk_update_subcategory_action.short_description = "تغییر دستهبندی محصولات انتخاب شده"
|
||||
actions = ['bulk_update_subcategory_action']
|
||||
|
||||
|
||||
# @display(
|
||||
# description=("نمایش در صفحه ی اصلی"),
|
||||
|
||||
@@ -30,13 +30,7 @@ class ProductAdminPermission:
|
||||
return request.user.shop == obj.shop
|
||||
|
||||
def has_delete_permission(self, request, obj=None):
|
||||
if request.user.is_superuser or obj == None:
|
||||
return True
|
||||
|
||||
if not hasattr(request.user, 'shop'):
|
||||
return False
|
||||
|
||||
return request.user.shop == obj.shop
|
||||
return request.user.is_superuser
|
||||
|
||||
def has_view_permission(self, request, obj=None):
|
||||
if request.user.is_superuser or obj == None:
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<div style="max-width: 800px; margin: 40px auto; padding: 20px;">
|
||||
<h1 style="margin-bottom: 20px;">{{ title }}</h1>
|
||||
|
||||
<div style="background: #f8f9fa; padding: 20px; border-radius: 5px; margin-bottom: 20px;">
|
||||
<h3 style="margin-top: 0;">محصولات انتخاب شده:</h3>
|
||||
<ul style="list-style: none; padding: 0;">
|
||||
{% for product in products %}
|
||||
<li style="padding: 8px; border-bottom: 1px solid #dee2e6;">
|
||||
<strong>{{ product.name }}</strong>
|
||||
{% if product.category %}
|
||||
<span style="color: #6c757d;"> - دسته فعلی: {{ product.category.name }}</span>
|
||||
{% else %}
|
||||
<span style="color: #dc3545;"> - بدون دستهبندی</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<p style="margin-top: 15px; font-weight: bold;">
|
||||
تعداد کل: {{ products|length }} محصول
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form method="post" style="background: white; padding: 20px; border: 1px solid #dee2e6; border-radius: 5px;">
|
||||
{% csrf_token %}
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label for="{{ form.subcategory.id_for_label }}" style="display: block; margin-bottom: 8px; font-weight: bold;">
|
||||
{{ form.subcategory.label }}
|
||||
</label>
|
||||
{{ form.subcategory }}
|
||||
{% if form.subcategory.help_text %}
|
||||
<p style="color: #6c757d; font-size: 0.9em; margin-top: 5px;">
|
||||
{{ form.subcategory.help_text }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if form.subcategory.errors %}
|
||||
<div style="color: #dc3545; margin-top: 5px;">
|
||||
{{ form.subcategory.errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="action" value="bulk_update_subcategory_action">
|
||||
{% for id in selected_ids %}
|
||||
<input type="hidden" name="_selected_action" value="{{ id }}">
|
||||
{% endfor %}
|
||||
|
||||
<div style="margin-top: 30px; display: flex; gap: 10px;">
|
||||
<button type="submit" name="apply"
|
||||
style="background: #28a745; color: white; border: none; padding: 10px 20px;
|
||||
border-radius: 5px; cursor: pointer; font-size: 14px;">
|
||||
اعمال تغییرات
|
||||
</button>
|
||||
<a href="{% url 'admin:product_productmodel_changelist' %}"
|
||||
style="background: #6c757d; color: white; border: none; padding: 10px 20px;
|
||||
border-radius: 5px; text-decoration: none; display: inline-block; font-size: 14px;">
|
||||
انصراف
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
select {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #ced4da;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
select:focus {
|
||||
outline: none;
|
||||
border-color: #80bdff;
|
||||
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
|
||||
}
|
||||
|
||||
button:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user