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

Posted

技术标签:

【中文标题】Django 的 FilteredSelectMultiple 小部件仅在登录时有效【英文标题】:Django's FilteredSelectMultiple widget only works when logged in 【发布时间】:2018-02-02 03:12:11 【问题描述】:

我有一个 ModelForm,我在其中使用 FilteredSelectMultiple 小部件。当我以我创建的超级用户身份登录时,它工作得很好。但是,当未登录时,我看不到表单中的小部件,我只看到所有项目的列表(如多选)。所以我的问题是:为什么登录时 FilteredSelectMultiple 工作得很好,但注销时却不存在?

我没有在任何我能想到的地方设置任何权限或类似的东西。

这是我的部分代码:

forms.py

from django.contrib.admin.widgets import FilteredSelectMultiple

class MyModelForm(forms.ModelForm):
    my_field = forms.ModelMultipleChoiceField(queryset=Something.objects.all(), widget=FilteredSelectMultiple("Somethings", is_stacked=False), required=False)

    class Media:
        css = 
            'all': (os.path.join(settings.BASE_DIR, '/static/admin/css/widgets.css'),),
        
        js = ('/admin/jsi18n'),

    class Meta:
        model = MyModel
        fields = ('some_field', 'some_other_field')

form.html

% extends base.html %
% block head %
% load staticfiles %
    some stuff
% endblock head %
% block content %
<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>

% endblock content %

urls.py

url(r'^admin/jsi18n/$',
    'django.views.i18n.javascript_catalog',
    name='jsi18n'
),

如果您需要任何其他代码,请告诉我。 (我使用 Django 1.8 和 Python 2.7)

编辑

在注销后加载页面时,控制台会显示以下内容:

jsi18n : SyntaxError: 预期表达式,得到 '

jsi18n : SyntaxError: 预期表达式,得到 '

SelectFilter2.js : ReferenceError: interpolate is not defined

当我以超级用户身份登录时,这些消息都不会出现。

编辑 2

按照答案中的建议,我尝试将媒体类更改为:

class Media:
    # Nécessaire pour l'affichage de FilteredSelectMultiple
    css = 
        'all': (os.path.join(settings.BASE_DIR, '/static/admin/css/widgets.css'),),
    
    extra = '' if settings.DEBUG else '.min'
    js = ('/admin/jsi18n', 'jquery%s.js' % extra, 'jquery.init.js', 'core.js', 'SelectBox.js', 'SelectFilter2.js'),

这会导致 AttributeError:

/my/url/form 处的 AttributeError

'tuple' 对象没有属性'startswith'

[...]

异常位置: /path/to/virtualenv/local/lib/python2.7/site-packages/django/forms/widgets.py 在 absolute_path 中,第 74 行

我也尝试更改我的模板:

<script type="text/javascript" src="% url 'jsi18n' %" > </script>
<script type="text/javascript" src="% static 'admin/js/jquery.min.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/SelectBox.js' %"></script>
<script type="text/javascript" src="% static 'admin/js/SelectFilter2.js' %"></script>
 form.media 

没有产生任何错误,但也没有改变我的问题:(

还有其他想法吗?

【问题讨论】:

只有你的详细问题对我有帮助:) 谢谢! 【参考方案1】:

我不完全确定,但可能是因为 url 在 admin auth 下?

url(r'^admin/jsi18n/$',
    'django.views.i18n.javascript_catalog',
    name='jsi18n'
)

所以当没有以管理员身份登录时,无法访问脚本jsi18n,因为您需要以管理员身份进行身份验证才能访问该脚本。

把网址写成不在管理员下:

url(r'^jsi18n/$',
    'django.views.i18n.javascript_catalog',
    name='jsi18n'
)

【讨论】:

好像就这么简单!太感谢了!抱歉,我没有足够的代表来投票... 不客气; 'tuple' 对象没有属性 'startswith' 错误应该是因为我们的 Media 类属性定义中的额外逗号(,)?【参考方案2】:

老问题,但我最近做了,想把事情弄清楚。 您将需要一些东西来使其工作。

    如前所述,因此我不会重复代码您需要将 FilteredSelectMultiple 小部件分配给您的表单字段。 模板中来自管理员的 CSS widget.css。

    小部件的 Jquery。在这里我遇到了一些问题,因为我正在使用 bootstrap 4 和 bootstrap date 小部件,其中 jquery 声明如下:

    <script src="% static 'admin/js/vendor/jquery/jquery.min.js' %"></script>
    <script>window.jQuery || document.write("<script src=\"% static 'admin/js/vendor/jquery/jquery.min.js' %\"><\/script>")</script>
    

您必须为 window.jquery 添加声明:

    <script>window.jquery || document.write("<script src=\"% static 'admin/js/vendor/jquery/jquery.min.js' %\"><\/script>")</script>

