Added documentation

This commit is contained in:
Johannes Hoppe 2015-09-25 22:11:50 +02:00
parent 5dfd8553cc
commit f301dc6f9d
22 changed files with 443 additions and 411 deletions

View File

@ -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
View File

@ -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.

View File

@ -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

View File

@ -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"

View File

@ -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'

View File

@ -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

View File

@ -1 +1 @@
# Django legacy file
"""Django legacy file."""

View 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

View File

@ -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

View File

@ -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.

42
docs/django_select2.rst Normal file
View File

@ -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:

View File

@ -1 +0,0 @@
Django >= 1.4.1

View File

@ -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.

View File

@ -9,9 +9,11 @@ All Contents
Contents:
.. toctree::
:maxdepth: 2
:glob:
get_started
reference
django_select2
Indices and tables
==================

View File

@ -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:

View File

@ -1,15 +0,0 @@
Util
====
Class Diagram
-------------
.. inheritance-diagram:: django_select2.util
:parts: 1
Reference
---------
.. automodule:: django_select2.util
:members:

View File

@ -1,15 +0,0 @@
Views
=====
Class Diagram
-------------
.. inheritance-diagram:: django_select2.views
:parts: 1
Reference
---------
.. automodule:: django_select2.views
:members:

View File

@ -1,15 +0,0 @@
Widgets
=======
Class Diagram
-------------
.. inheritance-diagram:: django_select2.widgets
:parts: 1
Reference
---------
.. automodule:: django_select2.widgets
:members:

View File

@ -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

View File

View File

@ -11,7 +11,6 @@ show-source = true
exclude = docs,runtests.py,setup.py,env
[pep257]
ignore = D100,D101,D102,D103
explain = true
count = true

View File

@ -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",