首页 > 编程问答 >forms.ModelMultipleChoiceField 与 widget=FilteredSelectMultiple 不适用于自定义新 Django 管理

forms.ModelMultipleChoiceField 与 widget=FilteredSelectMultiple 不适用于自定义新 Django 管理

时间:2024-07-26 14:36:24浏览次数:8  
标签:python django django-models django-forms django-templates

我试图在自定义的新管理表单页面上显示 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>
    &rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
    &rsaquo; <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 }}
    &lt;link rel="stylesheet" type="text/css" href="{% static 'admin/css/widgets.css' %}"&gt;
    &lt;script type="text/javascript" src="{% static 'admin/js/vendor/jquery/jquery.js' %}"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="{% static 'admin/js/jquery.init.js' %}"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="{% static 'admin/js/core.js' %}"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="{% static 'admin/js/admin/RelatedObjectLookups.js' %}"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="{% static 'admin/js/actions.js' %}"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="{% static 'admin/js/inlines.js' %}"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="{% static 'admin/js/collapse.js' %}"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="{% static 'admin/js/urlify.js' %}"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="{% static 'admin/js/prepopulate.js' %}"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="{% static 'admin/js/popup.js' %}"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="{% static 'admin/js/SelectBox.js' %}"&gt;&lt;/script&gt;
    &lt;script type="text/javascript" src="{% static 'admin/js/SelectFilter2.js' %}"&gt;&lt;/script&gt;
    {{ form.media }}
    &lt;script type="text/javascript"&gt;
        django.jQuery(document).ready(function($) {
            $("select.filtered").SelectFilter2();
        });
    &lt;/script&gt;
{% endblock %}

{% block content %}
&lt;div class="container"&gt;
    &lt;h1&gt;{% translate 'Assign Products' %}&lt;/h1&gt;
    &lt;form action="." method="post"&gt;
        {% csrf_token %}
        {{ form.as_p }}
        &lt;button type="submit" class="btn btn-primary"&gt;{% translate 'Assign Products' %}&lt;/button&gt;
    &lt;/form&gt;
&lt;/div&gt;
{% endblock %}

这将加载必要的 JavaScript 文件,包括 SelectFilter2.js ,它为 FilteredSelectMultiple 小部件提供功能。确保还包含 {{ form.media }} 以加载表单所需的任何其他媒体文件。

完成这些更改后,你的 forms.ModelMultipleChoiceField 在你的自定义 Django 管理页面中应该会正确显示 FilteredSelectMultiple 小部件。

标签:python,django,django-models,django-forms,django-templates
From: 78784451

相关文章

  • Python,Pyinstaller打包含taichi模块的程序
    Python版本3.9、taichi版本1.7.1,pyinstaller版本6.9.0问题描述:正常Pyinstaller打包后报错[Taichi]version1.7.1,llvm15.0.1,commit0f143b2f,win,python3.9.19[Taichi]Startingonarch=x64Traceback(mostrecentcalllast):File"taichi\lang\_wrap_inspec......
  • Python,运行Yolo项目,报错AttributeError: ‘ImageDraw‘ object has no attribute ‘te
    Python3.9问题描述:其他电脑已经运行成功的Python,YOLO代码到我电脑上运行报错Traceback(mostrecentcalllast): File"C:\Users\Administrator\Desktop\20240725\识别项目\predict.py",line122,in<module>  frame=np.array(yolo.detect_image(frame)) Fil......
  • Python从零开始制做文字游戏(荒岛求生)
    文章目录前言开发游戏《荒岛求生》游戏大纲背景内容通关条件游戏过程探索荒岛购买物资休息总结代码开发定义变量当前代码引入背景故事当前代码循环问题解决:函数当前代码制作延时当前代码制作a函数(探索荒岛阶段)展示数......
  • 使用 Python 进行数据分析:入门指南
    使用Python进行数据分析:入门指南1.简介本指南将介绍如何使用Python进行数据分析,涵盖从数据加载到可视化分析的各个方面。2.必要的库NumPy:用于数值计算和数组操作。Pandas:用于数据处理和分析,提供DataFrame结构。Matplotlib:用于数据可视化,创建各种图表。Seab......
  • IT实战课堂计算机毕业设计源码精品基于Python的高校教育教材采购出入库进销存储信息管
    项目功能简介:《[含文档+PPT+源码等]精品基于Python的高校教育教材信息管理系统设计与实现》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功以及课程答疑与微信售后交流群、送查重系统不限次数免费查重等福利!软件开发环境及开发工具:开......
  • 为什么我的 Python 脚本失败并出现 TypeError?
    我正在编写一个Python脚本,该脚本应该计算数字列表的总和。但是,当我运行代码时遇到TypeError这是一个最小的例子:numbers=[1,2,3,'4']total=sum(numbers)print(total)Theerrormessageis:TypeError:unsupportedoperandtype(s)for+:'int'and'str......
  • 如何通过socks代理传递所有Python的流量?
    有如何通过http代理传递所有Python的流量?但是,它不处理sock代理。我想使用sock代理,我们可以通过ssh隧道轻松获得它。ssh-D5005user@server你可以使用socks库,让你的Python代码通过SOCKS代理传递所有流量。这个库可以让你在套接字级别上指定代......
  • 如何在streamlit python中流式传输由LLM生成的输出
    代码:fromlangchain_community.vectorstoresimportFAISSfromlangchain_community.embeddingsimportHuggingFaceEmbeddingsfromlangchainimportPromptTemplatefromlangchain_community.llmsimportLlamaCppfromlangchain.chainsimportRetrievalQAimports......
  • python mysql操作
    pipinstallmysql-connector-pythonimportmysql.connector#配置数据库连接参数config={'user':'your_username','password':'your_password','host':'your_host','database'......
  • Python 中的面向对象编程
    一.介绍在本文中,我们将使用Python中的类和对象来探索基本的OOP概念。面向对象编程(OOP)是一种强大的方法,可帮助开发人员组织代码,使其易于理解、重用和维护。Python是一种灵活的语言,可以很好地支持OOP概念。1.类和对象类是创建对象的蓝图。它定义了该类的对象将......