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_horizontal' 的管理员中导航,检查源并将存储在文件夹 '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 小部件仅在登录时有效的主要内容,如果未能解决你的问题,请参考以下文章