Weapons. Migrations.
This commit is contained in:
parent
54ab35444e
commit
7b76481d1d
Binary file not shown.
34
app/migrations/0009_auto_20200411_1301.py
Normal file
34
app/migrations/0009_auto_20200411_1301.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
# Generated by Django 3.0.5 on 2020-04-11 13:01
|
||||||
|
|
||||||
|
import app.models
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('app', '0008_auto_20200411_1255'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='itemweaponmelee',
|
||||||
|
name='category',
|
||||||
|
field=app.models.SingleChoiceField(blank=True, choices=[('L', 'Light'), ('M', 'Medium'), ('H', 'Heavy')], max_length=100, verbose_name='Category'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='itemweaponmelee',
|
||||||
|
name='tags',
|
||||||
|
field=app.models.MultiChoiceField(blank=True, choices=[('General', (('ONE HANDED', 'One Handed'), ('TWO HANDED', 'Two Handed'), ('BASHING', 'Bashing'), ('CONCEALABLE', 'Concealable'), ('LETHAL', 'Lethal'), ('MOUNTED', 'Mounted'), ('PIERCING', 'Piercing'), ('SPECIAL', 'Special'))), ('Melee', (('MELEE', 'Melee'), ('BALANCED', 'Balanced'), ('BRAWL', 'Brawl'), ('CHOPPING', 'Chopping'), ('DISARMING', 'Disarming'), ('FLEXIBLE', 'Flexible'), ('IMPROVISED', 'Improvised'), ('GRAPPLING', 'Grappling'), ('MARTIAL ARTS', 'Martial Arts'), ('NATURAL', 'Natural'), ('REACHING', 'Reaching'), ('SHIELD', 'Shield'), ('SMASHING', 'Smashing'), ('WORN', 'Worn'))), ('Thrown', (('THROWN', 'Occult'), ('CUTTING', 'Cutting'), ('POISONABLE', 'Poisonable'), ('SUBTLE', 'Subtle'))), ('Archery', (('ARCHERY', 'Archery'), ('CROSSBOW', 'Crossbow'), ('FLAME', 'Flame'), ('POWERFUL', 'Powerful'), ('SLOW', 'Slow')))], max_length=100, verbose_name='Tags'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='itemweaponranged',
|
||||||
|
name='category',
|
||||||
|
field=app.models.SingleChoiceField(blank=True, choices=[('L', 'Light'), ('M', 'Medium'), ('H', 'Heavy')], max_length=100, verbose_name='Category'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='itemweaponranged',
|
||||||
|
name='tags',
|
||||||
|
field=app.models.MultiChoiceField(blank=True, choices=[('General', (('ONE HANDED', 'One Handed'), ('TWO HANDED', 'Two Handed'), ('BASHING', 'Bashing'), ('CONCEALABLE', 'Concealable'), ('LETHAL', 'Lethal'), ('MOUNTED', 'Mounted'), ('PIERCING', 'Piercing'), ('SPECIAL', 'Special'))), ('Melee', (('MELEE', 'Melee'), ('BALANCED', 'Balanced'), ('BRAWL', 'Brawl'), ('CHOPPING', 'Chopping'), ('DISARMING', 'Disarming'), ('FLEXIBLE', 'Flexible'), ('IMPROVISED', 'Improvised'), ('GRAPPLING', 'Grappling'), ('MARTIAL ARTS', 'Martial Arts'), ('NATURAL', 'Natural'), ('REACHING', 'Reaching'), ('SHIELD', 'Shield'), ('SMASHING', 'Smashing'), ('WORN', 'Worn'))), ('Thrown', (('THROWN', 'Occult'), ('CUTTING', 'Cutting'), ('POISONABLE', 'Poisonable'), ('SUBTLE', 'Subtle'))), ('Archery', (('ARCHERY', 'Archery'), ('CROSSBOW', 'Crossbow'), ('FLAME', 'Flame'), ('POWERFUL', 'Powerful'), ('SLOW', 'Slow')))], max_length=100, verbose_name='Tags'),
|
||||||
|
),
|
||||||
|
]
|
Binary file not shown.
@ -1,4 +1,5 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
import multiselectfield
|
||||||
|
|
||||||
#==============================================================================#
|
#==============================================================================#
|
||||||
#-------------------------------- OPTION LISTS --------------------------------#
|
#-------------------------------- OPTION LISTS --------------------------------#
|
||||||
@ -87,7 +88,7 @@ CATEGORIES = [
|
|||||||
("H", "Heavy"),
|
("H", "Heavy"),
|
||||||
]
|
]
|
||||||
|
|
||||||
TAGS_WEAPON = [
|
TAGS_WEAPONS = [
|
||||||
(
|
(
|
||||||
"General", (
|
"General", (
|
||||||
("ONE HANDED", "One Handed"),
|
("ONE HANDED", "One Handed"),
|
||||||
@ -181,6 +182,14 @@ class SingleChoiceField(models.CharField):
|
|||||||
kwargs['max_length'] = 100
|
kwargs['max_length'] = 100
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
class MultiChoiceField(multiselectfield.MultiSelectField):
|
||||||
|
def __init__(self, verbose_name, choices, *args, **kwargs):
|
||||||
|
kwargs['verbose_name'] = verbose_name
|
||||||
|
kwargs['choices'] = choices
|
||||||
|
kwargs['blank'] = True
|
||||||
|
kwargs['max_length'] = 100
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
class NamedIntegerField(models.IntegerField):
|
class NamedIntegerField(models.IntegerField):
|
||||||
def __init__(self, verbose_name, desc=None, *args, **kwargs):
|
def __init__(self, verbose_name, desc=None, *args, **kwargs):
|
||||||
kwargs['verbose_name'] = verbose_name
|
kwargs['verbose_name'] = verbose_name
|
||||||
@ -196,6 +205,7 @@ class NamedCharField(models.CharField):
|
|||||||
kwargs['max_length'] = 100
|
kwargs['max_length'] = 100
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
#==============================================================================#
|
#==============================================================================#
|
||||||
#--------------------------------- MODIFIERS ----------------------------------#
|
#--------------------------------- MODIFIERS ----------------------------------#
|
||||||
#==============================================================================#
|
#==============================================================================#
|
||||||
@ -233,8 +243,8 @@ class itemWeaponBase(itemBase):
|
|||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
# category
|
category = SingleChoiceField("Category", CATEGORIES)
|
||||||
# tags
|
tags = MultiChoiceField("Tags", TAGS_WEAPONS)
|
||||||
accuracy = NamedIntegerField("Accuracy")
|
accuracy = NamedIntegerField("Accuracy")
|
||||||
damage = NamedIntegerField("Damage")
|
damage = NamedIntegerField("Damage")
|
||||||
defense = NamedIntegerField("Defense")
|
defense = NamedIntegerField("Defense")
|
||||||
|
@ -0,0 +1,269 @@
|
|||||||
|
django-multiselectfield
|
||||||
|
=======================
|
||||||
|
|
||||||
|
.. image:: https://travis-ci.org/goinnn/django-multiselectfield.png?branch=master
|
||||||
|
:target: https://travis-ci.org/goinnn/django-multiselectfield
|
||||||
|
|
||||||
|
.. image:: https://coveralls.io/repos/goinnn/django-multiselectfield/badge.png?branch=master
|
||||||
|
:target: https://coveralls.io/r/goinnn/django-multiselectfield
|
||||||
|
|
||||||
|
.. image:: https://badge.fury.io/py/django-multiselectfield.png
|
||||||
|
:target: https://badge.fury.io/py/django-multiselectfield
|
||||||
|
|
||||||
|
A new model field and form field. With this you can get a multiple select from a choices. Stores to the database as a CharField of comma-separated values.
|
||||||
|
|
||||||
|
This egg is inspired by this `snippet <http://djangosnippets.org/snippets/1200/>`_.
|
||||||
|
|
||||||
|
Supported Python versions: 2.7, 3.4+
|
||||||
|
|
||||||
|
Supported Django versions: 1.4-2.0+
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
|
||||||
|
Install with pip
|
||||||
|
----------------
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ pip install django-multiselectfield
|
||||||
|
|
||||||
|
Configure your models.py
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from multiselectfield import MultiSelectField
|
||||||
|
|
||||||
|
# ...
|
||||||
|
|
||||||
|
MY_CHOICES = (('item_key1', 'Item title 1.1'),
|
||||||
|
('item_key2', 'Item title 1.2'),
|
||||||
|
('item_key3', 'Item title 1.3'),
|
||||||
|
('item_key4', 'Item title 1.4'),
|
||||||
|
('item_key5', 'Item title 1.5'))
|
||||||
|
|
||||||
|
MY_CHOICES2 = ((1, 'Item title 2.1'),
|
||||||
|
(2, 'Item title 2.2'),
|
||||||
|
(3, 'Item title 2.3'),
|
||||||
|
(4, 'Item title 2.4'),
|
||||||
|
(5, 'Item title 2.5'))
|
||||||
|
|
||||||
|
class MyModel(models.Model):
|
||||||
|
|
||||||
|
# .....
|
||||||
|
|
||||||
|
my_field = MultiSelectField(choices=MY_CHOICES)
|
||||||
|
my_field2 = MultiSelectField(choices=MY_CHOICES2,
|
||||||
|
max_choices=3,
|
||||||
|
max_length=3)
|
||||||
|
|
||||||
|
|
||||||
|
In your settings.py
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Only you need it, if you want the translation of django-multiselectfield
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
INSTALLED_APPS = (
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.sites',
|
||||||
|
'django.contrib.admin',
|
||||||
|
|
||||||
|
#.....................#
|
||||||
|
|
||||||
|
'multiselectfield',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
Customizing templates
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
It is possible to customize the HTML of this widget in your form template. To do so, you will need to loop through ``form.{field}.field.choices``. Here is an example that displays the field label underneath/after the checkbox for a ``MultiSelectField`` called ``providers``:
|
||||||
|
|
||||||
|
.. code-block:: HTML+Django
|
||||||
|
|
||||||
|
{% for value, text in form.providers.field.choices %}
|
||||||
|
<div class="ui slider checkbox">
|
||||||
|
<input id="id_providers_{{ forloop.counter0 }}" name="{{ form.providers.name }}" type="checkbox" value="{{ value }}"{% if value in checked_providers %} checked="checked"{% endif %}>
|
||||||
|
<label>{{ text }}</label>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
Django REST Framework
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Django REST Framework comes with a ``MultipleChoiceField`` that works perfectly with this:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from rest_framework import fields, serializers
|
||||||
|
|
||||||
|
from myapp.models import MY_CHOICES, MY_CHOICES2
|
||||||
|
|
||||||
|
class MyModelSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
|
# ...
|
||||||
|
my_field = fields.MultipleChoiceField(choices=MY_CHOICES)
|
||||||
|
my_field2 = fields.MultipleChoiceField(choices=MY_CHOICES2)
|
||||||
|
# ...
|
||||||
|
|
||||||
|
|
||||||
|
Known Bugs and Limitations
|
||||||
|
==========================
|
||||||
|
|
||||||
|
All tests pass on Django 1.4, 1.5, and 1.8+, so if you can, use a modern version of Django. However, if you must use Django 1.6 or 1.7 there are two known issues you will need to be aware of:
|
||||||
|
|
||||||
|
1. `Named groups <https://github.com/goinnn/django-multiselectfield/pull/30#issue-52149983>`_ do not render properly in Django 1.6. The workaround is to manually render the field in your form or use a custom widget. If your workaround is suitably generic, please submit a pull request with it.
|
||||||
|
|
||||||
|
2. Only in Django 1.6 and 1.7, due to `Django bug #9619 <https://code.djangoproject.com/ticket/9619>`_, passing a MultiSelectField to ``values()`` or ``values_list()`` will return the database representation of the field (a string of comma-separated values). The workaround is to manually call ``.split(',')`` on the result.
|
||||||
|
|
||||||
|
The Django bug was introduced in Django 1.6 and is fixed in Django 1.8 and onward, so ``values()`` and ``values_list()`` return a vanilla Python list of values for Django <= 1.5 and Django >= 1.8.
|
||||||
|
|
||||||
|
See `issue #40 <https://github.com/goinnn/django-multiselectfield/issues/40>`_ for discussion about this bug.
|
||||||
|
|
||||||
|
|
||||||
|
Development
|
||||||
|
===========
|
||||||
|
|
||||||
|
You can get the last bleeding edge version of django-multiselectfield by doing a clone
|
||||||
|
of its git repository:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
git clone https://github.com/goinnn/django-multiselectfield
|
||||||
|
|
||||||
|
|
||||||
|
Example project
|
||||||
|
===============
|
||||||
|
|
||||||
|
There is a fully configured example project in the `example directory <https://github.com/goinnn/django-multiselectfield/tree/master/example/>`_. You can run it as usual:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
python manage.py migrate # or python manage.py syncdb --noinput
|
||||||
|
python manage.py loaddata app_data
|
||||||
|
python manage.py runserver
|
||||||
|
|
||||||
|
|
||||||
|
0.1.12 (2020-02-20)
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
* Optimize multiselectfield to_python method
|
||||||
|
* Thanks to:
|
||||||
|
* `daimon99 <https://github.com/daimon99>`_
|
||||||
|
|
||||||
|
0.1.11 (2019-12-19)
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
* Added support for Django 3
|
||||||
|
* Added support for Python 3.8
|
||||||
|
* Thanks to:
|
||||||
|
* `thijsBoehme <https://github.com/thijsBoehme>`_
|
||||||
|
|
||||||
|
0.1.9 (2019-10-02)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Added support for Django 2
|
||||||
|
* Added support for Python 3.6
|
||||||
|
* Drop support for Python (2.6, 3.3)
|
||||||
|
* Thanks to:
|
||||||
|
* `hirokinko <https://github.com/hirokinko>`_
|
||||||
|
|
||||||
|
0.1.6 (2017-05-10)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Added support for Django 1.11
|
||||||
|
* Added support for Python 3.6
|
||||||
|
* Improved rendering in Django admin
|
||||||
|
* Improved documentation
|
||||||
|
* Thanks to:
|
||||||
|
* `atten <https://github.com/atten>`_
|
||||||
|
* `ixc <https://github.comixc>`_
|
||||||
|
* `LeilaniAnn <https://github.comLeilaniAnn>`_
|
||||||
|
|
||||||
|
0.1.5 (2017-01-02)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Added support for Django 1.8-1.10
|
||||||
|
* Added support for named groups in choices
|
||||||
|
* Added support for min_choices argument
|
||||||
|
* Various fixes
|
||||||
|
* More tests
|
||||||
|
* Thanks to:
|
||||||
|
* `danilogbotelho <https://github.comdanilogbotelho>`_
|
||||||
|
* `dmitry-krasilnikov <https://github.comdmitry-krasilnikov>`_
|
||||||
|
* `Kamil Dębowski <https://github.comkdebowski>`_
|
||||||
|
|
||||||
|
0.1.4 (2016-02-23)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Fixed warning about SubfieldBase
|
||||||
|
* Added support for Django 1.8+
|
||||||
|
* Added support for named groups
|
||||||
|
* We now play nice with django-dynamic-fixture
|
||||||
|
* More tests
|
||||||
|
|
||||||
|
0.1.3 (2014-10-13)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Support to Django 1.7 (I'm sorry to the delay)
|
||||||
|
* Adding get_FIELD_list function
|
||||||
|
* Fix an error when a MultiSelectField was reandonly at the admin site
|
||||||
|
* Thanks to:
|
||||||
|
* `Hernil <https://github.com/hernil>`_
|
||||||
|
* `Vasyl Stanislavchuk <https://github.com/vasyabigi>`_
|
||||||
|
* `Litchfield <https://github.com/litchfield/>`_
|
||||||
|
* `Chris-erickson <https://github.com/chris-erickson>`_
|
||||||
|
|
||||||
|
0.1.2 (2014-04-04)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Include the spanish translations to the pypi egg
|
||||||
|
* Improvements in the readme file
|
||||||
|
* Windows OS compatibility
|
||||||
|
* Thanks to:
|
||||||
|
* `StillNewb <https://github.com/StillNewb>`_
|
||||||
|
* `Diego Yungh <https://github.com/DiegoYungh>`_
|
||||||
|
|
||||||
|
0.1.1 (2013-12-04)
|
||||||
|
------------------
|
||||||
|
* Move the multiselectfield app to parent folder
|
||||||
|
* Details
|
||||||
|
|
||||||
|
0.1.0 (2013-11-30)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Test/example project
|
||||||
|
* Now works if the first composant of the list of tuple is an integer
|
||||||
|
* Now max_length is not required, the Multiselect field calculate it automatically.
|
||||||
|
* The max_choices attr can be a attr in the model field
|
||||||
|
* Refactor the code
|
||||||
|
* Spanish translations
|
||||||
|
* Support to python2.6
|
||||||
|
* Thanks to:
|
||||||
|
* `Daniele Procida <https://github.com/evildmp>`_
|
||||||
|
|
||||||
|
0.0.3 (2013-09-11)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Python 3 compatible
|
||||||
|
* Fix an error, the snippet had another error when the choices were translatables
|
||||||
|
* Improvements in the README file
|
||||||
|
|
||||||
|
|
||||||
|
0.0.2 (2012-09-28)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Fix an error, the snippet had an error.
|
||||||
|
|
||||||
|
0.0.1 (2012-09-27)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Initial version from the next `snippet <http://djangosnippets.org/snippets/1200/>`_
|
||||||
|
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
pip
|
@ -0,0 +1,294 @@
|
|||||||
|
Metadata-Version: 2.0
|
||||||
|
Name: django-multiselectfield
|
||||||
|
Version: 0.1.12
|
||||||
|
Summary: Django multiple select field
|
||||||
|
Home-page: https://github.com/goinnn/django-multiselectfield
|
||||||
|
Author: Pablo Martin
|
||||||
|
Author-email: goinnn@gmail.com
|
||||||
|
License: LGPL 3
|
||||||
|
Keywords: django,multiple,select,field,choices
|
||||||
|
Platform: UNKNOWN
|
||||||
|
Classifier: Development Status :: 4 - Beta
|
||||||
|
Classifier: Framework :: Django
|
||||||
|
Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
|
||||||
|
Classifier: Programming Language :: Python :: 2
|
||||||
|
Classifier: Programming Language :: Python :: 2.6
|
||||||
|
Classifier: Programming Language :: Python :: 2.7
|
||||||
|
Classifier: Programming Language :: Python :: 3
|
||||||
|
Classifier: Programming Language :: Python :: 3.3
|
||||||
|
Classifier: Programming Language :: Python :: 3.4
|
||||||
|
Classifier: Programming Language :: Python :: 3.5
|
||||||
|
Classifier: Programming Language :: Python :: 3.6
|
||||||
|
Classifier: Programming Language :: Python :: 3.7
|
||||||
|
Classifier: Programming Language :: Python :: 3.8
|
||||||
|
Requires-Dist: django (>=1.4)
|
||||||
|
|
||||||
|
django-multiselectfield
|
||||||
|
=======================
|
||||||
|
|
||||||
|
.. image:: https://travis-ci.org/goinnn/django-multiselectfield.png?branch=master
|
||||||
|
:target: https://travis-ci.org/goinnn/django-multiselectfield
|
||||||
|
|
||||||
|
.. image:: https://coveralls.io/repos/goinnn/django-multiselectfield/badge.png?branch=master
|
||||||
|
:target: https://coveralls.io/r/goinnn/django-multiselectfield
|
||||||
|
|
||||||
|
.. image:: https://badge.fury.io/py/django-multiselectfield.png
|
||||||
|
:target: https://badge.fury.io/py/django-multiselectfield
|
||||||
|
|
||||||
|
A new model field and form field. With this you can get a multiple select from a choices. Stores to the database as a CharField of comma-separated values.
|
||||||
|
|
||||||
|
This egg is inspired by this `snippet <http://djangosnippets.org/snippets/1200/>`_.
|
||||||
|
|
||||||
|
Supported Python versions: 2.7, 3.4+
|
||||||
|
|
||||||
|
Supported Django versions: 1.4-2.0+
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
|
||||||
|
Install with pip
|
||||||
|
----------------
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ pip install django-multiselectfield
|
||||||
|
|
||||||
|
Configure your models.py
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from multiselectfield import MultiSelectField
|
||||||
|
|
||||||
|
# ...
|
||||||
|
|
||||||
|
MY_CHOICES = (('item_key1', 'Item title 1.1'),
|
||||||
|
('item_key2', 'Item title 1.2'),
|
||||||
|
('item_key3', 'Item title 1.3'),
|
||||||
|
('item_key4', 'Item title 1.4'),
|
||||||
|
('item_key5', 'Item title 1.5'))
|
||||||
|
|
||||||
|
MY_CHOICES2 = ((1, 'Item title 2.1'),
|
||||||
|
(2, 'Item title 2.2'),
|
||||||
|
(3, 'Item title 2.3'),
|
||||||
|
(4, 'Item title 2.4'),
|
||||||
|
(5, 'Item title 2.5'))
|
||||||
|
|
||||||
|
class MyModel(models.Model):
|
||||||
|
|
||||||
|
# .....
|
||||||
|
|
||||||
|
my_field = MultiSelectField(choices=MY_CHOICES)
|
||||||
|
my_field2 = MultiSelectField(choices=MY_CHOICES2,
|
||||||
|
max_choices=3,
|
||||||
|
max_length=3)
|
||||||
|
|
||||||
|
|
||||||
|
In your settings.py
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Only you need it, if you want the translation of django-multiselectfield
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
INSTALLED_APPS = (
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.sites',
|
||||||
|
'django.contrib.admin',
|
||||||
|
|
||||||
|
#.....................#
|
||||||
|
|
||||||
|
'multiselectfield',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
Customizing templates
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
It is possible to customize the HTML of this widget in your form template. To do so, you will need to loop through ``form.{field}.field.choices``. Here is an example that displays the field label underneath/after the checkbox for a ``MultiSelectField`` called ``providers``:
|
||||||
|
|
||||||
|
.. code-block:: HTML+Django
|
||||||
|
|
||||||
|
{% for value, text in form.providers.field.choices %}
|
||||||
|
<div class="ui slider checkbox">
|
||||||
|
<input id="id_providers_{{ forloop.counter0 }}" name="{{ form.providers.name }}" type="checkbox" value="{{ value }}"{% if value in checked_providers %} checked="checked"{% endif %}>
|
||||||
|
<label>{{ text }}</label>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
Django REST Framework
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Django REST Framework comes with a ``MultipleChoiceField`` that works perfectly with this:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from rest_framework import fields, serializers
|
||||||
|
|
||||||
|
from myapp.models import MY_CHOICES, MY_CHOICES2
|
||||||
|
|
||||||
|
class MyModelSerializer(serializers.HyperlinkedModelSerializer):
|
||||||
|
# ...
|
||||||
|
my_field = fields.MultipleChoiceField(choices=MY_CHOICES)
|
||||||
|
my_field2 = fields.MultipleChoiceField(choices=MY_CHOICES2)
|
||||||
|
# ...
|
||||||
|
|
||||||
|
|
||||||
|
Known Bugs and Limitations
|
||||||
|
==========================
|
||||||
|
|
||||||
|
All tests pass on Django 1.4, 1.5, and 1.8+, so if you can, use a modern version of Django. However, if you must use Django 1.6 or 1.7 there are two known issues you will need to be aware of:
|
||||||
|
|
||||||
|
1. `Named groups <https://github.com/goinnn/django-multiselectfield/pull/30#issue-52149983>`_ do not render properly in Django 1.6. The workaround is to manually render the field in your form or use a custom widget. If your workaround is suitably generic, please submit a pull request with it.
|
||||||
|
|
||||||
|
2. Only in Django 1.6 and 1.7, due to `Django bug #9619 <https://code.djangoproject.com/ticket/9619>`_, passing a MultiSelectField to ``values()`` or ``values_list()`` will return the database representation of the field (a string of comma-separated values). The workaround is to manually call ``.split(',')`` on the result.
|
||||||
|
|
||||||
|
The Django bug was introduced in Django 1.6 and is fixed in Django 1.8 and onward, so ``values()`` and ``values_list()`` return a vanilla Python list of values for Django <= 1.5 and Django >= 1.8.
|
||||||
|
|
||||||
|
See `issue #40 <https://github.com/goinnn/django-multiselectfield/issues/40>`_ for discussion about this bug.
|
||||||
|
|
||||||
|
|
||||||
|
Development
|
||||||
|
===========
|
||||||
|
|
||||||
|
You can get the last bleeding edge version of django-multiselectfield by doing a clone
|
||||||
|
of its git repository:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
git clone https://github.com/goinnn/django-multiselectfield
|
||||||
|
|
||||||
|
|
||||||
|
Example project
|
||||||
|
===============
|
||||||
|
|
||||||
|
There is a fully configured example project in the `example directory <https://github.com/goinnn/django-multiselectfield/tree/master/example/>`_. You can run it as usual:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
python manage.py migrate # or python manage.py syncdb --noinput
|
||||||
|
python manage.py loaddata app_data
|
||||||
|
python manage.py runserver
|
||||||
|
|
||||||
|
|
||||||
|
0.1.12 (2020-02-20)
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
* Optimize multiselectfield to_python method
|
||||||
|
* Thanks to:
|
||||||
|
* `daimon99 <https://github.com/daimon99>`_
|
||||||
|
|
||||||
|
0.1.11 (2019-12-19)
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
* Added support for Django 3
|
||||||
|
* Added support for Python 3.8
|
||||||
|
* Thanks to:
|
||||||
|
* `thijsBoehme <https://github.com/thijsBoehme>`_
|
||||||
|
|
||||||
|
0.1.9 (2019-10-02)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Added support for Django 2
|
||||||
|
* Added support for Python 3.6
|
||||||
|
* Drop support for Python (2.6, 3.3)
|
||||||
|
* Thanks to:
|
||||||
|
* `hirokinko <https://github.com/hirokinko>`_
|
||||||
|
|
||||||
|
0.1.6 (2017-05-10)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Added support for Django 1.11
|
||||||
|
* Added support for Python 3.6
|
||||||
|
* Improved rendering in Django admin
|
||||||
|
* Improved documentation
|
||||||
|
* Thanks to:
|
||||||
|
* `atten <https://github.com/atten>`_
|
||||||
|
* `ixc <https://github.comixc>`_
|
||||||
|
* `LeilaniAnn <https://github.comLeilaniAnn>`_
|
||||||
|
|
||||||
|
0.1.5 (2017-01-02)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Added support for Django 1.8-1.10
|
||||||
|
* Added support for named groups in choices
|
||||||
|
* Added support for min_choices argument
|
||||||
|
* Various fixes
|
||||||
|
* More tests
|
||||||
|
* Thanks to:
|
||||||
|
* `danilogbotelho <https://github.comdanilogbotelho>`_
|
||||||
|
* `dmitry-krasilnikov <https://github.comdmitry-krasilnikov>`_
|
||||||
|
* `Kamil Dębowski <https://github.comkdebowski>`_
|
||||||
|
|
||||||
|
0.1.4 (2016-02-23)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Fixed warning about SubfieldBase
|
||||||
|
* Added support for Django 1.8+
|
||||||
|
* Added support for named groups
|
||||||
|
* We now play nice with django-dynamic-fixture
|
||||||
|
* More tests
|
||||||
|
|
||||||
|
0.1.3 (2014-10-13)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Support to Django 1.7 (I'm sorry to the delay)
|
||||||
|
* Adding get_FIELD_list function
|
||||||
|
* Fix an error when a MultiSelectField was reandonly at the admin site
|
||||||
|
* Thanks to:
|
||||||
|
* `Hernil <https://github.com/hernil>`_
|
||||||
|
* `Vasyl Stanislavchuk <https://github.com/vasyabigi>`_
|
||||||
|
* `Litchfield <https://github.com/litchfield/>`_
|
||||||
|
* `Chris-erickson <https://github.com/chris-erickson>`_
|
||||||
|
|
||||||
|
0.1.2 (2014-04-04)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Include the spanish translations to the pypi egg
|
||||||
|
* Improvements in the readme file
|
||||||
|
* Windows OS compatibility
|
||||||
|
* Thanks to:
|
||||||
|
* `StillNewb <https://github.com/StillNewb>`_
|
||||||
|
* `Diego Yungh <https://github.com/DiegoYungh>`_
|
||||||
|
|
||||||
|
0.1.1 (2013-12-04)
|
||||||
|
------------------
|
||||||
|
* Move the multiselectfield app to parent folder
|
||||||
|
* Details
|
||||||
|
|
||||||
|
0.1.0 (2013-11-30)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Test/example project
|
||||||
|
* Now works if the first composant of the list of tuple is an integer
|
||||||
|
* Now max_length is not required, the Multiselect field calculate it automatically.
|
||||||
|
* The max_choices attr can be a attr in the model field
|
||||||
|
* Refactor the code
|
||||||
|
* Spanish translations
|
||||||
|
* Support to python2.6
|
||||||
|
* Thanks to:
|
||||||
|
* `Daniele Procida <https://github.com/evildmp>`_
|
||||||
|
|
||||||
|
0.0.3 (2013-09-11)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Python 3 compatible
|
||||||
|
* Fix an error, the snippet had another error when the choices were translatables
|
||||||
|
* Improvements in the README file
|
||||||
|
|
||||||
|
|
||||||
|
0.0.2 (2012-09-28)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Fix an error, the snippet had an error.
|
||||||
|
|
||||||
|
0.0.1 (2012-09-27)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Initial version from the next `snippet <http://djangosnippets.org/snippets/1200/>`_
|
||||||
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
|||||||
|
django_multiselectfield-0.1.12.dist-info/DESCRIPTION.rst,sha256=QjtRluOTQmWzudG8mNHhBKQb7foYzHq7ZxCs3PAx1bM,8179
|
||||||
|
django_multiselectfield-0.1.12.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||||
|
django_multiselectfield-0.1.12.dist-info/METADATA,sha256=PF35_c0b7aDHBn_nVLS8Hs63e_S6wRZTs0khOvADJ4Q,9172
|
||||||
|
django_multiselectfield-0.1.12.dist-info/RECORD,,
|
||||||
|
django_multiselectfield-0.1.12.dist-info/WHEEL,sha256=8Lm45v9gcYRm70DrgFGVe4WsUtUMi1_0Tso1hqPGMjA,92
|
||||||
|
django_multiselectfield-0.1.12.dist-info/metadata.json,sha256=1R2BnZqhvSNaPVMsgYuBM9Hn50w_spOvHiwh7IdYYfk,1216
|
||||||
|
django_multiselectfield-0.1.12.dist-info/top_level.txt,sha256=Y5vMmoRWcEEnorayclFbrq60Hy-7-EM5TAhBEw-rlec,17
|
||||||
|
multiselectfield/__init__.py,sha256=YhzWaV3qo676EhtgUXuwWZBggKuLuls_8G2ytQqHBmY,217
|
||||||
|
multiselectfield/__pycache__/__init__.cpython-38.pyc,,
|
||||||
|
multiselectfield/__pycache__/apps.cpython-38.pyc,,
|
||||||
|
multiselectfield/__pycache__/utils.cpython-38.pyc,,
|
||||||
|
multiselectfield/__pycache__/validators.cpython-38.pyc,,
|
||||||
|
multiselectfield/apps.py,sha256=qcW5RvrLleieNOz4swZ1QA5SCvX7zDHwY4QcoNr9y30,146
|
||||||
|
multiselectfield/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||||
|
multiselectfield/db/__pycache__/__init__.cpython-38.pyc,,
|
||||||
|
multiselectfield/db/__pycache__/fields.cpython-38.pyc,,
|
||||||
|
multiselectfield/db/fields.py,sha256=tRm8Ux8aJZJ3Oacr7AYpnN6c88b1u7MgmP0lg-KPi10,7959
|
||||||
|
multiselectfield/forms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||||
|
multiselectfield/forms/__pycache__/__init__.cpython-38.pyc,,
|
||||||
|
multiselectfield/forms/__pycache__/fields.cpython-38.pyc,,
|
||||||
|
multiselectfield/forms/fields.py,sha256=dqaqK9bWwuRpJKBE1DcmsydcqU0OH0RGK3XXrOF-9XA,1659
|
||||||
|
multiselectfield/locale/es/LC_MESSAGES/django.mo,sha256=xqKsXhCPHi0YJI_s5ug4syKyoDGdQ_TEwuZzRZoiWNM,564
|
||||||
|
multiselectfield/locale/es/LC_MESSAGES/django.po,sha256=5uPlVcG897BqGXxBk-pPleMWUAypNVsZsf8s6JlERVk,770
|
||||||
|
multiselectfield/utils.py,sha256=Ojf4Iomw9dheF3ZaHQ_oNB3RsA-d-X3uHtZX95HfDJo,1153
|
||||||
|
multiselectfield/validators.py,sha256=E4xwHf56W_WtQ3nE_6WUPUl_DDLrMKjBB9ZKSSvbQfM,1310
|
@ -0,0 +1,5 @@
|
|||||||
|
Wheel-Version: 1.0
|
||||||
|
Generator: bdist_wheel (0.30.0)
|
||||||
|
Root-Is-Purelib: true
|
||||||
|
Tag: py3-none-any
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
{"classifiers": ["Development Status :: 4 - Beta", "Framework :: Django", "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8"], "extensions": {"python.details": {"contacts": [{"email": "goinnn@gmail.com", "name": "Pablo Martin", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/goinnn/django-multiselectfield"}}}, "extras": [], "generator": "bdist_wheel (0.30.0)", "keywords": ["django", "multiple", "select", "field", "choices"], "license": "LGPL 3", "metadata_version": "2.0", "name": "django-multiselectfield", "run_requires": [{"requires": ["django (>=1.4)"]}], "summary": "Django multiple select field", "test_requires": [{"requires": ["coverage", "django (>=1.4)", "flake8", "tox"]}], "version": "0.1.12"}
|
@ -0,0 +1 @@
|
|||||||
|
multiselectfield
|
@ -0,0 +1,5 @@
|
|||||||
|
from multiselectfield.db.fields import MultiSelectField # noqa: F401
|
||||||
|
from multiselectfield.forms.fields import MultiSelectFormField # noqa: F401
|
||||||
|
|
||||||
|
|
||||||
|
default_app_config = 'multiselectfield.apps.MultiSelectFieldConfig'
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class MultiSelectFieldConfig(AppConfig):
|
||||||
|
name = 'multiselectfield'
|
||||||
|
verbose_name = 'Multiselect Field'
|
Binary file not shown.
Binary file not shown.
205
venv/lib/python3.8/site-packages/multiselectfield/db/fields.py
Normal file
205
venv/lib/python3.8/site-packages/multiselectfield/db/fields.py
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2012 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
|
||||||
|
|
||||||
|
from django import VERSION
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.text import capfirst
|
||||||
|
from django.core import exceptions
|
||||||
|
|
||||||
|
from ..forms.fields import MultiSelectFormField, MinChoicesValidator, MaxChoicesValidator
|
||||||
|
from ..utils import get_max_length
|
||||||
|
from ..validators import MaxValueMultiFieldValidator
|
||||||
|
|
||||||
|
if sys.version_info < (3,):
|
||||||
|
string_type = unicode # noqa: F821
|
||||||
|
else:
|
||||||
|
string_type = str
|
||||||
|
|
||||||
|
# Code from six egg https://bitbucket.org/gutworth/six/src/a3641cb211cc360848f1e2dd92e9ae6cd1de55dd/six.py?at=default
|
||||||
|
|
||||||
|
|
||||||
|
def add_metaclass(metaclass):
|
||||||
|
"""Class decorator for creating a class with a metaclass."""
|
||||||
|
def wrapper(cls):
|
||||||
|
orig_vars = cls.__dict__.copy()
|
||||||
|
orig_vars.pop('__dict__', None)
|
||||||
|
orig_vars.pop('__weakref__', None)
|
||||||
|
for slots_var in orig_vars.get('__slots__', ()):
|
||||||
|
orig_vars.pop(slots_var)
|
||||||
|
return metaclass(cls.__name__, cls.__bases__, orig_vars)
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
class MSFList(list):
|
||||||
|
|
||||||
|
def __init__(self, choices, *args, **kwargs):
|
||||||
|
self.choices = choices
|
||||||
|
super(MSFList, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def __str__(msgl):
|
||||||
|
msg_list = [msgl.choices.get(int(i)) if i.isdigit() else msgl.choices.get(i) for i in msgl]
|
||||||
|
return u', '.join([string_type(s) for s in msg_list])
|
||||||
|
|
||||||
|
if sys.version_info < (3,):
|
||||||
|
def __unicode__(self, msgl):
|
||||||
|
return self.__str__(msgl)
|
||||||
|
|
||||||
|
|
||||||
|
class MultiSelectField(models.CharField):
|
||||||
|
""" Choice values can not contain commas. """
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.min_choices = kwargs.pop('min_choices', None)
|
||||||
|
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.min_choices is not None:
|
||||||
|
self.validators.append(MinChoicesValidator(self.min_choices))
|
||||||
|
if self.max_choices is not None:
|
||||||
|
self.validators.append(MaxChoicesValidator(self.max_choices))
|
||||||
|
|
||||||
|
def _get_flatchoices(self):
|
||||||
|
flat_choices = super(MultiSelectField, self)._get_flatchoices()
|
||||||
|
|
||||||
|
class MSFFlatchoices(list):
|
||||||
|
# Used to trick django.contrib.admin.utils.display_for_field into
|
||||||
|
# not treating the list of values as a dictionary key (which errors
|
||||||
|
# out)
|
||||||
|
def __bool__(self):
|
||||||
|
return False
|
||||||
|
__nonzero__ = __bool__
|
||||||
|
return MSFFlatchoices(flat_choices)
|
||||||
|
flatchoices = property(_get_flatchoices)
|
||||||
|
|
||||||
|
def get_choices_default(self):
|
||||||
|
return self.get_choices(include_blank=False)
|
||||||
|
|
||||||
|
def get_choices_selected(self, arr_choices):
|
||||||
|
named_groups = arr_choices and isinstance(arr_choices[0][1], (list, tuple))
|
||||||
|
choices_selected = []
|
||||||
|
if named_groups:
|
||||||
|
for choice_group_selected in arr_choices:
|
||||||
|
for choice_selected in choice_group_selected[1]:
|
||||||
|
choices_selected.append(string_type(choice_selected[0]))
|
||||||
|
else:
|
||||||
|
for choice_selected in arr_choices:
|
||||||
|
choices_selected.append(string_type(choice_selected[0]))
|
||||||
|
return choices_selected
|
||||||
|
|
||||||
|
def value_to_string(self, obj):
|
||||||
|
try:
|
||||||
|
value = self._get_val_from_obj(obj)
|
||||||
|
except AttributeError:
|
||||||
|
value = super(MultiSelectField, self).value_from_object(obj)
|
||||||
|
return self.get_prep_value(value)
|
||||||
|
|
||||||
|
def validate(self, value, model_instance):
|
||||||
|
arr_choices = self.get_choices_selected(self.get_choices_default())
|
||||||
|
for opt_select in value:
|
||||||
|
if (opt_select not in arr_choices):
|
||||||
|
if VERSION >= (1, 6):
|
||||||
|
raise exceptions.ValidationError(self.error_messages['invalid_choice'] % {"value": value})
|
||||||
|
else:
|
||||||
|
raise exceptions.ValidationError(self.error_messages['invalid_choice'] % value)
|
||||||
|
|
||||||
|
def get_default(self):
|
||||||
|
default = super(MultiSelectField, self).get_default()
|
||||||
|
if isinstance(default, int):
|
||||||
|
default = string_type(default)
|
||||||
|
return default
|
||||||
|
|
||||||
|
def formfield(self, **kwargs):
|
||||||
|
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)
|
||||||
|
return MultiSelectFormField(**defaults)
|
||||||
|
|
||||||
|
def get_prep_value(self, value):
|
||||||
|
return '' if value is None else ",".join(map(str, value))
|
||||||
|
|
||||||
|
def get_db_prep_value(self, value, connection, prepared=False):
|
||||||
|
if not prepared and not isinstance(value, string_type):
|
||||||
|
value = self.get_prep_value(value)
|
||||||
|
return value
|
||||||
|
|
||||||
|
def to_python(self, value):
|
||||||
|
choices = dict(self.flatchoices)
|
||||||
|
|
||||||
|
if value:
|
||||||
|
if isinstance(value, list):
|
||||||
|
return value
|
||||||
|
elif isinstance(value, string_type):
|
||||||
|
value_list = map(lambda x: x.strip(), value.replace(u',', ',').split(','))
|
||||||
|
return MSFList(choices, value_list)
|
||||||
|
elif isinstance(value, (set, dict)):
|
||||||
|
return MSFList(choices, list(value))
|
||||||
|
return MSFList(choices, [])
|
||||||
|
|
||||||
|
if VERSION < (2, ):
|
||||||
|
def from_db_value(self, value, expression, connection, context):
|
||||||
|
if value is None:
|
||||||
|
return value
|
||||||
|
return self.to_python(value)
|
||||||
|
else:
|
||||||
|
def from_db_value(self, value, expression, connection):
|
||||||
|
if value is None:
|
||||||
|
return value
|
||||||
|
return self.to_python(value)
|
||||||
|
|
||||||
|
def contribute_to_class(self, cls, name):
|
||||||
|
super(MultiSelectField, self).contribute_to_class(cls, name)
|
||||||
|
if self.choices:
|
||||||
|
def get_list(obj):
|
||||||
|
fieldname = name
|
||||||
|
choicedict = dict(self.choices)
|
||||||
|
display = []
|
||||||
|
if getattr(obj, fieldname):
|
||||||
|
for value in getattr(obj, fieldname):
|
||||||
|
item_display = choicedict.get(value, None)
|
||||||
|
if item_display is None:
|
||||||
|
try:
|
||||||
|
item_display = choicedict.get(int(value), value)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
item_display = value
|
||||||
|
display.append(string_type(item_display))
|
||||||
|
return display
|
||||||
|
|
||||||
|
def get_display(obj):
|
||||||
|
return ", ".join(get_list(obj))
|
||||||
|
get_display.short_description = self.verbose_name
|
||||||
|
|
||||||
|
setattr(cls, 'get_%s_list' % self.name, get_list)
|
||||||
|
setattr(cls, 'get_%s_display' % self.name, get_display)
|
||||||
|
|
||||||
|
|
||||||
|
if VERSION < (1, 8):
|
||||||
|
MultiSelectField = add_metaclass(models.SubfieldBase)(MultiSelectField)
|
||||||
|
|
||||||
|
try:
|
||||||
|
from south.modelsinspector import add_introspection_rules
|
||||||
|
add_introspection_rules([], ['^multiselectfield\.db.fields\.MultiSelectField'])
|
||||||
|
except ImportError:
|
||||||
|
pass
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,36 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2012 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 import forms
|
||||||
|
|
||||||
|
from ..utils import get_max_length
|
||||||
|
from ..validators import MaxValueMultiFieldValidator, MinChoicesValidator, MaxChoicesValidator
|
||||||
|
|
||||||
|
|
||||||
|
class MultiSelectFormField(forms.MultipleChoiceField):
|
||||||
|
widget = forms.CheckboxSelectMultiple
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.min_choices = kwargs.pop('min_choices', None)
|
||||||
|
self.max_choices = kwargs.pop('max_choices', None)
|
||||||
|
self.max_length = kwargs.pop('max_length', None)
|
||||||
|
super(MultiSelectFormField, self).__init__(*args, **kwargs)
|
||||||
|
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))
|
||||||
|
if self.min_choices is not None:
|
||||||
|
self.validators.append(MinChoicesValidator(self.min_choices))
|
Binary file not shown.
@ -0,0 +1,23 @@
|
|||||||
|
# django-multiselectfield.
|
||||||
|
# Copyright (C) 2012-2013
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <goinnn@gmail.com>, 2012.
|
||||||
|
#
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: 1.0.0\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2013-11-30 20:06-0500\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: Pablo Martín <goinnn@gmail.com>\n"
|
||||||
|
"Language-Team: Es <goinnn@gmail.com>\n"
|
||||||
|
"Language: Es\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
#: validators.py:28
|
||||||
|
#, python-format
|
||||||
|
msgid "You must select a maximum of %(limit_value)d choices."
|
||||||
|
msgstr "Tu debes de seleccionar un máximo de %(limit_value)d opciones."
|
34
venv/lib/python3.8/site-packages/multiselectfield/utils.py
Normal file
34
venv/lib/python3.8/site-packages/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 # noqa: F821
|
||||||
|
string_type = unicode # noqa: F821
|
||||||
|
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
|
@ -0,0 +1,36 @@
|
|||||||
|
# -*- 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 gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
class MaxValueMultiFieldValidator(validators.MaxLengthValidator):
|
||||||
|
code = 'max_multifield_value'
|
||||||
|
|
||||||
|
def clean(self, x):
|
||||||
|
return len(','.join(x))
|
||||||
|
|
||||||
|
|
||||||
|
class MinChoicesValidator(validators.MinLengthValidator):
|
||||||
|
message = _(u'You must select a minimum of %(limit_value)d choices.')
|
||||||
|
code = 'min_choices'
|
||||||
|
|
||||||
|
|
||||||
|
class MaxChoicesValidator(validators.MaxLengthValidator):
|
||||||
|
message = _(u'You must select a maximum of %(limit_value)d choices.')
|
||||||
|
code = 'max_choices'
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user