需要 FilteredSelectMultiple 小部件的指导

Gex*_*xas 4 python django django-forms python-3.x

如果问题可能变得有点宽泛,我很抱歉,但由于我只是在学习 django(而且我只是业余开发者),我需要一些指导,我希望这能在未来帮助像我这样的人,因为我找不到有关使用此小部件的任何清晰易懂的指南。有了您的回答和帮助,我将尝试使这个问题线程至少具有指导意义。

我发现对这个话题有些帮助的材料:

Django 多选小部件?

Django:替换默认的多对多表单小部件

Django 的 FilteredSelectMultiple 小部件仅在登录时有效

Django FilteredSelectMultiple 未在页面上呈现

在表单中使用 Django 管理应用程序的 FilteredSelectMultiple 小部件

从 Django 中的 FilteredSelectMultiple 小部件获取所选值

Django FilteredSelectMultiple 右半部分不渲染

其他链接很少,但他们没有做任何更清楚的事情或添加新信息,所以我不会提及它们。

这是我设法理解的内容(如果我错了,请纠正我或添加我遗漏的任何内容):

要首先创建FilteredSelectMultiple小部件,我需要修改forms.py(就像在任何其他小部件创建过程中一样)。修正forms.py应该有from django.contrib.admin.widgets import FilteredSelectMultiple导入和Media类。forms.py代码应该是这样的(请纠正我,因为它可能是错误的):

from django import forms
from catalog.models import DrgCode  
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.conf import settings #without it I get an error that settings not defined

class CalculatorForm(forms.Form):
    drg_choice = forms.ModelMultipleChoiceField(queryset=DrgCode.objects.all(), widget=FilteredSelectMultiple("Somethings", is_stacked=False), required=True)

    class Media:
        css = {
            'all': (os.path.join(settings.BASE_DIR, '/static/admin/css/widgets.css'),),
        }
        js = ('/admin/jsi18n',)
Run Code Online (Sandbox Code Playgroud)

关于这部分的问题:

  1. 我对django.conf进口的看法正确吗?因为我没有看到它在我找到的任何材料中导入。答:在我的测试过程中,我确定django.conf如果使用settings.BASE_DIR零件,则需要导入。在各种来源中,有两种书写css路径的方式,这一种对我有用。
  2. 我需要创建widgets.css和对应的目录吗?还是 Django 会自己找到?由于我使用django-admin startprojectcmd创建骨架网站后没有生成此类文件或目录?答:不需要。不需要创建widgets.css或任何文件,因为 django 会自己找到它们。
  3. 与之前jsi18n部分相同的问题。还有这是什么?我假设它的 javascript 文件,但由于某种原因它没有扩展名。另外我在任何地方都找不到它?我应该创建它吗?怎么做?或者我可以从某个地方复制它?部分答案:不需要创建它。只需将其指向urls.py. 仍然不知道它到底是那种文件(或它在哪里)

修改后forms.py我应该urls.py通过添加来修改url(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', name='jsi18n')

所以urls.py现在看起来像这样:

from django.urls import path
from . import views
from django.conf.urls import url 


urlpatterns = [
    path('', views.index, name='index'),
    'django.views.i18n.javascript_catalog',
    name='jsi18n'),
]
Run Code Online (Sandbox Code Playgroud)

问题:

  1. 我做得对还是应该在下面添加它urlpatterns答:这个方法就好了。

现在我需要HTML为要呈现的表单设置模板文件(就像在任何其他情况下一样)。它的代码(文件名为DrgCalculator.html):

{% extends "base_generic.html" %}
   <script type="text/javascript" src="{% url 'jsi18n' %}" > </script>

  {{ form.media }}

  <form enctype="multipart/form-data" method="POST">
  {% csrf_token %}
  {{ form.as_p }}
  <button type="submit" class="save btn btn-default">Submit</button>
  </form>
Run Code Online (Sandbox Code Playgroud)
  1. 这部分似乎或多或少是清楚的。但也许我应该修改一些东西或了解一下?答:应该改。下面会写完整的代码。

最后,我需要调整views.py以设置此表单以及与之相关的所有内容发生的位置。

据我了解,这部分中的代码或多或少与小部件没有直接关系,但是为了完成所有内容并制作工作示例,我将使用我在这个(非常好的)django 教程中学习/获得的代码:

from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse

from catalog.models import DrgCode
from catalog.forms import CalculatorForm

def DrgCalculator(request):
    if request.method == 'POST':
        form = CalculatorForm(request.POST)
        if form.is_valid():
            return render(request, 'DrgCalculator.html')
    context = {
        'form': form,
    }
    return render(request, 'DrgCalculator.html', context)
