mirror of
https://github.com/Hopiu/django-select2.git
synced 2026-03-17 05:50:23 +00:00
Compare commits
9 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7fa49a6e2 | ||
|
|
39ab326884 | ||
|
|
d63f410bca | ||
|
|
5680f0daf9 | ||
|
|
8deb2b6a11 | ||
|
|
37e2515be6 | ||
|
|
cc8989a625 | ||
|
|
1ae52d7436 | ||
|
|
dca7dbc5d1 |
13 changed files with 97 additions and 38 deletions
2
.github/FUNDING.yml
vendored
Normal file
2
.github/FUNDING.yml
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
github: codingjoe
|
||||
custom: https://paypal.me/codingjoe
|
||||
10
.travis.yml
10
.travis.yml
|
|
@ -4,10 +4,10 @@ dist: xenial
|
|||
python:
|
||||
- "3.6"
|
||||
- "3.7"
|
||||
- "3.8"
|
||||
env:
|
||||
- DJANGO=20
|
||||
- DJANGO=21
|
||||
- DJANGO=22
|
||||
- DJANGO=30
|
||||
- DJANGO=master
|
||||
|
||||
matrix:
|
||||
|
|
@ -41,7 +41,7 @@ stages:
|
|||
|
||||
jobs:
|
||||
include:
|
||||
- python: "3.5"
|
||||
- python: "3.7"
|
||||
env: TOXENV=docs
|
||||
addons:
|
||||
apt:
|
||||
|
|
@ -56,7 +56,7 @@ jobs:
|
|||
node_js: lts/*
|
||||
cache: npm
|
||||
- stage: deploy
|
||||
python: "3.7"
|
||||
python: "3.8"
|
||||
install: skip
|
||||
script: skip
|
||||
after_success: true
|
||||
|
|
@ -71,7 +71,7 @@ jobs:
|
|||
- stage: deploy
|
||||
language: node_js
|
||||
node_js: lts/*
|
||||
python: "3.7"
|
||||
python: "3.8"
|
||||
install: skip
|
||||
script: skip
|
||||
after_success: true
|
||||
|
|
|
|||
22
CONTRIBUTING.rst
Normal file
22
CONTRIBUTING.rst
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
Contributing
|
||||
============
|
||||
|
||||
This package uses the pyTest test runner. To run the tests locally simply run::
|
||||
|
||||
python setup.py test
|
||||
|
||||
If you need to the development dependencies installed of you local IDE, you can run::
|
||||
|
||||
python setup.py develop
|
||||
|
||||
Documentation pull requests welcome. The Sphinx documentation can be compiled via::
|
||||
|
||||
python setup.py build_sphinx
|
||||
|
||||
Bug reports welcome, even more so if they include a correct patch. Much
|
||||
more so if you start your patch by adding a failing unit test, and correct
|
||||
the code until zero unit tests fail.
|
||||
|
||||
The list of supported Django and Python version can be found in the CI suite setup.
|
||||
Please make sure to verify that none of the linters or tests failed, before you submit
|
||||
a patch for review.
|
||||
|
|
@ -8,7 +8,7 @@ __all__ = ('settings', 'Select2Conf')
|
|||
class Select2Conf(AppConf):
|
||||
"""Settings for Django-Select2."""
|
||||
|
||||
LIB_VERSION = '4.0.5'
|
||||
LIB_VERSION = '4.0.12'
|
||||
"""Version of the Select2 library."""
|
||||
|
||||
CACHE_BACKEND = 'default'
|
||||
|
|
|
|||
|
|
@ -20,10 +20,11 @@ Widgets are generally of two types:
|
|||
drop-in-replacement for Django's default
|
||||
select widgets.
|
||||
|
||||
2. **Heavy** --
|
||||
2(a). **Heavy** --
|
||||
They are suited for scenarios when the number of options
|
||||
are large and need complex queries (from maybe different
|
||||
sources) to get the options.
|
||||
|
||||
This dynamic fetching of options undoubtedly requires
|
||||
Ajax communication with the server. Django-Select2 includes
|
||||
a helper JS file which is included automatically,
|
||||
|
|
@ -31,15 +32,15 @@ Widgets are generally of two types:
|
|||
Although on the server side you do need to create a view
|
||||
specifically to respond to the queries.
|
||||
|
||||
3. **Model** --
|
||||
2(b). **Model** --
|
||||
Model-widgets are a further specialized versions of Heavies.
|
||||
These do not require views to serve Ajax requests.
|
||||
When they are instantiated, they register themselves
|
||||
with one central view which handles Ajax requests for them.
|
||||
|
||||
Heavy widgets have the word 'Heavy' in their name.
|
||||
Light widgets are normally named, i.e. there is no
|
||||
'Light' word in their names.
|
||||
Heavy and Model widgets have respectively the word 'Heavy' and 'Model' in
|
||||
their name. Light widgets are normally named, i.e. there is no 'Light' word
|
||||
in their names.
|
||||
|
||||
.. inheritance-diagram:: django_select2.forms
|
||||
:parts: 1
|
||||
|
|
@ -70,6 +71,8 @@ class Select2Mixin:
|
|||
form media.
|
||||
"""
|
||||
|
||||
empty_label = ''
|
||||
|
||||
def build_attrs(self, base_attrs, extra_attrs=None):
|
||||
"""Add select2 data attributes."""
|
||||
default_attrs = {'data-minimum-input-length': 0}
|
||||
|
|
@ -77,7 +80,7 @@ class Select2Mixin:
|
|||
default_attrs['data-allow-clear'] = 'false'
|
||||
else:
|
||||
default_attrs['data-allow-clear'] = 'true'
|
||||
default_attrs['data-placeholder'] = ''
|
||||
default_attrs['data-placeholder'] = self.empty_label or ""
|
||||
|
||||
default_attrs.update(base_attrs)
|
||||
attrs = super().build_attrs(default_attrs, extra_attrs=extra_attrs)
|
||||
|
|
@ -208,6 +211,7 @@ class HeavySelect2Mixin:
|
|||
widget could be dependent on a country.
|
||||
Key is a name of a field in a form.
|
||||
Value is a name of a field in a model (used in `queryset`).
|
||||
|
||||
"""
|
||||
self.choices = choices
|
||||
if attrs is not None:
|
||||
|
|
@ -339,6 +343,12 @@ class ModelSelect2Mixin:
|
|||
max_results = 25
|
||||
"""Maximal results returned by :class:`.AutoResponseView`."""
|
||||
|
||||
@property
|
||||
def empty_label(self):
|
||||
if isinstance(self.choices, ModelChoiceIterator):
|
||||
return self.choices.field.empty_label
|
||||
return ''
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
Overwrite class parameters if passed as keyword arguments.
|
||||
|
|
|
|||
1
docs/CONTRIBUTING.rst
Normal file
1
docs/CONTRIBUTING.rst
Normal file
|
|
@ -0,0 +1 @@
|
|||
.. include:: ../CONTRIBUTING.rst
|
||||
|
|
@ -49,8 +49,9 @@ DjangoSelect2 handles the initialization of select2 fields automatically. Just i
|
|||
``{{ form.media.js }}`` in your template before the closing ``body`` tag. That's it!
|
||||
|
||||
If you insert forms after page load or if you want to handle the initialization
|
||||
yourself, DjangoSelect2 provides a jQuery plugin. It will handle both normal and
|
||||
heavy fields. Simply call ``djangoSelect2(options)`` on your select fields.::
|
||||
yourself, DjangoSelect2 provides a jQuery plugin, replacing and enhancing the Select2
|
||||
plugin. It will handle both normal and heavy fields. Simply call
|
||||
``djangoSelect2(options)`` on your select fields.::
|
||||
|
||||
$('.django-select2').djangoSelect2();
|
||||
|
||||
|
|
@ -59,6 +60,9 @@ You can pass see `Select2 options <https://select2.github.io/options.html>`_ if
|
|||
|
||||
$('.django-select2').djangoSelect2({placeholder: 'Select an option'});
|
||||
|
||||
Please replace all your ``.select2`` invocations with the here provided
|
||||
``.djangoSelect2``.
|
||||
|
||||
Security & Authentication
|
||||
-------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,12 @@ Overview
|
|||
.. automodule:: django_select2
|
||||
:members:
|
||||
|
||||
Assumptions
|
||||
-----------
|
||||
|
||||
* You have a running Django up and running.
|
||||
* You have form fully working without Django-Select2.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
|
|
@ -17,11 +23,12 @@ Installation
|
|||
|
||||
2. Add ``django_select2`` to your ``INSTALLED_APPS`` in your project settings.
|
||||
|
||||
3. Add ``django_select`` to your ``urlconf``::
|
||||
|
||||
3. Add ``django_select`` to your ``urlconf`` **if** you use any
|
||||
:class:`ModelWidgets <.django_select2.forms.ModelSelect2Mixin>`::
|
||||
path('select2/', include('django_select2.urls')),
|
||||
|
||||
url(r'^select2/', include('django_select2.urls')),
|
||||
You can safely skip this one if you do not use any
|
||||
:class:`ModelWidgets <.django_select2.forms.ModelSelect2Mixin>`
|
||||
|
||||
Quick Start
|
||||
-----------
|
||||
|
|
@ -30,19 +37,22 @@ Here is a quick example to get you started:
|
|||
|
||||
0. Follow the installation instructions above.
|
||||
|
||||
1. Add a select2 widget to the form. For example if you wanted Select2 with multi-select you would use
|
||||
``Select2MultipleWidget``
|
||||
Replacing::
|
||||
1. Replace native Django forms widgets with one of the several ``django_select2.form`` widgets.
|
||||
Start by importing them into your ``forms.py``, right next to Django own ones::
|
||||
|
||||
class MyForm(forms.Form):
|
||||
things = ModelMultipleChoiceField(queryset=Thing.objects.all())
|
||||
from django import forms
|
||||
from django_select2 import forms as s2forms
|
||||
|
||||
with::
|
||||
Then let's assume you have a model with a choice, a :class:`.ForeignKey`, and a
|
||||
:class:`.ManyToManyField`, you would add this information to your Form Meta
|
||||
class::
|
||||
|
||||
from django_select2.forms import Select2MultipleWidget
|
||||
|
||||
class MyForm(forms.Form):
|
||||
things = ModelMultipleChoiceField(queryset=Thing.objects.all(), widget=Select2MultipleWidget)
|
||||
widgets = {
|
||||
'category': s2forms.Select2Widget,
|
||||
'author': s2forms.ModelSelect2Widget(model=auth.get_user_model(),
|
||||
search_fields=['first_name__istartswith', 'last_name__icontains']),
|
||||
'attending': s2forms.ModelSelect2MultipleWidget …
|
||||
}
|
||||
|
||||
2. Add the CSS to the ``head`` of your Django template::
|
||||
|
||||
|
|
@ -57,9 +67,9 @@ with::
|
|||
External Dependencies
|
||||
---------------------
|
||||
|
||||
* jQuery version 2
|
||||
This is not included in the package since it is expected
|
||||
that in most scenarios this would already be available.
|
||||
* jQuery (version >=2)
|
||||
jQuery is not included in the package since it is expected
|
||||
that in most scenarios jQuery is already loaded.
|
||||
|
||||
Example Application
|
||||
-------------------
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ Contents:
|
|||
get_started
|
||||
django_select2
|
||||
extra
|
||||
CONTRIBUTING
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ classifier =
|
|||
include_package_data = True
|
||||
packages = django_select2
|
||||
install_requires =
|
||||
django>=2.0
|
||||
django>=2.2
|
||||
django-appconf>=0.6.0
|
||||
setup_requires =
|
||||
setuptools_scm
|
||||
|
|
@ -53,14 +53,13 @@ addopts = --cov=django_select2 --cov-report xml
|
|||
DJANGO_SETTINGS_MODULE=tests.testapp.settings
|
||||
|
||||
[tox:tox]
|
||||
envlist = py{35,36,37}-dj{22,21,20,master},docs
|
||||
envlist = py{36,37,38}-dj{22,30,master},docs
|
||||
|
||||
[testenv]
|
||||
passenv=CI
|
||||
deps =
|
||||
dj20: https://github.com/django/django/archive/stable/2.0.x.tar.gz#egg=django
|
||||
dj21: https://github.com/django/django/archive/stable/2.1.x.tar.gz#egg=django
|
||||
dj22: https://github.com/django/django/archive/stable/2.2.x.tar.gz#egg=django
|
||||
dj22: django~=2.2
|
||||
dj30: django~=3.0
|
||||
djmaster: https://github.com/django/django/archive/master.tar.gz#egg=django
|
||||
commands = python setup.py test
|
||||
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
from setuptools import setup
|
||||
|
||||
setup(use_scm_version=True)
|
||||
setup(name='django-select2', use_scm_version=True)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ def random_name(n):
|
|||
@pytest.yield_fixture(scope='session')
|
||||
def driver():
|
||||
chrome_options = webdriver.ChromeOptions()
|
||||
chrome_options.headless = False
|
||||
chrome_options.headless = True
|
||||
try:
|
||||
b = webdriver.Chrome(options=chrome_options)
|
||||
except WebDriverException as e:
|
||||
|
|
|
|||
|
|
@ -95,7 +95,9 @@ class TestSelect2Mixin:
|
|||
multiple_select = self.multiple_form.fields['featured_artists']
|
||||
assert multiple_select.required is False
|
||||
assert multiple_select.widget.allow_multiple_selected
|
||||
assert '<option value=""></option>' not in multiple_select.widget.render('featured_artists', None)
|
||||
output = multiple_select.widget.render('featured_artists', None)
|
||||
assert '<option value=""></option>' not in output
|
||||
assert 'data-placeholder=""' in output
|
||||
|
||||
def test_i18n(self):
|
||||
translation.activate('de')
|
||||
|
|
@ -412,6 +414,14 @@ class TestModelSelect2Mixin(TestHeavySelect2Mixin):
|
|||
form = forms.GroupieForm(instance=groupie)
|
||||
assert '<option value="Take That" selected>TAKE THAT</option>' in form.as_p()
|
||||
|
||||
def test_empty_label(self, db):
|
||||
# Empty options is only required for single selects
|
||||
# https://select2.github.io/options.html#allowClear
|
||||
single_select = self.form.fields['primary_genre']
|
||||
single_select.empty_label = 'Hello World'
|
||||
assert single_select.required is False
|
||||
assert 'data-placeholder="Hello World"' in single_select.widget.render('primary_genre', None)
|
||||
|
||||
|
||||
class TestHeavySelect2TagWidget(TestHeavySelect2Mixin):
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue