有没有办法让ArrayField的管理窗口小部件允许添加和删除对象?似乎默认情况下,它只显示一个文本字段,并使用逗号分隔作为其值。
除了不方便之外,AFAICT在数组的基本字段是Char / TextField的情况下,这并不允许在数组的任何文本中包含逗号的任何方式。
答案 0 :(得分:15)
我不相信(original source),但更简单的选择是在模型上继承ArrayField
并覆盖默认的管理窗口小部件。接下来是一个基本实现(在Django 1.9和1.10中测试):
<强> models.py 强>
from django import forms
from django.db import models
from django.contrib.postgres.fields import ArrayField
class ChoiceArrayField(ArrayField):
"""
A field that allows us to store an array of choices.
Uses Django's Postgres ArrayField
and a MultipleChoiceField for its formfield.
"""
def formfield(self, **kwargs):
defaults = {
'form_class': forms.MultipleChoiceField,
'choices': self.base_field.choices,
}
defaults.update(kwargs)
# Skip our parent's formfield implementation completely as we don't
# care for it.
# pylint:disable=bad-super-call
return super(ArrayField, self).formfield(**defaults)
FUNCTION_CHOICES = (
('0', 'Planning'),
('1', 'Operation'),
('2', 'Reporting'),
)
class FunctionModel(models.Model):
name = models.CharField(max_length=128, unique=True)
function = ChoiceArrayField(
base_field=models.CharField(max_length=256, choices=FUNCTION_CHOICES),
default=list)
答案 1 :(得分:8)
对于OP或任何在那里看的人,在这些有用的位之间你应该好好去:
答案 2 :(得分:2)
这是一个已经被接受的解决方案的更好版本。使用“CheckboxSelectMultiple”使其在管理页面中更有用。
class ChoiceArrayField(ArrayField):
def formfield(self, **kwargs):
defaults = {
'form_class': forms.TypedMultipleChoiceField,
'choices': self.base_field.choices,
'coerce': self.base_field.to_python,
'widget': forms.CheckboxSelectMultiple,
}
defaults.update(kwargs)
return super(ArrayField, self).formfield(**defaults)
答案 3 :(得分:2)
Django 更好的管理 ArrayField 包正好提供了这个功能。与上述解决方案相比,它的优势在于它允许您动态添加新条目,而不是依赖于预定义的选择。
请参阅此处的文档:django-better-admin-arrayfield
它有一个替代 /* csv to json */
const express = require("express"),
app = express(),
upload = require("express-fileupload"),
csvtojson = require("csvtojson");
var http = require('http');
var path = require("path");
var bodyParser = require('body-parser');
var helmet = require('helmet');
var rateLimit = require("express-rate-limit");
app.use(upload());
var server = http.createServer(app);
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
app.use(bodyParser.urlencoded({extended: false}));
app.use(helmet());
app.use(limiter);
const port = process.env.PORT || 3000
// Creates a server which runs on port 3000 and
// can be accessed through localhost:3000
app.listen(port, () => {
console.log(`server running on port at ${port}`);
})
app.get('/', function(req, res){
res.sendFile(path.join(__dirname,'index.html'));
});
app.post('/getscore', getscore);
function getscore(req, res){
var spawn = require("child_process").spawn;
var process = spawn('python',["mainfile.py", req.body.patentNumber]);
// Takes stdout data from script which executed
// with arguments and send this data to res object
// dataString = "Date: "
process.stdout.on('data', function(data) {
res.send("<p>Input patent number: "+req.body.patentNumber+"</p><p>"+data+"</p>");
// dataString = dataString + data
// console.log(dataString)
})
// process.stdout.on('end', function(dataString){
// res.send("<p>Input patent number: "+req.body.patentNumber+"</p><p>"+dataString+"</p>");
// })
process.stderr.on('data', function(data){
res.send(data.toString());
});
}
的插件和一个简单的 mixin,可以添加到管理模型中。
print()
这将显示如下内容:
答案 4 :(得分:1)
django-select2
提供了一种使用Select2呈现ArrayField
的方法。在他们的文档中,示例适用于ArrayField
:
渲染已选择的值:
class ArrayFieldWidget(Select2TagWidget):
def render_options(self, *args, **kwargs):
try:
selected_choices, = args
except ValueError: # Signature contained `choices` prior to Django 1.10
choices, selected_choices = args
output = ['<option></option>' if not self.is_required and not self.allow_multiple_selected else '']
selected_choices = {force_text(v) for v in selected_choices.split(',')}
choices = {(v, v) for v in selected_choices}
for option_value, option_label in choices:
output.append(self.render_option(selected_choices, option_value, option_label))
return '\n'.join(output)
def value_from_datadict(self, data, files, name):
values = super().value_from_datadict(data, files, name)
return ",".join(values)
将小部件添加到表单:
class MyForm(ModelForm):
class Meta:
fields = ['my_array_field']
widgets = {
'my_array_field': ArrayFieldWidget
}
答案 5 :(得分:0)
这是另一个使用 Django Admin M2M filter_horizontal
小部件的版本,而不是标准的 HTML 选择多个。
我们仅在 Admin 站点中使用 Django 表单,这对我们有用,但是如果在 Admin 之外使用,管理小部件 FilteredSelectMultiple
可能会损坏。另一种方法是覆盖 ModelAdmin.get_form
以实例化数组字段的正确表单类和小部件。 ModelAdmin.formfields_overrides
是不够的,因为您需要实例化小部件,设置位置参数,如代码片段所示。
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.contrib.postgres.fields import ArrayField
from django.forms import MultipleChoiceField
class ChoiceArrayField(ArrayField):
"""
A choices ArrayField that uses the `horizontal_filter` style of an M2M in the Admin
Usage::
class MyModel(models.Model):
tags = ChoiceArrayField(
models.TextField(choices=TAG_CHOICES),
verbose_name="Tags",
help_text="Some tags help",
blank=True,
default=list,
)
"""
def formfield(self, **kwargs):
widget = FilteredSelectMultiple(self.verbose_name, False)
defaults = {
"form_class": MultipleChoiceField,
"widget": widget,
"choices": self.base_field.choices,
}
defaults.update(kwargs)
# Skip our parent's formfield implementation completely as we don't
# care for it.
return super(ArrayField, self).formfield(**defaults)
答案 6 :(得分:0)
为你的模型编写一个表单类并使用 forms.MultipleChoiceField for ArrayField:
class ModelForm(forms.ModelForm):
my_array_field = forms.MultipleChoiceField(
choices=[1, 2, 3]
)
class Meta:
exclude = ()
model = Model
在您的管理类中使用 ModelForm:
class ModelAdmin(admin.ModelAdmin):
form = ModelForm
exclude = ()
fields = (
'my_array_field',
)