Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ repos:
rev: v0.20.0
hooks:
- id: yamlfmt
- repo: https://github.com/sphinx-contrib/sphinx-lint
rev: v1.0.2
hooks:
- id: sphinx-lint
ci:
autoupdate_schedule: weekly
skip:
Expand Down
44 changes: 26 additions & 18 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
Contributing
============
##############
Contributing
##############

Before you start editing the python code, you will need to make sure
you have binary dependencies installed::
Before you start editing the python code, you will need to make sure you
have binary dependencies installed:

# Debian
sudo apt install -y gettext graphviz google-chrome-stable
# macOS
brew install -y gettext graphviz google-chrome-stable
.. code::

You may run the tests via::
# Debian
sudo apt install -y gettext graphviz google-chrome-stable
# macOS
brew install -y gettext graphviz google-chrome-stable

uv run pytest
You may run the tests via:

Documentation pull requests welcome. The Sphinx documentation can be compiled via::
.. code::

uv run sphinx-build -W -b doctest -b html docs docs/_build/html
uv run pytest

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.
Documentation pull requests welcome. The Sphinx documentation can be
compiled via:

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.
.. code::

uv run sphinx-build -W -b doctest -b html docs docs/_build/html

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.
4 changes: 0 additions & 4 deletions MANIFEST.in

This file was deleted.

24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/codingjoe/django-select2/raw/main/images/logo-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="https://github.com/codingjoe/django-select2/raw/main/images/logo-light.svg">
<img alt="Django Select2: Custom autocomplete fields for Django" src="https://github.com/codingjoe/django-select2/raw/main/images/logo-light.svg">
</picture>
<br>
<a href="https://django-select2.rtfd.io">Documentation</a>
</p>

# Django-Select2