Run Code Online (Sandbox Code Playgroud)

问题:

  1. 对这部分代码有什么评论吗?答:不见了else: form = DrgCalculator()。下面会写修改后的代码。
  2. 我将如何访问用户选择使用的值 FilteredSelectMultiple?我想我应该forms.py像其他小部件一样清理数据 。所以,我应该添加以下嵌套函数到我class CalculatorFormforms.py是吗?答:是的,应该像其他情况一样清理数据。功能正确。

    def clean_CalculatorForm(self): drg_choice = self.cleaned_data['drg_choice'] return drg_choice

  3. 清理后得到的数据是列表还是字典?我对吗?回答:不,从这个小部件用户输入作为 QuerySet 接收

这就是我所有的问题,对不起,长篇大论,我尽量把它说清楚。如果我需要澄清一些事情,请告诉我。我将尝试编辑和更新它,以使其对将来阅读它的人友好。

EDIT1:回答了我的一些问题。

EDIT2:回答了我的其余问题。

Gex*_*xas 6

经过几天的研究和测试,我设法让FilteredSelectMultiple小部件以用户形式在管理页面之外工作。正如所承诺的那样,我将尝试将我积累的知识综合成某种指南,我希望将来能帮助像我这样的人。请注意,我远非专业人士(确切地说只是一个没有计算机工程背景的业余爱好者)所以我的观察可能不完全正确,或者我做的方式不是最好的,但它可能会帮助您找到正确的方法追踪。

于是开始与FilteredSelectMultiple小部件forms.py必须由进口部件,创造了IT领域(类似像常规的小部件)和添加嵌套修改Media类。代码示例:

from django.contrib.admin.widgets import FilteredSelectMultiple    

class DrgCalculator(forms.Form):
        drg_choise = forms.ModelMultipleChoiceField(queryset=DrgCode.objects.all(),
                                                          label="Something",
                                                          widget=FilteredSelectMultiple("Title", is_stacked=False),
                                                          required=True)

        class Media:
            css = {
                'all': ('/static/admin/css/widgets.css',),
            }
            js = ('/admin/jsi18n',)

        def clean_drg_choise(self):
            drg_choise = self.cleaned_data['drg_choise']
            return drg_choise
Run Code Online (Sandbox Code Playgroud)

正如我在测试和研究期间确定的那样,class Media应该按书面形式复制,并且不需要更改小部件即可工作。此类中提到的文件将由 django 本身找到,因此无需搜索和复制它们(如我阅读的某些材料中所述)。

创建表单后urls.py应进行修改。在测试期间我发现,在较新的 django 版本(或至少我使用过的版本)中 javascript_catalog被重命名,并且提供的 url 不能是字符串。所以代码应该是这样的:

from django.urls import path
from . import views
from django.conf.urls import url
from django import views as django_views

urlpatterns = [
    url(r'^jsi18n/$', django_views.i18n.JavaScriptCatalog.as_view(), name='jsi18n'),
]
Run Code Online (Sandbox Code Playgroud)

现在对于htlm模板,我确信有更多的方法可以做到,所以我只提供示例:

{% extends "base_generic.html" %}

{% block content %}
<div id='frame'>
    <form action="" method="post">
        <div id='sk_body'>
            <fieldset>
            <legend>Fill required fields</legend>      
                <form>
                    {% csrf_token %}
                    <table>
                        {{ form.media }}
                        {{ form.as_table }}
                        <script type="text/javascript" src="{% url 'jsi18n' %}"></script>
                    </table>
                        <input type="submit" value="Count">
                </form>
            </fieldset>
        </div>
    </form>
</div>
{% endblock %}
Run Code Online (Sandbox Code Playgroud)

要从这个小部件接收数据,views.py应该使用相当标准的代码,我使用的示例代码:

def DRG_calcualtor(request):
    if request.method == 'POST':
        form = DrgCalculator(request.POST)
        if form.is_valid():
            choosen_drg = form.cleaned_data['drg_choise'] #result as QuerySet
            choosen_drg_list = list([str(i) for i in choosen_drg]) #you can convert it to list or anything you need             

            return render(request, 'DRGcalculator_valid.html')

        context = {
            'form': form,
            }
        return render(request, 'DRGcalculator.html', context)

    else:
        form = DrgCalculator()
    context = {
        'form': form,
        }
    return render(request, 'DRGcalculator.html', context)
Run Code Online (Sandbox Code Playgroud)