Now max_length is not required, the Multiselect field calculate it. And max_choices could be a param in the model
This commit is contained in:
parent
cd3ef2e8e7
commit
8c9c3a7682
5 changed files with 95 additions and 20 deletions
|
@ -41,9 +41,10 @@ TAGS_CHOICES = (
|
|||
|
||||
class Book(models.Model):
|
||||
title = models.CharField(max_length=200)
|
||||
categories = MultiSelectField(choices=CATEGORY_CHOICES, max_length=10,
|
||||
null=True, blank=True)
|
||||
tags = MultiSelectField(choices=TAGS_CHOICES, max_length=10)
|
||||
categories = MultiSelectField(choices=CATEGORY_CHOICES,
|
||||
max_choices=3)
|
||||
tags = MultiSelectField(choices=TAGS_CHOICES,
|
||||
null=True, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
|
|
@ -21,7 +21,9 @@ from django.db import models
|
|||
from django.utils.text import capfirst
|
||||
from django.core import exceptions
|
||||
|
||||
from ..forms.fields import MultiSelectFormField
|
||||
from ..forms.fields import MultiSelectFormField, MaxChoicesValidator
|
||||
from ..utils import get_max_length
|
||||
from ..validators import MaxValueMultiFieldValidator
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
string = basestring
|
||||
|
@ -48,11 +50,19 @@ def add_metaclass(metaclass):
|
|||
class MultiSelectField(models.CharField):
|
||||
""" Choice values can not contain commas. """
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.max_choices = kwargs.pop('max_choices', None)
|
||||
super(MultiSelectField, self).__init__(*args, **kwargs)
|
||||
self.max_length = get_max_length(self.choices, self.max_length)
|
||||
self.validators[0] = MaxValueMultiFieldValidator(self.max_length)
|
||||
if self.max_choices is not None:
|
||||
self.validators.append(MaxChoicesValidator(self.max_choices))
|
||||
|
||||
def get_choices_default(self):
|
||||
return self.get_choices(include_blank=False)
|
||||
|
||||
def get_choices_selected(self, arr_choices=''):
|
||||
if not arr_choices:
|
||||
def get_choices_selected(self, arr_choices=None):
|
||||
if arr_choices is None:
|
||||
return False
|
||||
list = []
|
||||
for choice_selected in arr_choices:
|
||||
|
@ -75,8 +85,12 @@ class MultiSelectField(models.CharField):
|
|||
return
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name),
|
||||
'help_text': self.help_text, 'choices': self.choices}
|
||||
defaults = {'required': not self.blank,
|
||||
'label': capfirst(self.verbose_name),
|
||||
'help_text': self.help_text,
|
||||
'choices': self.choices,
|
||||
'max_length': self.max_length,
|
||||
'max_choices': self.max_choices}
|
||||
if self.has_default():
|
||||
defaults['initial'] = self.get_default()
|
||||
defaults.update(kwargs)
|
||||
|
|
|
@ -15,22 +15,19 @@
|
|||
# along with this programe. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django import forms
|
||||
from django.contrib.humanize.templatetags.humanize import apnumber
|
||||
from django.template.defaultfilters import pluralize
|
||||
|
||||
from ..utils import get_max_length
|
||||
from ..validators import MaxValueMultiFieldValidator, MaxChoicesValidator
|
||||
|
||||
|
||||
class MultiSelectFormField(forms.MultipleChoiceField):
|
||||
widget = forms.CheckboxSelectMultiple
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.max_choices = kwargs.pop('max_choices', 0)
|
||||
self.max_choices = kwargs.pop('max_choices', None)
|
||||
self.max_length = kwargs.pop('max_length', None)
|
||||
super(MultiSelectFormField, self).__init__(*args, **kwargs)
|
||||
|
||||
def clean(self, value):
|
||||
if not value and self.required:
|
||||
raise forms.ValidationError(self.error_messages['required'])
|
||||
if value and self.max_choices and len(value) > self.max_choices:
|
||||
raise forms.ValidationError('You must select a maximum of %s choice%s.'
|
||||
% (apnumber(self.max_choices),
|
||||
pluralize(self.max_choices)))
|
||||
return value
|
||||
self.max_length = get_max_length(self.choices, self.max_length)
|
||||
self.validators.append(MaxValueMultiFieldValidator(self.max_length))
|
||||
if self.max_choices is not None:
|
||||
self.validators.append(MaxChoicesValidator(self.max_choices))
|
||||
|
|
34
src/multiselectfield/utils.py
Normal file
34
src/multiselectfield/utils.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2013 by Pablo Martín <goinnn@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this programe. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
string = basestring
|
||||
string_type = unicode
|
||||
else:
|
||||
string = str
|
||||
string_type = string
|
||||
|
||||
|
||||
def get_max_length(choices, max_length, default=200):
|
||||
if max_length is None:
|
||||
if choices:
|
||||
return len(','.join([string_type(key) for key, label in choices]))
|
||||
else:
|
||||
return default
|
||||
return max_length
|
29
src/multiselectfield/validators.py
Normal file
29
src/multiselectfield/validators.py
Normal file
|
@ -0,0 +1,29 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2013 by Pablo Martín <goinnn@gmail.com>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this programe. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from django.core import validators
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class MaxValueMultiFieldValidator(validators.MaxLengthValidator):
|
||||
clean = lambda self, x: len(','.join(x))
|
||||
code = 'max_multifield_value'
|
||||
|
||||
|
||||
class MaxChoicesValidator(validators.MaxLengthValidator):
|
||||
message = _(u'You must select a maximum of %(limit_value)d choices.')
|
||||
code = 'max_choices'
|
Loading…
Reference in a new issue