Added documentation
This commit is contained in:
parent
5dfd8553cc
commit
f301dc6f9d
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -1,6 +1,18 @@
|
|||
Changelog Summary
|
||||
=================
|
||||
|
||||
### v5.0.0
|
||||
Version 5 is a complete rewrite of the package to drastically reduce
|
||||
the code base and to ensure a future maintainability.
|
||||
|
||||
While we feature set remained unchanged, the API changed completely.
|
||||
Major changes:
|
||||
* Fields have been removed in favor of widgets.
|
||||
* All version 4 settings have been removed.
|
||||
* Template tags have been removed.
|
||||
* 3rd party javascript is served by a CDN.
|
||||
* No more inline javascript code.
|
||||
|
||||
### v4.3.2
|
||||
|
||||
* Use `django.contrib.staticfiles.templatetags.staticfiles.static` over `django.templatetags.static.static` to allow hashing.
|
||||
|
|
86
README
86
README
|
@ -1,86 +0,0 @@
|
|||
Django-Select2
|
||||
==============
|
||||
|
||||
[![PyPi Version](https://img.shields.io/pypi/v/Django-Select2.svg)](https://pypi.python.org/pypi/Django-Select2/)
|
||||
[![Build Status](https://travis-ci.org/applegrew/django-select2.svg?branch=master)](https://travis-ci.org/applegrew/django-select2)
|
||||
[![Code Health](https://landscape.io/github/applegrew/django-select2/master/landscape.svg?style=flat)](https://landscape.io/github/applegrew/django-select2/master)
|
||||
[![Test Coverage](https://coveralls.io/repos/applegrew/django-select2/badge.png?branch=master)](https://coveralls.io/r/applegrew/django-select2)
|
||||
[![GitHub license](https://img.shields.io/badge/license-APL2-blue.svg)](https://raw.githubusercontent.com/applegrew/django-select2/master/LICENSE.txt)
|
||||
[![Join the chat at https://gitter.im/applegrew/django-select2](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/applegrew/django-select2?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
This is a [Django](https://www.djangoproject.com/) integration of [Select2](http://ivaynberg.github.com/select2/).
|
||||
|
||||
The app includes Select2 driven Django Widgets and Form Fields.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
1. Install `django_select2`
|
||||
|
||||
pip install django_select2
|
||||
|
||||
2. Add `django_select2` to your `INSTALLED_APPS` in your project settings.
|
||||
|
||||
3. When deploying on production server, run :-
|
||||
|
||||
python manage.py collectstatic
|
||||
|
||||
4. Add `django_select` to your urlconf if you use any 'Auto' fields.
|
||||
|
||||
url(r'^select2/', include('django_select2.urls')),
|
||||
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
Documentation available at http://django-select2.readthedocs.org/.
|
||||
|
||||
More details
|
||||
============
|
||||
|
||||
More details can be found on my blog at - http://blog.applegrew.com/2012/08/django-select2/.
|
||||
|
||||
External Dependencies
|
||||
=====================
|
||||
|
||||
* Django - This is obvious.
|
||||
* jQuery - This is not included in the package since it is expected that in most scenarios this would already be available.
|
||||
* Memcached or Redis - If you run more than one node, you'll need a shared memory.
|
||||
|
||||
Example Application
|
||||
===================
|
||||
Please see `testapp` application. This application is used to manually test the functionalities of this package. This also serves as a good example.
|
||||
|
||||
You need only Django 1.4 or above to run that. It might run on older versions but that is not tested.
|
||||
|
||||
Special Thanks
|
||||
==============
|
||||
|
||||
* Samuel Goldszmidt (@ouhouhsami) for reporting many fundamental issues with the code, because of which versions 2.0 and 2.0.1 were released.
|
||||
|
||||
Official Contributors
|
||||
=====================
|
||||
|
||||
* Johannes Hoppe (@codingjoe)
|
||||
|
||||
Changelog
|
||||
=========
|
||||
|
||||
See [CHANGELOG.md](CHANGELOG.md)
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
Copyright 2012 Nirupam Biswas
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this project except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
[http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
81
README.md
81
README.md
|
@ -3,17 +3,16 @@ Django-Select2
|
|||
|
||||
[![PyPi Version](https://img.shields.io/pypi/v/Django-Select2.svg)](https://pypi.python.org/pypi/Django-Select2/)
|
||||
[![Build Status](https://travis-ci.org/applegrew/django-select2.svg?branch=master)](https://travis-ci.org/applegrew/django-select2)
|
||||
[![Code Health](https://landscape.io/github/applegrew/django-select2/master/landscape.svg?style=flat)](https://landscape.io/github/applegrew/django-select2/master)
|
||||
[![Test Coverage](https://coveralls.io/repos/applegrew/django-select2/badge.png?branch=master)](https://coveralls.io/r/applegrew/django-select2)
|
||||
[![GitHub license](https://img.shields.io/badge/license-APL2-blue.svg)](https://raw.githubusercontent.com/applegrew/django-select2/master/LICENSE.txt)
|
||||
[![Join the chat at https://gitter.im/applegrew/django-select2](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/applegrew/django-select2?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
This is a [Django](https://www.djangoproject.com/) integration of [Select2](http://ivaynberg.github.com/select2/).
|
||||
|
||||
The app includes Select2 driven Django Widgets and Form Fields.
|
||||
The app includes Select2 driven Django Widgets.
|
||||
|
||||
## Installation
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
1. Install `django_select2`
|
||||
|
||||
|
@ -21,56 +20,70 @@ Installation
|
|||
|
||||
2. Add `django_select2` to your `INSTALLED_APPS` in your project settings.
|
||||
|
||||
3. When deploying on production server, run :-
|
||||
|
||||
python manage.py collectstatic
|
||||
|
||||
4. Add `django_select` to your urlconf if you use any 'Auto' fields.
|
||||
3. Add `django_select` to your urlconf if you use any 'Auto' fields.
|
||||
|
||||
url(r'^select2/', include('django_select2.urls')),
|
||||
|
||||
|
||||
Documentation
|
||||
=============
|
||||
### Upgrade from Version 4
|
||||
|
||||
Version 5 is a complete rewrite of the package to drastically reduce
|
||||
the code base and to ensure a future maintainability.
|
||||
|
||||
While we feature set remained unchanged, the API changed completely.
|
||||
Major changes:
|
||||
- Fields have been removed in favor of widgets.
|
||||
- All version 4 settings have been removed.
|
||||
- Template tags have been removed.
|
||||
- 3rd party javascript is served by a CDN.
|
||||
- No more inline javascript code.
|
||||
|
||||
#### Upgrade can be done in 5 simple steps:
|
||||
|
||||
1. Remove all existing and to setup the new cache backend.
|
||||
2. Remove the old template tags from your templates:
|
||||
1. `import_django_select2_js`
|
||||
2. `import_django_select2_css`
|
||||
3. `import_django_select2_js_css`
|
||||
3. Add `form.media.css` to the top and `form.media.js`
|
||||
to the bottom of your base template.
|
||||
4. Upgrade to jQuery version 2, if you are still running version 1.
|
||||
5. Replace old fields with new widgets.
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
Documentation available at http://django-select2.readthedocs.org/.
|
||||
|
||||
More details
|
||||
============
|
||||
|
||||
More details can be found on my blog at - http://blog.applegrew.com/2012/08/django-select2/.
|
||||
|
||||
External Dependencies
|
||||
=====================
|
||||
|
||||
* Django - This is obvious.
|
||||
* jQuery - This is not included in the package since it is expected that in most scenarios this would already be available.
|
||||
* Memcached or Redis - If you run more than one node, you'll need a shared memory.
|
||||
## External Dependencies
|
||||
|
||||
|
||||
Example Application
|
||||
===================
|
||||
Please see `testapp` application. This application is used to manually test the functionalities of this package. This also serves as a good example.
|
||||
* jQuery version 2
|
||||
This is not included in the package since it is expected
|
||||
that in most scenarios this would already be available.
|
||||
|
||||
You need only Django 1.4 or above to run that. It might run on older versions but that is not tested.
|
||||
|
||||
Special Thanks
|
||||
==============
|
||||
## Example Application
|
||||
|
||||
Please see `tests/testapp` application.
|
||||
This application is used to manually test the functionalities of this package.
|
||||
This also serves as a good example.
|
||||
|
||||
## Special Thanks
|
||||
|
||||
|
||||
* Samuel Goldszmidt (@ouhouhsami) for reporting many fundamental issues with the code, because of which versions 2.0 and 2.0.1 were released.
|
||||
|
||||
Official Contributors
|
||||
=====================
|
||||
## Official Contributors
|
||||
|
||||
* Johannes Hoppe (@codingjoe)
|
||||
|
||||
Changelog
|
||||
=========
|
||||
## Changelog
|
||||
|
||||
See [CHANGELOG.md](CHANGELOG.md)
|
||||
|
||||
License
|
||||
=======
|
||||
## License
|
||||
|
||||
Copyright 2012 Nirupam Biswas
|
||||
|
||||
|
|
|
@ -7,75 +7,6 @@ The app includes Select2 driven Django Widgets and Form Fields.
|
|||
.. _Django: https://www.djangoproject.com/
|
||||
.. _Select2: http://ivaynberg.github.com/select2/
|
||||
|
||||
Widgets
|
||||
-------
|
||||
|
||||
These components are responsible for rendering
|
||||
the necessary JavaScript and HTML markups. Since this whole
|
||||
package is to render choices using Select2 JavaScript
|
||||
library, hence these components are meant to be used
|
||||
with choice fields.
|
||||
|
||||
Widgets are generally of two types :-
|
||||
|
||||
1. **Light** --
|
||||
They are not meant to be used when there
|
||||
are too many options, say, in thousands.
|
||||
This is because all those options would
|
||||
have to be pre-rendered onto the page
|
||||
and JavaScript would be used to search
|
||||
through them. Said that, they are also one
|
||||
the most easiest to use. They are almost
|
||||
drop-in-replacement for Django's default
|
||||
select widgets.
|
||||
|
||||
2. **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,
|
||||
so you need not worry about writing any Ajax related JS code.
|
||||
Although on the server side you do need to create a view
|
||||
specifically to respond to the queries.
|
||||
|
||||
Heavies have further specialized versions called -- **Auto Heavy**.
|
||||
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.
|
||||
|
||||
**Available widgets:**
|
||||
|
||||
:py:class:`.Select2Widget`,
|
||||
:py:class:`.Select2MultipleWidget`,
|
||||
:py:class:`.HeavySelect2Widget`,
|
||||
:py:class:`.HeavySelect2MultipleWidget`,
|
||||
:py:class:`.ModelSelect2Widget`,
|
||||
:py:class:`.ModelSelect2MultipleWidget`,
|
||||
:py:class:`.HeavySelect2TagWidget`,
|
||||
:py:class:`.GenreSelect2TagWidget`
|
||||
|
||||
`Read more`_
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
The view - `Select2View`, exposed here is meant
|
||||
to be used with 'Heavy' fields and widgets.
|
||||
|
||||
**Imported:**
|
||||
|
||||
:py:class:`.Select2View`, :py:data:`.NO_ERR_RESP`
|
||||
|
||||
`Read more`_
|
||||
|
||||
.. _Read more: http://blog.applegrew.com/2012/08/django-select2/
|
||||
|
||||
"""
|
||||
|
||||
__version__ = "5.0.0"
|
||||
|
|
|
@ -1,15 +1,53 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Settings for Django-Select2."""
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from appconf import AppConf
|
||||
from django.conf import settings # NOQA
|
||||
|
||||
__all__ = ('settings',)
|
||||
__all__ = ('settings', 'Select2Conf')
|
||||
|
||||
|
||||
class Select2Conf(AppConf):
|
||||
|
||||
"""Settings for Django-Select2."""
|
||||
|
||||
CACHE_BACKEND = 'default'
|
||||
"""
|
||||
Django-Select2 uses Django's cache to sure a consistent state across multiple machines.
|
||||
|
||||
Example of settings.py::
|
||||
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": "django_redis.cache.RedisCache",
|
||||
"LOCATION": "redis://127.0.0.1:6379/1",
|
||||
"OPTIONS": {
|
||||
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||
}
|
||||
},
|
||||
'select2': {
|
||||
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
||||
'LOCATION': '127.0.0.1:11211',
|
||||
}
|
||||
}
|
||||
|
||||
# Set the cache backend to select2
|
||||
SELECT2_CACHE_BACKEND = 'select2'
|
||||
|
||||
.. tip:: To ensure a consistent state across all you machines you need to user
|
||||
a consistent external cache backend like Memcached, Redis or a database.
|
||||
|
||||
.. note:: The timeout of select2's caching backend determines
|
||||
how long a browser session can last.
|
||||
Once widget is dropped from the cache the json response view will return a 404.
|
||||
"""
|
||||
CACHE_PREFIX = 'select2_'
|
||||
"""
|
||||
If you caching backend doesn't support multiple databases
|
||||
you can isolate select2 using the cache prefix setting.
|
||||
It has set `select2_` as a default value, which you can change if needed.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
prefix = 'SELECT2'
|
||||
|
|
|
@ -1,8 +1,53 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Contains all the Django widgets for Select2."""
|
||||
"""
|
||||
Django-Select2 Widgets.
|
||||
|
||||
These components are responsible for rendering
|
||||
the necessary HTML data markups. Since this whole
|
||||
package is to render choices using Select2 JavaScript
|
||||
library, hence these components are meant to be used
|
||||
with choice fields.
|
||||
|
||||
Widgets are generally of two types:
|
||||
|
||||
1. **Light** --
|
||||
They are not meant to be used when there
|
||||
are too many options, say, in thousands.
|
||||
This is because all those options would
|
||||
have to be pre-rendered onto the page
|
||||
and JavaScript would be used to search
|
||||
through them. Said that, they are also one
|
||||
the most easiest to use. They are a
|
||||
drop-in-replacement for Django's default
|
||||
select widgets.
|
||||
|
||||
2. **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,
|
||||
so you need not worry about writing any Ajax related JS code.
|
||||
Although on the server side you do need to create a view
|
||||
specifically to respond to the queries.
|
||||
|
||||
3. **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.
|
||||
|
||||
.. inheritance-diagram:: django_select2.forms
|
||||
:parts: 1
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import logging
|
||||
from functools import reduce
|
||||
|
||||
from django import forms
|
||||
|
@ -15,11 +60,6 @@ from django.utils.encoding import force_text
|
|||
from .cache import cache
|
||||
from .conf import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# ## Light mixin and widgets ##
|
||||
|
||||
|
||||
class Select2Mixin(object):
|
||||
|
||||
|
@ -32,6 +72,7 @@ class Select2Mixin(object):
|
|||
"""
|
||||
|
||||
def build_attrs(self, extra_attrs=None, **kwargs):
|
||||
"""Add select2 data attributes."""
|
||||
attrs = super(Select2Mixin, self).build_attrs(extra_attrs=extra_attrs, **kwargs)
|
||||
if self.is_required:
|
||||
attrs.setdefault('data-allow-clear', 'false')
|
||||
|
@ -47,6 +88,7 @@ class Select2Mixin(object):
|
|||
return attrs
|
||||
|
||||
def render_options(self, choices, selected_choices):
|
||||
"""Render options including an empty one, if the field is not required."""
|
||||
output = '<option></option>' if not self.is_required else ''
|
||||
output += super(Select2Mixin, self).render_options(choices, selected_choices)
|
||||
return output
|
||||
|
@ -55,11 +97,8 @@ class Select2Mixin(object):
|
|||
"""
|
||||
Construct Media as a dynamic property.
|
||||
|
||||
This is essential because we need to check RENDER_SELECT2_STATICS
|
||||
before returning our assets.
|
||||
|
||||
for more information:
|
||||
https://docs.djangoproject.com/en/1.8/topics/forms/media/#media-as-a-dynamic-property
|
||||
.. Note:: For more information visit
|
||||
https://docs.djangoproject.com/en/1.8/topics/forms/media/#media-as-a-dynamic-property
|
||||
"""
|
||||
return forms.Media(
|
||||
js=('//cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.min.js',
|
||||
|
@ -71,10 +110,38 @@ class Select2Mixin(object):
|
|||
|
||||
|
||||
class Select2Widget(Select2Mixin, forms.Select):
|
||||
|
||||
"""
|
||||
Select2 drop in widget.
|
||||
|
||||
Example usage::
|
||||
|
||||
class MyModelForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = MyModel
|
||||
fields = ('my_field', )
|
||||
widgets = {
|
||||
'my_field': Select2Widget
|
||||
}
|
||||
|
||||
or::
|
||||
|
||||
class MyForm(forms.Form):
|
||||
my_choice = forms.ChoiceField(widget=Select2Widget)
|
||||
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class Select2MultipleWidget(Select2Mixin, forms.SelectMultiple):
|
||||
|
||||
"""
|
||||
Select2 drop in widget for multiple select.
|
||||
|
||||
Works just like :class:`.Select2Widget` but for multi select.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
@ -83,6 +150,15 @@ class HeavySelect2Mixin(Select2Mixin):
|
|||
"""Mixin that adds select2's ajax options and registers itself on django's cache."""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
Return HeavySelect2Mixin.
|
||||
|
||||
:param data_view: url pattern name
|
||||
:type data_view: str
|
||||
:param data_url: url
|
||||
:type data_url: str
|
||||
:return:
|
||||
"""
|
||||
self.data_view = kwargs.pop('data_view', None)
|
||||
self.data_url = kwargs.pop('data_url', None)
|
||||
if not (self.data_view or self.data_url):
|
||||
|
@ -91,11 +167,13 @@ class HeavySelect2Mixin(Select2Mixin):
|
|||
super(HeavySelect2Mixin, self).__init__(**kwargs)
|
||||
|
||||
def get_url(self):
|
||||
"""Return url from instance or by reversing :attr:`.data_view`."""
|
||||
if self.data_url:
|
||||
return self.data_url
|
||||
return reverse_lazy(self.data_view)
|
||||
|
||||
def build_attrs(self, extra_attrs=None, **kwargs):
|
||||
"""Set select2's ajax attributes."""
|
||||
attrs = super(HeavySelect2Mixin, self).build_attrs(extra_attrs=extra_attrs, **kwargs)
|
||||
|
||||
# encrypt instance Id
|
||||
|
@ -111,6 +189,7 @@ class HeavySelect2Mixin(Select2Mixin):
|
|||
return attrs
|
||||
|
||||
def render(self, name, value, attrs=None, choices=()):
|
||||
"""Render widget and register it in Django's cache."""
|
||||
output = super(HeavySelect2Mixin, self).render(name, value, attrs=attrs, choices=choices)
|
||||
self.set_to_cache()
|
||||
return output
|
||||
|
@ -123,6 +202,7 @@ class HeavySelect2Mixin(Select2Mixin):
|
|||
cache.set(self._get_cache_key(), self)
|
||||
|
||||
def render_options(self, choices, selected_choices):
|
||||
"""Render only selected options."""
|
||||
output = ['<option></option>' if not self.is_required else '']
|
||||
choices = {(k, v) for k, v in choices if k in selected_choices}
|
||||
selected_choices = {force_text(v) for v in selected_choices}
|
||||
|
@ -132,15 +212,42 @@ class HeavySelect2Mixin(Select2Mixin):
|
|||
|
||||
|
||||
class HeavySelect2Widget(HeavySelect2Mixin, forms.Select):
|
||||
|
||||
"""
|
||||
Select2 widget with AJAX support that registers itself to Django's Cache.
|
||||
|
||||
Usage example::
|
||||
|
||||
class MyWidget(HeavySelectWidget):
|
||||
data_view = 'my_view_name'
|
||||
|
||||
or::
|
||||
|
||||
class MyForm(forms.Form):
|
||||
my_field = forms.ChoicesField(
|
||||
widget=HeavySelectWidget(
|
||||
data_url='/url/to/json/response'
|
||||
)
|
||||
)
|
||||
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class HeavySelect2MultipleWidget(HeavySelect2Mixin, forms.SelectMultiple):
|
||||
|
||||
"""Select2 multi select widget similar to :class:`.HeavySelect2Widget`."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class HeavySelect2TagWidget(HeavySelect2MultipleWidget):
|
||||
|
||||
"""Mixin to add select2 tag functionality."""
|
||||
|
||||
def build_attrs(self, extra_attrs=None, **kwargs):
|
||||
"""Add select2's tag attributes."""
|
||||
attrs = super(HeavySelect2TagWidget, self).build_attrs(extra_attrs, **kwargs)
|
||||
attrs['data-minimum-input-length'] = 1
|
||||
attrs['data-tags'] = 'true'
|
||||
|
@ -152,12 +259,39 @@ class HeavySelect2TagWidget(HeavySelect2MultipleWidget):
|
|||
|
||||
|
||||
class ModelSelect2Mixin(object):
|
||||
|
||||
"""Widget mixin that provides attributes and methods for :class:`.AutoResponseView`."""
|
||||
|
||||
model = None
|
||||
queryset = None
|
||||
search_fields = []
|
||||
"""
|
||||
Model lookups that are used to filter the queryset.
|
||||
|
||||
Example::
|
||||
|
||||
search_fields = [
|
||||
'title__icontains',
|
||||
]
|
||||
|
||||
"""
|
||||
|
||||
max_results = 25
|
||||
"""Maximal results returned by :class:`.AutoResponseView`."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
Overwrite class parameters if passed as keyword arguments.
|
||||
|
||||
:param model: model to select choices from
|
||||
:type model: django.db.models.Model
|
||||
:param queryset: queryset to select choices from
|
||||
:type queryset: django.db.models.query.QuerySet
|
||||
:param search_fields: list of model lookup strings
|
||||
:type search_fields: list
|
||||
:param max_results: max. JsonResponse view page size
|
||||
:type max_results: int
|
||||
"""
|
||||
self.model = kwargs.pop('model', self.model)
|
||||
self.queryset = kwargs.pop('queryset', self.queryset)
|
||||
self.search_fields = kwargs.pop('search_fields', self.search_fields)
|
||||
|
@ -167,6 +301,14 @@ class ModelSelect2Mixin(object):
|
|||
super(ModelSelect2Mixin, self).__init__(*args, **defaults)
|
||||
|
||||
def filter_queryset(self, term):
|
||||
"""
|
||||
Return queryset filtered by search_fields matching the passed term.
|
||||
|
||||
:param term: Search term
|
||||
:type term: str
|
||||
:return: Filtered queryset
|
||||
:rtype: :class:`.django.db.models.QuerySet`
|
||||
"""
|
||||
qs = self.get_queryset()
|
||||
search_fields = self.get_search_fields()
|
||||
select = reduce(lambda x, y: Q(**{x: term}) | Q(**{y: term}), search_fields,
|
||||
|
@ -174,6 +316,12 @@ class ModelSelect2Mixin(object):
|
|||
return qs.filter(select).distinct()
|
||||
|
||||
def get_queryset(self):
|
||||
"""
|
||||
Return queryset based on :attr:`.queryset` or :attr:`.model`.
|
||||
|
||||
:return: queryset of available choices
|
||||
:rtype: :class:`.django.db.models.QuerySet`
|
||||
"""
|
||||
if self.queryset is not None:
|
||||
queryset = self.queryset
|
||||
elif self.model is not None:
|
||||
|
@ -189,11 +337,13 @@ class ModelSelect2Mixin(object):
|
|||
return queryset
|
||||
|
||||
def get_search_fields(self):
|
||||
"""Return list of lookup names."""
|
||||
if self.search_fields:
|
||||
return self.search_fields
|
||||
raise NotImplementedError('%s, must implement "search_fields".' % self.__class__.__name__)
|
||||
|
||||
def render_options(self, choices, selected_choices):
|
||||
"""Render only selected options and set queryset from :class:`ModelChoicesIterator`."""
|
||||
output = ['<option></option>' if not self.is_required else '']
|
||||
if isinstance(self.choices, ModelChoiceIterator):
|
||||
if not self.queryset:
|
||||
|
@ -212,20 +362,79 @@ class ModelSelect2Mixin(object):
|
|||
|
||||
class ModelSelect2Widget(ModelSelect2Mixin, HeavySelect2Widget):
|
||||
|
||||
"""Auto version of :py:class:`.HeavySelect2Widget`."""
|
||||
"""
|
||||
Select2 drop in model select widget.
|
||||
|
||||
Example usage::
|
||||
|
||||
class MyWidget(ModelSelect2Widget):
|
||||
search_fields = [
|
||||
'title__icontians',
|
||||
]
|
||||
|
||||
class MyModelForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = MyModel
|
||||
fields = ('my_field', )
|
||||
widgets = {
|
||||
'my_field': MyWidget,
|
||||
}
|
||||
|
||||
or::
|
||||
|
||||
class MyForm(forms.Form):
|
||||
my_choice = forms.ChoiceField(
|
||||
widget=ModelSelect2Widget(
|
||||
model=MyOtherModel,
|
||||
search_fields=['title__icontains']
|
||||
)
|
||||
)
|
||||
|
||||
.. tip:: The ModelSelect2(Multiple)Widget will try
|
||||
to get the queryset from the fields choices.
|
||||
Therefore you don't need to define a queryset,
|
||||
if you just drop in the widget for a ForeignKey field.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ModelSelect2MultipleWidget(ModelSelect2Mixin, HeavySelect2MultipleWidget):
|
||||
|
||||
"""Auto version of :py:class:`.HeavySelect2MultipleWidget`."""
|
||||
"""
|
||||
Select2 drop in model multiple select widget.
|
||||
|
||||
Works just like :class:`.ModelSelect2Widget` but for multi select.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class ModelSelect2TagWidget(ModelSelect2Mixin, HeavySelect2TagWidget):
|
||||
|
||||
"""Auto version of :py:class:`.HeavySelect2TagWidget`."""
|
||||
"""
|
||||
Select2 model field with tag support.
|
||||
|
||||
This it not a simple drop in widget.
|
||||
It requires to implement you own :func:`.value_from_datadict`
|
||||
that adds missing tags to you queryset.
|
||||
|
||||
Example::
|
||||
|
||||
class MyModelSelect2TagWidget(ModelSelect2TagWidget):
|
||||
queryset = MyModel.objects.all()
|
||||
|
||||
def value_from_datadict(self, data, files, name):
|
||||
values = super().value_from_datadict(self, data, files, name):
|
||||
qs = self.queryset.filter(**{'pk__in': list(values)})
|
||||
pks = set(force_text(getattr(o, pk)) for o in qs)
|
||||
cleaned_values = []
|
||||
for val in value:
|
||||
if force_text(val) not in pks:
|
||||
val = queryset.create(title=val).pk
|
||||
cleaned_values.append(val)
|
||||
return cleaned_values
|
||||
|
||||
"""
|
||||
|
||||
pass
|
||||
|
|
|
@ -1 +1 @@
|
|||
# Django legacy file
|
||||
"""Django legacy file."""
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Django-Select2 url config.
|
||||
|
||||
Add `django_select` to your urlconf **if** you use any 'Model' fields::
|
||||
|
||||
url(r'^select2/', include('django_select2.urls')),
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from django.conf.urls import patterns, url
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""JSONResponse views for model widgets."""
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from django.core import signing
|
||||
|
@ -13,7 +14,28 @@ from .conf import settings
|
|||
|
||||
class AutoResponseView(BaseListView):
|
||||
|
||||
"""
|
||||
View that handles requests from heavy model widgets.
|
||||
|
||||
The view only supports HTTP's GET method.
|
||||
"""
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
"""
|
||||
Return a :class:`.django.http.JsonResponse`.
|
||||
|
||||
Example::
|
||||
|
||||
{
|
||||
'results': [
|
||||
{
|
||||
'text': "foo",
|
||||
'id': 123
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
"""
|
||||
self.widget = self.get_widget_or_404()
|
||||
self.term = kwargs.get('term', request.GET.get('term', ''))
|
||||
self.object_list = self.get_queryset()
|
||||
|
@ -29,12 +51,22 @@ class AutoResponseView(BaseListView):
|
|||
})
|
||||
|
||||
def get_queryset(self):
|
||||
"""Get queryset from cached widget."""
|
||||
return self.widget.filter_queryset(self.term)
|
||||
|
||||
def get_paginate_by(self, queryset):
|
||||
"""Paginate response by size of widget's `max_results` parameter."""
|
||||
return self.widget.max_results
|
||||
|
||||
def get_widget_or_404(self):
|
||||
"""
|
||||
Get and return widget from cache.
|
||||
|
||||
Raises a 404 if the widget can not be found or no id is provided.
|
||||
|
||||
:raises: Http404
|
||||
:return: ModelSelect2Mixin
|
||||
"""
|
||||
field_id = self.kwargs.get('field_id', self.request.GET.get('field_id', None))
|
||||
if not field_id:
|
||||
raise Http404('No "field_id" provided.')
|
||||
|
@ -44,7 +76,7 @@ class AutoResponseView(BaseListView):
|
|||
raise Http404('Invalid "field_id".')
|
||||
else:
|
||||
cache_key = '%s%s' % (settings.SELECT2_CACHE_PREFIX, key)
|
||||
field = cache.get(cache_key)
|
||||
if field is None:
|
||||
widget = cache.get(cache_key)
|
||||
if widget is None:
|
||||
raise Http404('field_id not found')
|
||||
return field
|
||||
return widget
|
||||
|
|
37
docs/conf.py
37
docs/conf.py
|
@ -11,24 +11,28 @@
|
|||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
import datetime
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
|
||||
|
||||
year = datetime.datetime.now().strftime("%Y")
|
||||
|
||||
# This is needed since django_select2 requires django model modules
|
||||
# and those modules assume that django settings is configured and
|
||||
# have proper DB settings.
|
||||
# Using this we give a proper environment with working django settings.
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "testapp.settings")
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tests.testapp.settings")
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
sys.path.insert(0, os.path.abspath('../testapp'))
|
||||
sys.path.insert(0, os.path.abspath('../tests.testapp'))
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
import datetime
|
||||
year = datetime.datetime.now().strftime("%Y")
|
||||
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
|
@ -40,10 +44,9 @@ year = datetime.datetime.now().strftime("%Y")
|
|||
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.inheritance_diagram', 'sphinx.ext.intersphinx', 'sphinx.ext.viewcode']
|
||||
|
||||
intersphinx_mapping = {
|
||||
'python': ('http://docs.python.org/2.7', None),
|
||||
'django': ('https://docs.djangoproject.com/en/1.4/',
|
||||
'http://www.applegrew.com/others/django.inv'),
|
||||
#'http://docs.djangoproject.com/en/1.4/_objects/'),
|
||||
'python': ('http://docs.python.org/3.5', None),
|
||||
'django': ('https://docs.djangoproject.com/en/dev/',
|
||||
'https://docs.djangoproject.com/en/dev/_objects/'),
|
||||
}
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
|
@ -62,9 +65,11 @@ master_doc = 'index'
|
|||
project = u'Django-Select2'
|
||||
copyright = u'%s, Nirupam Biswas' % year
|
||||
|
||||
|
||||
def get_version():
|
||||
import django_select2
|
||||
return django_select2.__version__
|
||||
import django_select2
|
||||
|
||||
return django_select2.__version__
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
|
@ -120,10 +125,10 @@ def setup(app):
|
|||
autodoc_default_flags = ['members', 'show-inheritance']
|
||||
autodoc_member_order = 'bysource'
|
||||
|
||||
inheritance_graph_attrs = dict(rankdir="TB", size='""')
|
||||
inheritance_graph_attrs = dict(rankdir='TB')
|
||||
|
||||
inheritance_node_attrs = dict(shape='ellipse', fontsize=9,
|
||||
color='"#97C9FD"', style='filled')
|
||||
inheritance_node_attrs = dict(shape='rect', fontsize=14, fillcolor='gray90',
|
||||
color='gray30', style='filled')
|
||||
|
||||
inheritance_edge_attrs = dict(penwidth=0.75)
|
||||
|
||||
|
@ -134,7 +139,7 @@ inheritance_edge_attrs = dict(penwidth=0.75)
|
|||
if on_rtd:
|
||||
html_theme = 'default'
|
||||
else:
|
||||
html_theme = 'nature'
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
|
@ -163,7 +168,7 @@ else:
|
|||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
#html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
API Documentation
|
||||
=================
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
.. automodule:: django_select2.conf
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
Widgets
|
||||
-------
|
||||
|
||||
.. automodule:: django_select2.forms
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
URLs
|
||||
----
|
||||
|
||||
.. automodule:: django_select2.urls
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
Views
|
||||
-----
|
||||
|
||||
.. automodule:: django_select2.views
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
Cache
|
||||
-----
|
||||
|
||||
.. automodule:: django_select2.cache
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
|
@ -1 +0,0 @@
|
|||
Django >= 1.4.1
|
|
@ -11,107 +11,27 @@ Overview
|
|||
Installation
|
||||
------------
|
||||
|
||||
1. Install `django_select2`::
|
||||
1. Install ``django_select2``::
|
||||
|
||||
pip install django_select2
|
||||
|
||||
2. Add `django_select2` to your `INSTALLED_APPS` in your project settings.
|
||||
2. Add ``django_select2`` to your ``INSTALLED_APPS`` in your project settings.
|
||||
|
||||
3. When deploying on production server, run::
|
||||
|
||||
python manage.py collectstatic
|
||||
|
||||
4. Add `django_select` to your urlconf **if** you use any 'Auto' fields::
|
||||
3. Add ``django_select`` to your urlconf **if** you use any 'Auto' fields::
|
||||
|
||||
url(r'^select2/', include('django_select2.urls')),
|
||||
|
||||
5. (Optionally) If you need multiple processes support, then::
|
||||
|
||||
python manage.py syncdb
|
||||
|
||||
Available Settings
|
||||
------------------
|
||||
|
||||
``AUTO_RENDER_SELECT2_STATICS`` [Default ``True``]
|
||||
..................................................
|
||||
|
||||
This, when specified and set to ``False`` in ``settings.py`` then Django_Select2 widgets won't automatically include the required scripts and stylesheets. When this setting is ``True`` then every Select2 field on the page will output ``<script>`` and ``<link>`` tags to include the required JS and CSS files. This is convenient but will output the same JS and CSS files multiple times if there are more than one Select2 fields on the page.
|
||||
|
||||
When this settings is ``False`` then you are responsible for including the JS and CSS files. To help you with this the following template tags are available in ``django_select2_tags``.
|
||||
|
||||
* ``import_django_select2_js`` - Outputs ``<script>`` tags to include all the JS files, required by Light and Heavy widgets.
|
||||
* ``import_django_select2_css`` - Outputs ``<link>`` tags to include all the CSS files, required by Light and Heavy widgets.
|
||||
* ``import_django_select2_js_css`` - Outputs both ``<script>`` and ``<link>`` tags to include all the JS and CSS files, required by Light and Heavy widgets.
|
||||
|
||||
.. tip:: Make sure to include them at the top of the page, preferably in ``<head>...</head>``.
|
||||
|
||||
.. note:: (Since version 3.3.1) The above template tags accept one argument ``light``. Default value for that is ``0``.
|
||||
If that is set to ``1`` then only the JS and CSS libraries needed by Select2Widget (Light fields) are rendered.
|
||||
That effectively leaves out ``heavy.js`` and ``extra.css``.
|
||||
|
||||
``SELECT2_CACHE_BACKEND`` [Default ``default``]
|
||||
...............................................
|
||||
|
||||
Django-Select2 uses Django's cache to sure a consistent state across multiple machines.
|
||||
|
||||
Example of settings.py::
|
||||
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": "django_redis.cache.RedisCache",
|
||||
"LOCATION": "redis://127.0.0.1:6379/1",
|
||||
"OPTIONS": {
|
||||
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||
}
|
||||
},
|
||||
'select2': {
|
||||
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
||||
'LOCATION': '127.0.0.1:11211',
|
||||
}
|
||||
}
|
||||
|
||||
# Set the cache backend to select2
|
||||
SELECT2_CACHE_BACKEND = 'select2'
|
||||
|
||||
.. tip:: To ensure a consistent state across all you machines you need to user
|
||||
a consistent external cache backend like Memcached, Redis or a database.
|
||||
|
||||
.. note:: Select2 requires the cache to never expire. Therefore you should avoid clearing the cache.
|
||||
As third party apps might add unpredictable behavior we recommend to always use an separate cache server.
|
||||
|
||||
``ENABLE_SELECT2_MULTI_PROCESS_SUPPORT`` [Default ``False``]
|
||||
............................................................
|
||||
|
||||
.. warning:: Deprecated in favour of ``SELECT2_CACHE_BACKEND``. Will be removed in version 5.
|
||||
|
||||
Since version 4.3 django-select2 supports multiprocessing support out of the box.
|
||||
If you want to have multiple machine support take a look at ``SELECT2_CACHE_BACKEND``.
|
||||
|
||||
|
||||
``SELECT2_MEMCACHE_HOST`` [Default ``None``], ``SELECT2_MEMCACHE_PORT`` [Default ``None``]
|
||||
..........................................................................................
|
||||
|
||||
.. warning:: Deprecated in favour of ``SELECT2_CACHE_BACKEND``. Will be removed in version 5.
|
||||
|
||||
Since version 4.3 dajngo-select2 uses Django's own caching solution.
|
||||
The hostname and port will be used to create a new django cache backend.
|
||||
|
||||
.. note:: It is recommended to upgrade to ``SELECT2_CACHE_BACKEND`` to avoid cache consistency issues.
|
||||
|
||||
``SELECT2_BOOTSTRAP`` [Default ``False``]
|
||||
.........................................
|
||||
|
||||
Setting to True will include the CSS for making Select2 fit in with Bootstrap a bit better using the css found here https://github.com/fk/select2-bootstrap-css.
|
||||
|
||||
External Dependencies
|
||||
---------------------
|
||||
|
||||
* Django - This is obvious.
|
||||
* jQuery - This is not included in the package since it is expected that in most scenarios this would already be available. The above template tags also won't output ``<script>`` tag to include this. You need to do this yourself.
|
||||
* Memcached (python-memcached) - If you plan on running multiple Python processes, which is usually the case in production, then you need to turn on ``ENABLE_SELECT2_MULTI_PROCESS_SUPPORT``. In that mode it is highly recommended that you use Memcached, to minimize DB hits.
|
||||
* jQuery version 2
|
||||
This is not included in the package since it is expected
|
||||
that in most scenarios this would already be available.
|
||||
|
||||
Example Application
|
||||
-------------------
|
||||
Please see ``testapp`` application. This application is used to manually test the functionalities of this package. This also serves as a good example.
|
||||
|
||||
You need only Django 1.4 or above to run that. It might run on older versions but that is not tested.
|
||||
Please see ``tests/testapp`` application.
|
||||
This application is used to manually test the functionalities of this package.
|
||||
This also serves as a good example.
|
||||
|
|
|
@ -9,9 +9,11 @@ All Contents
|
|||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:glob:
|
||||
|
||||
get_started
|
||||
reference
|
||||
django_select2
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
Fields
|
||||
======
|
||||
|
||||
Class Diagrams
|
||||
--------------
|
||||
|
||||
.. inheritance-diagram:: django_select2.fields.Select2ChoiceField django_select2.fields.Select2MultipleChoiceField
|
||||
:parts: 1
|
||||
|
||||
.. inheritance-diagram:: django_select2.fields.ModelSelect2Field django_select2.fields.ModelSelect2MultipleField
|
||||
:parts: 1
|
||||
|
||||
.. inheritance-diagram:: django_select2.fields.HeavySelect2TagField
|
||||
:parts: 1
|
||||
|
||||
.. inheritance-diagram:: django_select2.fields.HeavyModelSelect2ChoiceField django_select2.fields.HeavyModelSelect2MultipleChoiceField django_select2.fields.HeavyModelSelect2TagField
|
||||
:parts: 1
|
||||
|
||||
.. inheritance-diagram:: django_select2.fields.AutoSelect2Field django_select2.fields.AutoSelect2MultipleField django_select2.fields.AutoSelect2TagField
|
||||
:parts: 1
|
||||
|
||||
.. inheritance-diagram:: django_select2.fields.AutoModelSelect2Field
|
||||
:parts: 1
|
||||
|
||||
.. inheritance-diagram:: django_select2.fields.AutoModelSelect2MultipleField django_select2.fields.AutoModelSelect2TagField
|
||||
:parts: 1
|
||||
|
||||
Reference
|
||||
---------
|
||||
|
||||
.. automodule:: django_select2.fields
|
||||
:members:
|
|
@ -1,15 +0,0 @@
|
|||
Util
|
||||
====
|
||||
|
||||
Class Diagram
|
||||
-------------
|
||||
|
||||
.. inheritance-diagram:: django_select2.util
|
||||
:parts: 1
|
||||
|
||||
|
||||
Reference
|
||||
---------
|
||||
|
||||
.. automodule:: django_select2.util
|
||||
:members:
|
|
@ -1,15 +0,0 @@
|
|||
Views
|
||||
=====
|
||||
|
||||
Class Diagram
|
||||
-------------
|
||||
|
||||
.. inheritance-diagram:: django_select2.views
|
||||
:parts: 1
|
||||
|
||||
|
||||
Reference
|
||||
---------
|
||||
|
||||
.. automodule:: django_select2.views
|
||||
:members:
|
|
@ -1,15 +0,0 @@
|
|||
Widgets
|
||||
=======
|
||||
|
||||
Class Diagram
|
||||
-------------
|
||||
|
||||
.. inheritance-diagram:: django_select2.widgets
|
||||
:parts: 1
|
||||
|
||||
|
||||
Reference
|
||||
---------
|
||||
|
||||
.. automodule:: django_select2.widgets
|
||||
:members:
|
|
@ -1,15 +0,0 @@
|
|||
=============
|
||||
API Reference
|
||||
=============
|
||||
|
||||
The API references also include examples and suggestions, where relevant.
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
|
||||
ref_widgets
|
||||
ref_fields
|
||||
ref_views
|
||||
ref_util
|
||||
|
|
@ -11,7 +11,6 @@ show-source = true
|
|||
exclude = docs,runtests.py,setup.py,env
|
||||
|
||||
[pep257]
|
||||
ignore = D100,D101,D102,D103
|
||||
explain = true
|
||||
count = true
|
||||
|
||||
|
|
4
setup.py
4
setup.py
|
@ -17,7 +17,7 @@ def read(file_name):
|
|||
PACKAGE = "django_select2"
|
||||
NAME = "Django-Select2"
|
||||
DESCRIPTION = "Select2 option fields for Django"
|
||||
AUTHOR = "Nirupam Biswas"
|
||||
AUTHOR = "Nirupam Biswas, Johannes Hoppe"
|
||||
AUTHOR_EMAIL = "admin@applegrew.com"
|
||||
URL = "https://github.com/applegrew/django-select2"
|
||||
VERSION = __import__(PACKAGE).__version__
|
||||
|
@ -49,7 +49,7 @@ setup(
|
|||
author_email=AUTHOR_EMAIL,
|
||||
license="LICENSE.txt",
|
||||
url=URL,
|
||||
packages=find_packages(),
|
||||
packages=find_packages('django_select2'),
|
||||
include_package_data=True,
|
||||
classifiers=[
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
|
|
Loading…
Reference in New Issue