你还必须包含 jquery.init.js:

    <script src="% static 'admin/js/jquery.init.js' %"></script>

    jsi18n 是在 django admin 中生成的 JS,这里也有几句话要说。

    您可以直接声明它,但您必须以管理员身份登录,否则它将不起作用:

    <script type="text/javascript" src="/admin/jsi18n"></script>
    

    上面提到的解决方案是为此创建 url,但是如果您使用的是英语以外的其他语言,它不会本地化您的小部件:

    url(r'^jsi18n/$',
        'django.views.i18n.javascript_catalog',
        name='jsi18n')
    
    我的解决方案是生成手动本地化文件,转到 /admin/jsi18n url,将其保存为静态文件,然后将生成的文件从静态文件导入模板 - 在浏览器中转到“http://localhost/admin/jsi18n/”,这将生成使用您的本地化的 javascript 文件项目设置中的语言。像常规 js 文件一样保存内容,然后像常规 js 脚本/文件一样将其导入您的模板中。

    小部件的 JS。您可以在模板中使用 django form.media ,但如果您在像我这样由 ajax 加载的模态窗口中使用此小部件,它会延迟事情,所以我只需在我的基本模板中手动导入它们。

    从 django 10 开始(如果我没记错的话)你必须在模板中手动启动小部件:

     form.building 
    <script>SelectFilter.init("id_building", "Builidngs", 0, "/static/");</script>
    

    最后一件事是,如果您想在管理面板中看起来完全一样,那么您将不得不覆盖一些 css,因为如果您使用引导程序,它会在少数地方使用通用 css。我不会粘贴代码,因为我已经修改了这些,但你应该处理它就好了:)

【讨论】:

感谢您的详细解答。它对我没有用,因为 sergiuz 的回答以非常简单的方式完美地解决了我的问题;但是,它可能对其他人有用。作为记录,当我发布问题时,我使用的是 Django 1.8、Bootstrap 3 和当时可用的 jQuery 版本。当我升级到 Bootstrap 4 和最新的 jQuery 时,代码仍然有效。 我知道这是旧帖子,但也许您可以举个例子并详细解释一下-您的意思是:My solution is to generate manually localizeds file going to /admin/jsi18n url, saving it in static and then importing generated file from static to template.我该怎么做? 我对您提出的解决方案进行了小编辑。希望它解释得更多。这只是通过 django 保存生成的文件并像常规 js 文件一样导入它的简单过程【参考方案3】:

这就是我所做的

from django.contrib.admin.widgets import FilteredSelectMultiple

class MyModelForm(forms.ModelForm):
    my_field = forms.ModelMultipleChoiceField(queryset=Something.objects.all(), widget=FilteredSelectMultiple("Somethings", is_stacked=False), required=False)

    class Media:
        extend = False
        css = 
            'all': [
                'admin/css/widgets.css'
            ]
        
        js = (
            'js/django_global.js',
            'admin/js/jquery.init.js',
            'admin/js/core.js',
            'admin/js/prepopulate_init.js',
            'admin/js/prepopulate.js',
            'admin/js/SelectBox.js',
            'admin/js/SelectFilter2.js',
            'admin/js/admin/RelatedObjectLookups.js',
        )  

    class Meta:
        model = MyModel
        fields = ('some_field', 'some_other_field')

“js/django_global.js”是从管理模块中保存的,如“rifle2000”@第 4.3 点所述。在实现 'filter_horizo​​ntal' 的管理员中导航,检查源并将存储在文件夹 'localhost/admin/jsi18n' 中的(索引)文件作为 django_global.js 保存在你的 'app/static' 文件夹中。

在您的表单模板中

% extends 'base.html' %
% load static bootstrap4 %

% block extrastyle %
    % bootstrap_javascript jquery='full' %  # Embed Bootstrap JS+jQuery #
     form.media 
    <style>
    .selector h2 
        margin: 0;
        padding: 8px;
        font-weight: 400;
        font-size: 15px;
        text-align: left;
        background: #005236;
        color: white;
    
    </style>
% endblock extrastyle %

【讨论】:

【参考方案4】:

这可能是因为当登录并在管理员中查看时,它会通过小部件的媒体属性加载额外的 javascript。

在此处查看小部件的源代码: https://github.com/django/django/blob/master/django/contrib/admin/widgets.py

查看小部件媒体属性中的那些 javascript 文件是否在您未登录时加载。如果没有,请尝试将它们添加到表单的媒体中。

【讨论】:

它没有用——或者我没能让它工作——请看我的第二次编辑。【参考方案5】:

我遇到了同样的问题,但对于 Django 3.2。我发现的所有其他答案都指向与 urls.py 当前在最新版本 Django 中的工作方式不兼容的旧解决方案。

如果您发现 FilteredSelectMultiple 小部件仅在您登录到管理门户时有效,那么您需要将以下内容添加到您的主项目文件夹中的 urls.py 中:

from django.views.i18n import JavaScriptCatalog

urlpatterns = [
path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'),]

您还应该确保表单的 Media 类看起来像这样:

from django.contrib.admin.widgets import FilteredSelectMultiple
class DepartmentForm(ModelForm):
    employees = forms.ModelMultipleChoiceField(label="", queryset=Employees.objects.all(), widget=FilteredSelectMultiple("Employees", is_stacked=False))
    
    class Media:
            css = 'all': ('/static/path/to/widgets.css',),
            js = ('/jsi18n',)

在那之后,我的工作正常。如果您使用的是最新版本的 Django,并且发现 FilteredSelectMultiple 小部件仅在您登录到管理门户时才有效,请尝试上述方法。希望这可以帮助。把我逼疯了几个小时。

【讨论】:

以上是关于Django 的 FilteredSelectMultiple 小部件仅在登录时有效的主要内容,如果未能解决你的问题,请参考以下文章

django的文档

Django 大神带你飞系列~走进Django

Django:启动django

django的单元测试怎么用

django-admin 和django-admin.py的区别

mac电脑安装django ,运行django报错解决