需要有关FilteredSelectMultiple小部件的指导

时间:2019-09-06 10:54:25

标签: python django python-3.x django-forms

很抱歉,这个问题可能会变得不太广泛,但是由于我只是在学习django(我只是业余爱好者开发人员),我需要一些指导,希望对我以后的人会有所帮助。找不到有关使用此小部件的任何清晰易懂的指南。在您的回答和帮助下,我将尝试使该问题至少具有指导意义。

材料对于该主题我有所帮助:

Django multi-select widget?

Django: Replacement for the default ManyToMany Widget of Forms

Django's FilteredSelectMultiple widget only works when logged in

Django FilteredSelectMultiple not rendering on page

Use the Django admin app's FilteredSelectMultiple widget in form

Get the chosen values from FilteredSelectMultiple widget in Django

Django FilteredSelectMultiple Right Half Does Not Render

其他链接很少,但是它们没有使任何内容更清楚或添加了新信息,因此我不会提及它们。

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

要创建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',)

有关此部分的问题:

  1. 我对django.conf导入是否正确?因为我没看到 导入任何我发现的材料。 答案:在我的测试中,我确定如果使用django.conf部分,则必须导入settings.BASE_DIR。在各种来源中,有两种编写css路径的方式,这种方式对我有用。
  2. 我需要创建widgets.css和相应的目录吗?要么 django会自己找到它吗?由于没有这样的文件或目录 使用django-admin startproject cmd创建框架网站后生成的代码? 答案:否。由于django会找到它们本身,因此无需创建widgets.css或任何文件。
  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'),
]

问题:

  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>
  1. 这部分似乎或多或少清楚。但是也许我应该修改 有什么了解吗? 答案:应该更改。将在下面编写完整的代码。

最后,我需要调整views.py来设置此表格及其相关内容的发生位置。

据我了解,本部分中的代码或多或少与小部件没有直接关系,但是为了完成所有工作并制作示例,我将使用在this (very good) django tutorial中倾斜/获取的代码:

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)

问题:

  1. 对这部分代码有何评论? 答案:缺少else: form = DrgCalculator()。将在下面编写修改后的代码。
  2. 我将如何访问用户选择使用的值 FilteredSelectMultiple?我想我应该清理数据 forms.py与其他小部件一样。所以我应该添加嵌套函数 在class CalculatorForm的{​​{1}}下面,对吗? 答案:是的,应该像其他情况一样清除数据。功能正确。

    forms.py

  3. 清洗后得到的数据将是列表还是字典?我是吗 对? 答案:否,从此小部件用户输入中收到的是QuerySet

这就是我所有的问题,很抱歉,我的回答太长了,我试图使其尽可能清楚。如果我需要澄清一些事情,请告诉我。我将尝试对其进行编辑和更新,以使其对以后将要阅读的人们友好。

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

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

1 个答案:

答案 0 :(得分:0)

经过几天的研究和测试,我设法使FilteredSelectMultiple小部件以用户形式在管理页面之外工作。如所答应的那样,我将尝试将积累的知识汇总为某种指南,希望对以后像我这样的人有所帮助。请注意,我不是专业人士(只是业余爱好者,没有精确的计算机工程背景),所以我的观察可能并不完全正确,或者我的观察方法不是最好的,但是它可能会帮助您获得正确的成绩跟踪。

因此,从FilteredSelectMultiple小部件forms.py开始,必须通过导入小部件,为其创建字段(类似于常规小部件)并添加嵌套的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

如我在测试和研究期间所确定的,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'),
]

现在使用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 %}

要从此小部件接收数据,应使用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)