[![version](https://img.shields.io/pypi/v/Django-Select2.svg)](https://pypi.python.org/pypi/Django-Select2/)
[![coverage](https://codecov.io/gh/codingjoe/django-select2/branch/main/graph/badge.svg)](https://codecov.io/gh/codingjoe/django-select2)
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/codingjoe/django-select2/main/LICENSE.txt)

Custom autocomplete fields for [Django](https://www.djangoproject.com/).

## Documentation

Documentation available at <https://django-select2.rtfd.io>.

> [!NOTE]
> Django's admin comes with builtin support for Select2 via the [autocomplete_fields](https://docs.djangoproject.com/en/stable/ref/contrib/admin/#django.contrib.admin.ModelAdmin.autocomplete_fields) feature.
31 changes: 0 additions & 31 deletions README.rst

This file was deleted.

7 changes: 0 additions & 7 deletions SECURITY.md

This file was deleted.

1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
version = ".".join(release.split(".")[:2])

master_doc = "index" # default in Sphinx v2
html_theme = "furo"


extensions = [
Expand Down
190 changes: 103 additions & 87 deletions docs/django_select2.rst
Original file line number Diff line number Diff line change
@@ -1,124 +1,140 @@
API Documentation
=================
###################
API Documentation
###################

Configuration
-------------
***************
Configuration
***************

.. automodule:: django_select2.conf
:members:
:undoc-members:
:show-inheritance:
:members:
:undoc-members:
:show-inheritance:

Widgets
-------
*********
Widgets
*********

.. automodule:: django_select2.forms
:members:
:undoc-members:
:show-inheritance:
:members:
:undoc-members:
:show-inheritance:

URLs
----
******
URLs
******

.. automodule:: django_select2.urls
:members:
:undoc-members:
:show-inheritance:
:members:
:undoc-members:
:show-inheritance:

Views
-----
*******
Views
*******

.. automodule:: django_select2.views
:members:
:undoc-members:
:show-inheritance:
:members:
:undoc-members:
:show-inheritance:

Cache
-----
*******
Cache
*******

.. automodule:: django_select2.cache
:members:
:undoc-members:
:show-inheritance:
:members:
:undoc-members:
:show-inheritance:

************
JavaScript
************

JavaScript
----------
DjangoSelect2 handles the initialization of select2 fields
automatically. Just include ``{{ form.media.js }}`` in your template
before the closing ``body`` tag. That's it!

DjangoSelect2 handles the initialization of select2 fields automatically. Just include
``{{ 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,
replacing and enhancing the Select2 plugin. It will handle both normal
and heavy fields. Simply call ``djangoSelect2(options)`` on your select
fields.:

If you insert forms after page load or if you want to handle the initialization
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.::
.. code::

$('.django-select2').djangoSelect2();
$('.django-select2').djangoSelect2();

Please replace all your ``.select2`` invocations with the here provided
``.djangoSelect2``.

*********************
Configuring Select2
*********************

Configuring Select2
-------------------

Select2 options can be configured either directly from Javascript or from within Django
using widget attributes. `(List of options in the Select2 docs) <https://select2.org/configuration/options-api>`_.
Select2 options can be configured either directly from Javascript or
from within Django using widget attributes. `(List of options in the
Select2 docs) <https://select2.org/configuration/options-api>`_.

To pass options in javascript

.. code-block:: javascript

$('.django-select2').djangoSelect2({
minimumInputLength: 0,
placeholder: 'Select an option',
});

From Django, you can use ``data-`` attributes using the same names in camel-case and
passing them to your widget. Select2 will then pick these up. For example when
initialising a widget in a form, you could do:

.. code-block:: python

class MyForm(forms.Form):
my_field = forms.ModelMultipleChoiceField(
widget=ModelSelect2MultipleWidget(
model=MyModel
search_fields=['another_field']
attrs={
"data-minimum-input-length": 0,
"data-placeholder": "Select an option",
"data-close-on-select": "false",
}
)
)

(If you do not want to initialize the widget, you could add the attributes by overriding
a widget method and adding them in a super call, e.g. `get_context() <https://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.Widget.get_context>`_)


Security & Authentication
-------------------------
.. code:: javascript

$('.django-select2').djangoSelect2({
minimumInputLength: 0,
placeholder: 'Select an option',
});

From Django, you can use ``data-`` attributes using the same names in
camel-case and passing them to your widget. Select2 will then pick these
up. For example when initialising a widget in a form, you could do:

.. code:: python

class MyForm(forms.Form):
my_field = forms.ModelMultipleChoiceField(
widget=ModelSelect2MultipleWidget(
model=MyModel
search_fields=['another_field']
attrs={
"data-minimum-input-length": 0,
"data-placeholder": "Select an option",
"data-close-on-select": "false",
}
)
)

(If you do not want to initialize the widget, you could add the
attributes by overriding a widget method and adding them in a super
call, e.g. `get_context()
<https://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.Widget.get_context>`_)

***************************
Security & Authentication
***************************

Security is important. Therefore make sure to read and understand what
the security measures in place and their limitations.

Set up a separate cache. If you have a public form that uses a model widget
make sure to setup a separate cache database for Select2. An attacker
could constantly reload your site and fill up the select2 cache.
Having a separate cache allows you to limit the effect to select2 only.
Set up a separate cache. If you have a public form that uses a model
widget make sure to setup a separate cache database for Select2. An
attacker could constantly reload your site and fill up the select2
cache. Having a separate cache allows you to limit the effect to select2
only.

You might want to add a secure select2 JSON endpoint for data you don't
want to be accessible to the general public. Doing so is easy::
want to be accessible to the general public. Doing so is easy:

.. code::

class UserSelect2View(LoginRequiredMixin, AutoResponseView):
pass
class UserSelect2View(LoginRequiredMixin, AutoResponseView):
pass

class UserSelect2WidgetMixin(object):
def __init__(self, *args, **kwargs):
kwargs['data_view'] = 'user-select2-view'
super(UserSelect2WidgetMixin, self).__init__(*args, **kwargs)
class UserSelect2WidgetMixin(object):
def __init__(self, *args, **kwargs):
kwargs['data_view'] = 'user-select2-view'
super(UserSelect2WidgetMixin, self).__init__(*args, **kwargs)

class MySecretWidget(UserSelect2WidgetMixin, ModelSelect2Widget):
model = MySecretModel
search_fields = ['title__icontains']
class MySecretWidget(UserSelect2WidgetMixin, ModelSelect2Widget):
model = MySecretModel
search_fields = ['title__icontains']
Loading
Loading