我想保存枚举数组。
我有以下内容:
CREATE TABLE public.campaign
(
id integer NOT NULL,
product product[]
)
产品是enum
。
在Django中,我这样定义:
PRODUCT = (
('car', 'car'),
('truck', 'truck')
)
class Campaign(models.Model):
product = ArrayField(models.CharField(null=True, choices=PRODUCT))
但是,当我写下以下内容时:
campaign = Campaign(id=5, product=["car", "truck"])
campaign.save()
我收到以下错误:
ProgrammingError: column "product" is of type product[] but expression is of type text[]
LINE 1: ..."product" = ARRAY['car...
注意 我看到this回答了,但我不使用sqlalchemy,如果不需要,我宁愿不使用它。
EDITED 我尝试下面的@Roman Konoval建议:
class PRODUCT(Enum):
CAR = 'car'
TRUCK = 'truck'
class Campaign(models.Model):
product = ArrayField(EnumField(PRODUCT, max_length=10))
和:
campaign = Campaign(id=5, product=[CAR, TRUCK])
campaign.save()
然而,我仍然得到同样的错误,
我看到django正在将它翻译成字符串列表。 如果我直接在psql控制台上编写以下内容:
INSERT INTO campaign ("product") VALUES ('{car,truck}'::product[])
它运作得很好
答案 0 :(得分:10)
这里有两个基本问题。
如果继续使用枚举,那么Stackoverflow上的下一个问题将是"如何在枚举中添加新条目?"。 Django不支持开箱即用的枚举类型(谢天谢地)。所以你必须使用第三方库。您的里程数将随图书馆的完整程度而变化。
枚举值占用磁盘上的四个字节。枚举的长度 value的文本标签受编译的NAMEDATALEN设置的限制 进入PostgreSQL;在标准版本中,这意味着最多63个字节。
如果您认为使用枚举节省磁盘空间,manual的上述引用表明它是一种错觉。
有关枚举的优点和缺点的更多信息,请参阅此Q&A。但通常缺点超过了优点。
提示:数组不是集合;搜索特定的数组元素即可 数据库错误设计的标志。考虑使用单独的表格 每个项目的行都是一个数组元素。这会更容易 搜索,并可能为大量的更好地扩展 元件。
来源:https://www.postgresql.org/docs/9.6/static/arrays.html
如果您要搜索涉及汽车或卡车的广告系列,您将需要做很多艰苦的工作。数据库也是如此。
正确的设计是postgresql数组文档页面中建议的设计。创建一个相关的表。这也是标准的django方式。
class Campaign(models.Model):
name = models.CharField(max_length=20)
class Product(Models.model):
name = models.CharField(max_length=20)
campaign = models.ForeignKey(Campaign)
这使您的代码更简单。不需要任何额外的存储空间。不需要第三方库。最重要的是django related models的广泛api可供您使用。
答案 1 :(得分:2)
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.data = { amount: ''};
});
app.directive('amountInputCurrency', function () {
var isAllowedKey = function (k, v) {
return (
k === 8 || k === 9 || k === 46 ||
(k > 47 && k < 58) ||
(k > 95 && k < 106) ||
(k > 36 && k < 41) ||
(k === 188 && (!v || v.search(/(\.|\,)/)<0)) ||
((k === 190 || k === 110) && (!v || v.search(/(\.|\,)/)<0))
);
};
return {
restrict: 'E',
// require: 'ngModel',
templateUrl: 'amountInputCurrency.tmpl.html',
scope: {
model: '=',
},
link: function (scope, elem, attrs) {
// scope.model2 = ngModelCtrl;
console.log("I am in the directive!");
var myAmountCurrencyType = elem.find('.cb-amount-input-currency');
myAmountCurrencyType.on('keydown', function (e) {
//if (!isAllowedKey(e.which, scope.model)) {
if (!isAllowedKey(e.which, scope.model)) {
e.preventDefault();
}
});
scope.onFocus = function() {
removeThousandSeparator();
};
scope.onBlur = function() {
renderValue();
// ngModelCtrl.$render();
// scope.model = ngModelCtrl.$viewValue;
};
// //format text going to user (model to view)
// ngModelCtrl.$formatters.push(function(value) {
// return parseValue(value);
// });
// //format text from the user (view to model)
// ngModelCtrl.$parsers.push(function(value) {
// var num = Number(value);
// if(isNumeric(num)) {
// var decimal = 2;
// return formatAmount(Number(num).toFixed(decimal), decimal, ',', '.');
// } else {
// return value;
// }
// });
function isNumeric(val) {
return Number(parseFloat(val))==val;
}
function renderValue() {
var value = String(scope.model || '');
var decimal = attrs.cbAmountDecimal || 2;
if (value != undefined && value !="") {
scope.model = formatAmount(value, decimal, ',', '.');
// ngModelCtrl.$render();
}
}
function formatAmount(amount, c, d, t) {
if (amount.indexOf(',') !== -1) {
if (amount.indexOf('.') !== -1) {
amount = amount.replace(/\./g,''); //remove thousand separator
}
amount = amount.replace(/\,/g,'.');
}
c = isNaN(c = Math.abs(c)) ? 2 : c;
d = d === undefined ? "." : d;
t = t === undefined ? "," : t;
var n = amount,
s = n < 0 ? "-" : "",
i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "",
j = (j = i.length) > 3 ? j % 3 : 0;
return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
}
function removeThousandSeparator() {
if(scope.model != undefined && scope.model !="") {
scope.model = scope.model.replace(/\./g,'');
// ngModelCtrl.$render();
// scope.model = ngModelCtrl.$viewValue;
}
}
function parseValue(viewValue) {
var num = 0;
if(isNumeric(viewValue)) {
num = viewValue;
} else {
num = viewValue ? viewValue.replace(/,/g,'.') : viewValue;
}
return num;
}
}
}
});
字段的定义不正确,因为它指定它是product
s的数组,但它实际上是枚举数组。 Django does not现在支持枚举类型,因此您可以尝试this extension来正确定义类型:
CharField
答案 2 :(得分:2)
试试这个:
def django2psql(s):
return '{'+','.join(s) + '}
campaign = Campaign(id=5, product=django2psql(["car", "truck"]))
答案 3 :(得分:-1)
我认为您可能需要将CharField
子类化,以使其报告正确的db_type
。可能会出现更多问题,但您可以尝试一下:
class Product(models.CharField):
def db_type(self, connection):
return 'product'
PRODUCT = (
('car', 'car'),
('truck', 'truck')
)
class Campaign(models.Model):
product = ArrayField(Product(null=True, choices=PRODUCT))