我试图在自定义的新管理表单页面上显示 forms.ModelMultipleChoiceField 但它似乎没有像在已经制作的 Django 页面上显示的方式显示,例如模型产品 Django 管理页面。 我的 forms.ModelMultipleChoiceField 看起来像这样: 显示我的 forms.ModelMultipleChoiceField 是什么样子 当它应该看起来像这样: 显示 forms.ModelMultipleChoiceField 应该是什么样子
forms.py:|| |部分代码形式admin.py:
from django import forms
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
from django.contrib.admin.widgets import FilteredSelectMultiple
from home.models import Collection, Tag, Product
class ProductAssignForm(forms.Form):
from_name = forms.CharField(required=True, max_length=255, label='From Name')
to_name = forms.CharField(required=True, max_length=255, label='To Name')
assign_collections_name = forms.ModelMultipleChoiceField(
queryset=Collection.objects.all(),
required=False,
widget=FilteredSelectMultiple(
verbose_name='Collections',
is_stacked=False
),
label='Assign Collection Name'
)
tags = forms.ModelMultipleChoiceField(
queryset=Tag.objects.all(),
required=False,
widget=FilteredSelectMultiple(
verbose_name='Tags',
is_stacked=False
),
label='Tags'
)
class Meta:
model = Product
fields = ['collections', 'tags'] # Include the tags field in the fields list
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_method = 'POST'
self.helper.add_input(Submit('submit', 'Assign Products'))
assign_products.html:
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
form = ProductAdminForm
list_display = ('name', 'quantity', 'price', 'first_collection')
exclude = ('user', 'updated',)
def save_model(self, request, obj, form, change):
if not obj.user:
obj.user = request.user
obj.save()
def first_collection(self, obj):
first_collection = obj.collections.first()
return first_collection.name if first_collection else 'No collection'
def get_urls(self):
# return [
# path('assign-products/', self.admin_site.admin_view(self.assign_products), name='assign-products'),
# ] + super().get_urls()
custom_urls = [
path('assign-products/', self.admin_site.admin_view(self.assign_products), name='assign-products'),
*super().get_urls(),
]
return custom_urls
def assign_products(self, request):
opts = self.model._meta
if request.method == 'POST':
form = ProductAssignForm(request.POST)
if form.is_valid():
from_name = form.cleaned_data['from_name']
to_name = form.cleaned_data['to_name']
assign_collections_name = form.cleaned_data['assign_collections_name']
tags = form.cleaned_data['tags']
print(f"Searching products from '{from_name}' to '{to_name}'")
# Normalizing the names by removing whitespace and non-alphanumeric characters
from_name_normalized = ''.join(e for e in from_name if e.isalnum()).lower()
to_name_normalized = ''.join(e for e in to_name if e.isalnum()).lower()
# Search by search_name
products = Product.objects.filter(
search_name__gte=from_name_normalized,
search_name__lte=to_name_normalized
)
print(f"search_handle__gte={from_name_normalized}, search_handle__lte={to_name_normalized}")
print(f"Found {products.count()} products")
for product in products:
if assign_collections_name:
print(f"Assigning collections to product '{product.name}'")
product.collections.set(assign_collections_name)
if tags:
print(f"Assigning tags to product '{product.name}'")
product.tags.set(tags)
product.save()
return HttpResponseRedirect(request.path_info)
else:
form = ProductAssignForm()
context = dict(
self.admin_site.each_context(request),
title="Assign Products",
form=form,
opts=opts,
**self.admin_site.each_context(request),
)
return render(request, 'admin/assign_products.html', context)
我尝试过
{% block extrahead %}
{{ block.super }}
{{ form.media }}
<link rel="stylesheet" type="text/css" href="{% static 'css/admin_custom.css' %}">
<script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/core.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.init.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.form.js' %}"></script>
{% endblock %}
{% block javascript %}
{{ block.super }}
<script type="text/javascript">
django.jQuery(document).ready(function() {
django.jQuery('.selectfilter').filterchain();
});
</script>
{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% translate 'Home' %}</a>
› <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
› <a href="{% url 'admin:assign-products' %}">{% translate 'Assign Products' %}</a>
</div>
{% endblock %}
{% block content %}
<div class="container">
<h1>{% translate 'Assign Products' %}</h1>
<form action="." method="post">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
{% if field.help_text %}
<small class="form-text text-muted">{{ field.help_text }}</small>
{% endif %}
{% for error in field.errors %}
<div class="text-danger">{{ error }}</div>
{% endfor %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">{% translate 'Assign Products' %}</button>
</form>
</div>
{% endblock %}
脆皮形式 和 普通形式 ,我尝试过询问 ChatGPT和ClaudeAI| ||甚至 搜索谷歌 帮助将非常感激! 我的models.py代码:
Help would be really appreciated!
My models.py code:
class Collection(models.Model):
"""
TODO: Modify product method to get all the products in the collection and the subcollections.
TODO: THe functionality of default .all() is renamed to .all_self()
"""
parent = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, related_name='subcollections') # Store the parent collection, linked to itself
cid = ShortUUIDField(unique=True, length=10, max_length=15, prefix="col", alphabet="abcdefghijklmnopqrstuvwxyz0123456789", editable=False)
name = models.CharField(max_length=255)
description = models.TextField(default='No description provided.', blank=True, null=True)
images = models.ManyToManyField('Image', related_name='collections', blank=True)
has_image = models.BooleanField(default=False)
products = models.ManyToManyField('Product', related_name='collections', blank=True)
tags = models.ManyToManyField('Tag', related_name='collections', blank=True)
product_count = models.IntegerField(default=0) # Store the number of products in this collection only
total_product_count = models.IntegerField(default=0) # Store the number of products in this collection and all subcollections
created_at = models.DateTimeField(auto_now_add=True) # Stores when the collection field was created
handle = models.CharField(max_length=255, null=True, blank=True) # This will be used to generate the URL
active = models.BooleanField(default=True) # This will be used to determine if the collection is active or not
class Product(models.Model):
pid = ShortUUIDField(unique=True, length=10, max_length=20, prefix="prd", alphabet="abcdefghijklmnopqrstuvwxyz0123456789", editable=False)
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
name = models.CharField(max_length=255, default="Fresh Pear")
images = models.ManyToManyField('Image', related_name='products', blank=True)
description = models.TextField(null=True, blank=True, default="This is the description")
price = models.DecimalField(max_digits=9999999999, decimal_places=2, default="0.00")
old_price = models.DecimalField(max_digits=9999999999, decimal_places=2, default="0.00", blank=True)
specifications = models.JSONField(null=True, blank=True, default=dict)
product_status = models.CharField(choices=PRODUCT_STATUS, max_length=10, default="in_review")
status = models.BooleanField(default=True)
# in_stock = models.BooleanField(default=True)
quantity = models.DecimalField(max_digits=9999999999, decimal_places=0, default=0, blank=True)
featured = models.BooleanField(default=False)
digital = models.BooleanField(default=False)
sku = ShortUUIDField(unique=True, length=8, max_length=11, prefix="sku", alphabet="0123456789")
date = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(null=True, blank=True)
handle = models.CharField(unique=True, max_length=255, null=True, blank=True) # This will be used to generate the URL
search_name = models.CharField(max_length=255, null=True, blank=True) # This will be used to search the product
tags = models.ManyToManyField('Tag', related_name='products', blank=True)
# product.collections.[method] refers to Collection MTM Field declared in collection model
# tags = models.ForeignKey(Tag, on_delete=models.SET_NULL, null=True)
class Meta:
verbose_name_plural = "Products"
def __str__(self):
return self.name
def get_percentage(self):
# (1000 - 900) / 1000 * 100 = 10% discount
# Handle the cases of zero
if self.old_price == 0:
return 0
return (self.old_price - self.price) / self.old_price * 100
def save(self, *args, **kwargs):
self.updated = timezone.now()
super().save(*args, **kwargs)
问题在于,Django 的
FilteredSelectMultiple
小部件依赖于在 Django 管理模板中加载的 JavaScript 文件。当你创建一个自定义管理视图(如你所做的
assign_products
)时,这些 JavaScript 文件默认不会被加载。
你可以通过在
assign_products.html
模板中包含必要的 JavaScript 文件来解决这个问题:
{% extends 'admin/base.html' %}
{% load static i18n %}
{% block extrahead %}
{{ block.super }}
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/widgets.css' %}">
<script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/jquery.init.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/core.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/admin/RelatedObjectLookups.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/actions.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/inlines.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/collapse.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/urlify.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/prepopulate.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/popup.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/SelectBox.js' %}"></script>
<script type="text/javascript" src="{% static 'admin/js/SelectFilter2.js' %}"></script>
{{ form.media }}
<script type="text/javascript">
django.jQuery(document).ready(function($) {
$("select.filtered").SelectFilter2();
});
</script>
{% endblock %}
{% block content %}
<div class="container">
<h1>{% translate 'Assign Products' %}</h1>
<form action="." method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">{% translate 'Assign Products' %}</button>
</form>
</div>
{% endblock %}
这将加载必要的 JavaScript 文件,包括
SelectFilter2.js
,它为
FilteredSelectMultiple
小部件提供功能。确保还包含
{{ form.media }}
以加载表单所需的任何其他媒体文件。
完成这些更改后,你的
forms.ModelMultipleChoiceField
在你的自定义 Django 管理页面中应该会正确显示
FilteredSelectMultiple
小部件。