Added tests

This commit is contained in:
Johannes Hoppe 2015-09-16 11:02:44 +02:00
parent f80abb10f2
commit 5dfd8553cc
15 changed files with 413 additions and 343 deletions

View file

@ -14,23 +14,19 @@ env:
global:
- DISPLAY=:99.0
matrix:
- DJANGO="Django<1.7,>=1.6"
- DJANGO="Django<1.8,>=1.7"
- DJANGO="Django<1.9,>=1.8"
- DJANGO="-e git+https://github.com/django/django.git@master#egg=Django"
matrix:
fast_finish: true
allow_failures:
- env: DJANGO="Django<1.7,>=1.6"
- env: DJANGO="-e git+https://github.com/django/django.git@master#egg=Django"
- python: "pypy"
- python: "pypy3"
install:
- pip install --upgrade pip
- pip install -e .
- pip install -r requirements_dev.txt
- if [[ $TRAVIS_PYTHON_VERSION == 2* ]]; then pip install python-memcached; fi
- if [[ $TRAVIS_PYTHON_VERSION == 3* ]]; then pip install python3-memcached; fi
- if [[ $TRAVIS_PYTHON_VERSION == 2* ]] || [[ $TRAVIS_PYTHON_VERSION == pypy ]]; then pip install python-memcached; fi
- if [[ $TRAVIS_PYTHON_VERSION == 3* ]] || [[ $TRAVIS_PYTHON_VERSION == pypy3 ]]; then pip install python3-memcached; fi
- pip install $DJANGO
- pip install coveralls
- sh -e /etc/init.d/xvfb start

View file

@ -58,7 +58,7 @@ Light widgets are normally named, i.e. there is no
:py:class:`.ModelSelect2Widget`,
:py:class:`.ModelSelect2MultipleWidget`,
:py:class:`.HeavySelect2TagWidget`,
:py:class:`.ModelSelect2TagWidget`
:py:class:`.GenreSelect2TagWidget`
`Read more`_

View file

@ -32,14 +32,14 @@ class Select2Mixin(object):
"""
def build_attrs(self, extra_attrs=None, **kwargs):
attrs = super(Select2Mixin, self).build_attrs(extra_attrs=None, **kwargs)
attrs = super(Select2Mixin, self).build_attrs(extra_attrs=extra_attrs, **kwargs)
if self.is_required:
attrs.setdefault('data-allow-clear', 'false')
else:
attrs.setdefault('data-allow-clear', 'true')
attrs.setdefault('data-placeholder', '')
attrs.setdefault('data-minimumInputLength', 0)
attrs.setdefault('data-minimum-input-length', 0)
if 'class' in attrs:
attrs['class'] += ' django-select2'
else:
@ -47,7 +47,7 @@ class Select2Mixin(object):
return attrs
def render_options(self, choices, selected_choices):
output = '<option></option>\n' if not self.is_required else ''
output = '<option></option>' if not self.is_required else ''
output += super(Select2Mixin, self).render_options(choices, selected_choices)
return output
@ -86,7 +86,7 @@ class HeavySelect2Mixin(Select2Mixin):
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):
ValueError('You must ether specify "data_view" or "data_url".')
raise ValueError('You must ether specify "data_view" or "data_url".')
self.userGetValTextFuncName = kwargs.pop('userGetValTextFuncName', 'null')
super(HeavySelect2Mixin, self).__init__(**kwargs)
@ -96,39 +96,37 @@ class HeavySelect2Mixin(Select2Mixin):
return reverse_lazy(self.data_view)
def build_attrs(self, extra_attrs=None, **kwargs):
attrs = super(HeavySelect2Mixin, self).build_attrs(extra_attrs, **kwargs)
attrs = super(HeavySelect2Mixin, self).build_attrs(extra_attrs=extra_attrs, **kwargs)
# encrypt instance Id
widget_id = signing.dumps(id(self))
# add widget object to cache
cache.set(self._get_cache_key(), self)
self.widget_id = signing.dumps(id(self))
attrs['data-field_id'] = widget_id
attrs['data-field_id'] = self.widget_id
attrs.setdefault('data-ajax--url', self.get_url())
attrs.setdefault('data-ajax--cache', "true")
attrs.setdefault('data-ajax--type', "GET")
attrs.setdefault('data-minimumInputLength', 2)
attrs.setdefault('data-minimum-input-length', 2)
if 'class' in attrs:
attrs['class'] += ' django-select2-heavy'
else:
attrs['class'] = 'django-select2-heavy'
attrs['class'] += ' django-select2-heavy'
return attrs
def render(self, name, value, attrs=None, choices=()):
output = super(HeavySelect2Mixin, self).render(name, value, attrs=attrs, choices=choices)
self.set_to_cache()
return output
def _get_cache_key(self):
return "%s%s" % (settings.SELECT2_CACHE_PREFIX, id(self))
def value_from_datadict(self, *args, **kwargs):
return super(HeavySelect2Mixin, self).value_from_datadict(*args, **kwargs)
def set_to_cache(self):
"""Add widget object to Djnago's cache."""
cache.set(self._get_cache_key(), self)
def render_options(self, choices, selected_choices):
output = [super(HeavySelect2Mixin, self).render_options(choices, selected_choices)]
if isinstance(choices, ModelChoiceIterator):
selected_choices = set(choices.choice(obj)
for obj in choices.queryset.filter(pk__in=selected_choices))
else:
selected_choices = set((force_text(v), v) for v in choices if v in selected_choices)
for option_label, option_value in selected_choices:
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}
for option_value, option_label in choices:
output.append(self.render_option(selected_choices, option_value, option_label))
return '\n'.join(output)
@ -143,10 +141,10 @@ class HeavySelect2MultipleWidget(HeavySelect2Mixin, forms.SelectMultiple):
class HeavySelect2TagWidget(HeavySelect2MultipleWidget):
def build_attrs(self, extra_attrs=None, **kwargs):
attrs = super(HeavySelect2TagWidget, self).build_attrs(self, extra_attrs, **kwargs)
attrs['data-minimumInputLength'] = 1
attrs = super(HeavySelect2TagWidget, self).build_attrs(extra_attrs, **kwargs)
attrs['data-minimum-input-length'] = 1
attrs['data-tags'] = 'true'
attrs['data-tokenSeparators'] = [",", " "]
attrs['data-token-separators'] = [",", " "]
return attrs
@ -154,9 +152,6 @@ class HeavySelect2TagWidget(HeavySelect2MultipleWidget):
class ModelSelect2Mixin(object):
"""Mixin for """
model = None
queryset = None
search_fields = []
@ -198,6 +193,22 @@ class ModelSelect2Mixin(object):
return self.search_fields
raise NotImplementedError('%s, must implement "search_fields".' % self.__class__.__name__)
def render_options(self, choices, selected_choices):
output = ['<option></option>' if not self.is_required else '']
if isinstance(self.choices, ModelChoiceIterator):
if not self.queryset:
self.queryset = self.choices.queryset
selected_choices = {c for c in selected_choices
if c not in self.choices.field.empty_values}
choices = {self.choices.choice(obj)
for obj in self.choices.queryset.filter(pk__in=selected_choices)}
else:
choices = {(k, v) for k, v in choices if k in selected_choices}
selected_choices = {force_text(v) for v in selected_choices}
for option_value, option_label in choices:
output.append(self.render_option(selected_choices, option_value, option_label))
return '\n'.join(output)
class ModelSelect2Widget(ModelSelect2Mixin, HeavySelect2Widget):

View file

@ -1,4 +1,5 @@
[pytest]
norecursedirs = env
addopts = --tb=short -rxs
DJANGO_SETTINGS_MODULE=tests.testapp.settings

View file

@ -23,50 +23,6 @@ URL = "https://github.com/applegrew/django-select2"
VERSION = __import__(PACKAGE).__version__
def getPkgPath():
return __import__(PACKAGE).__path__[0] + '/'
def minify(files, outfile, ftype):
import requests
import io
content = ''
for filename in files:
with io.open(getPkgPath() + filename, 'r', encoding='utf8') as f:
content = content + '\n' + f.read()
data = {
'code': content,
'type': ftype,
}
response = requests.post('http://api.applegrew.com/minify', data)
response.raise_for_status()
response = response.json()
if response['success']:
with io.open(getPkgPath() + outfile, 'w', encoding='utf8') as f:
f.write(response['compiled_code'])
else:
raise Exception('%(error_code)s: "%(error)s"' % response)
if len(sys.argv) > 1 and 'sdist' == sys.argv[1]:
minify(['static/django_select2/js/select2.js'], 'static/django_select2/js/select2.min.js', 'js')
minify(['static/django_select2/js/heavy_data.js'], 'static/django_select2/js/heavy_data.min.js', 'js')
minify(['static/django_select2/css/select2.css'], 'static/django_select2/css/select2.min.css', 'css')
minify(['static/django_select2/css/select2.css', 'static/django_select2/css/extra.css'],
'static/django_select2/css/all.min.css', 'css')
minify(['static/django_select2/css/select2.css', 'static/django_select2/css/select2-bootstrap.css'],
'static/django_select2/css/select2-bootstrapped.min.css', 'css')
minify(
[
'static/django_select2/css/select2.css',
'static/django_select2/css/extra.css',
'static/django_select2/css/select2-bootstrap.css'
], 'static/django_select2/css/all-bootstrapped.min.css', 'css')
class PyTest(Command):
user_options = []
@ -102,6 +58,10 @@ setup(
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 3",
"Framework :: Django :: 1.7",
"Framework :: Django :: 1.8",
"Framework :: Django",
],
install_requires=[

View file

@ -1,50 +0,0 @@
# -*- coding:utf-8 -*-
from __future__ import print_function, unicode_literals
import json
import pytest
from django.core.urlresolvers import reverse
from django.utils.encoding import smart_text
from selenium.common.exceptions import NoSuchElementException
from django_select2.types import NO_ERR_RESP
from tests.testapp.forms import AlbumForm, ArtistForm
class ViewTestMixin(object):
url = ''
def test_get(self, client):
response = client.get(self.url)
assert response.status_code == 200
class TestAutoModelSelect2TagField(object):
url = reverse('single_value_model_field')
def test_no_js_error(self, db, client, live_server, driver, genres):
driver.get(live_server + self.url)
with pytest.raises(NoSuchElementException):
error = driver.find_element_by_xpath('//body[@JSError]')
pytest.fail(error.get_attribute('JSError'))
def test_form(self):
form = ArtistForm()
assert form
class TestAutoModelSelect2Field(object):
def test_form(self, client, artists):
artist = artists[0]
form = AlbumForm()
assert form.as_p()
field_id = form.fields['artist'].widget.widget_id
url = reverse('django_select2_central_json')
response = client.get(url, {'field_id': field_id, 'term': artist.title})
assert response.status_code == 200
data = json.loads(response.content.decode('utf-8'))
assert data['results']
assert {'id': artist.pk, 'text': smart_text(artist)} in data['results']
assert data['more'] is False
assert data['err'] == NO_ERR_RESP

188
tests/test_forms.py Normal file
View file

@ -0,0 +1,188 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
import collections
import json
import pytest
from django.core import signing
from django.core.urlresolvers import reverse
from django.db.models import QuerySet
from django.utils.encoding import force_text
from model_mommy import mommy
from selenium.common.exceptions import NoSuchElementException
from six import text_type
from django_select2.cache import cache
from django_select2.forms import (
HeavySelect2Widget, ModelSelect2TagWidget, ModelSelect2Widget,
Select2Widget
)
from tests.testapp import forms
from tests.testapp.forms import NUMBER_CHOICES, HeavySelect2MultipleWidgetForm
from tests.testapp.models import Genre
class TestSelect2Mixin(object):
url = reverse('select2_widget')
form = forms.AlbumSelect2WidgetForm()
widget_cls = Select2Widget
def test_initial_form_class(self):
widget = self.widget_cls(attrs={'class': 'my-class'})
assert 'my-class' in widget.render('name', None)
assert 'django-select2' in widget.render('name', None)
def test_allow_clear(self, db):
required_field = self.form.fields['artist']
assert required_field.required is True
assert 'data-allow-clear="true"' not in required_field.widget.render('artist', None)
assert 'data-allow-clear="false"' in required_field.widget.render('artist', None)
assert '<option></option>' not in required_field.widget.render('artist', None)
not_required_field = self.form.fields['primary_genre']
assert not_required_field.required is False
assert 'data-allow-clear="true"' in not_required_field.widget.render('primary_genre', None)
assert 'data-allow-clear="false"' not in not_required_field.widget.render('primary_genre',
None)
assert 'data-placeholder' in not_required_field.widget.render('primary_genre', None)
assert '<option></option>' in not_required_field.widget.render('primary_genre', None)
def test_no_js_error(self, db, live_server, driver):
driver.get(live_server + self.url)
with pytest.raises(NoSuchElementException):
error = driver.find_element_by_xpath('//body[@JSError]')
pytest.fail(error.get_attribute('JSError'))
def test_selecting(self, db, live_server, driver):
driver.get(live_server + self.url)
with pytest.raises(NoSuchElementException):
driver.find_element_by_css_selector('.select2-results')
elem = driver.find_element_by_css_selector('.select2-selection')
elem.click()
results = driver.find_element_by_css_selector('.select2-results')
assert results.is_displayed() is True
elem = results.find_element_by_css_selector('.select2-results__option')
elem.click()
with pytest.raises(NoSuchElementException):
error = driver.find_element_by_xpath('//body[@JSError]')
pytest.fail(error.get_attribute('JSError'))
def test_data_url(self):
with pytest.raises(ValueError):
HeavySelect2Widget()
widget = HeavySelect2Widget(data_url='/foo/bar')
assert widget.get_url() == '/foo/bar'
class TestHeavySelect2Mixin(TestSelect2Mixin):
url = reverse('heavy_select2_widget')
form = forms.HeavySelect2WidgetForm(initial={'primary_genre': [1]})
widget_cls = HeavySelect2Widget
def test_initial_form_class(self):
widget = self.widget_cls(data_view='heavy_data', attrs={'class': 'my-class'})
assert 'my-class' in widget.render('name', None)
assert 'django-select2' in widget.render('name', None)
assert 'django-select2-heavy' in widget.render('name', None), widget.render('name', None)
def test_selected_option(self, db):
not_required_field = self.form.fields['primary_genre']
assert not_required_field.required is False
assert '<option value="1" selected="selected">One</option>' in \
not_required_field.widget.render('primary_genre', 1, choices=NUMBER_CHOICES), \
not_required_field.widget.render('primary_genre', 1, choices=NUMBER_CHOICES)
def test_many_selected_option(self, db, genres):
field = HeavySelect2MultipleWidgetForm().fields['genres']
widget_output = field.widget.render(
'genres', [1, 2],
choices=NUMBER_CHOICES)
selected_option = '<option value="{pk}" selected="selected">{value}</option>'.format(pk=1, value='One')
selected_option2 = '<option value="{pk}" selected="selected">{value}</option>'.format(pk=2, value='Two')
assert selected_option in widget_output, widget_output
assert selected_option2 in widget_output
class TestModelSelect2Mixin(TestHeavySelect2Mixin):
form = forms.AlbumModelSelect2WidgetForm(initial={'primary_genre': 1})
@pytest.fixture(autouse=True)
def genres(self, db):
return mommy.make(Genre, 100)
def test_selected_option(self, db, genres):
genre = genres[0]
genre2 = genres[1]
not_required_field = self.form.fields['primary_genre']
assert not_required_field.required is False
widget_output = not_required_field.widget.render(
'primary_genre', genre.pk)
selected_option = '<option value="{pk}" selected="selected">{value}</option>'.format(
pk=genre.pk, value=force_text(genre))
unselected_option = '<option value="{pk}">{value}</option>'.format(
pk=genre2.pk, value=force_text(genre2))
assert selected_option in widget_output, widget_output
assert unselected_option not in widget_output
def test_get_queryset(self):
widget = ModelSelect2Widget()
with pytest.raises(NotImplementedError):
widget.get_queryset()
widget.model = Genre
assert isinstance(widget.get_queryset(), QuerySet)
widget.model = None
widget.queryset = Genre.objects.all()
assert isinstance(widget.get_queryset(), QuerySet)
def test_get_search_fields(self):
widget = ModelSelect2Widget()
with pytest.raises(NotImplementedError):
widget.get_search_fields()
widget.search_fields = ['title__icontains']
assert isinstance(widget.get_search_fields(), collections.Iterable)
assert all(isinstance(x, text_type) for x in widget.get_search_fields())
def test_model_kwarg(self):
widget = ModelSelect2Widget(model=Genre, search_fields=['title__icontains'])
genre = Genre.objects.last()
result = widget.filter_queryset(genre.title)
assert result.exists()
def test_queryset_kwarg(self):
widget = ModelSelect2Widget(queryset=Genre.objects, search_fields=['title__icontains'])
genre = Genre.objects.last()
result = widget.filter_queryset(genre.title)
assert result.exists()
def test_ajax_view_registration(self, client):
widget = ModelSelect2Widget(queryset=Genre.objects, search_fields=['title__icontains'])
widget.render('name', 'value')
url = reverse('django_select2-json')
genre = Genre.objects.last()
response = client.get(url, data=dict(field_id=signing.dumps(id(widget)), term=genre.title))
assert response.status_code == 200, response.content
data = json.loads(response.content.decode('utf-8'))
assert data['results']
assert genre.pk in [result['id'] for result in data['results']]
def test_render(self):
widget = ModelSelect2Widget()
widget.render('name', 'value')
cached_widget = cache.get(widget._get_cache_key())
assert isinstance(cached_widget, ModelSelect2Widget)
class TestHeavySelect2TagWidget(TestHeavySelect2Mixin):
def test_tag_attrs(self):
widget = ModelSelect2TagWidget(queryset=Genre.objects, search_fields=['title__icontains'])
output = widget.render('name', 'value')
assert 'data-minimum-input-length="1"' in output
assert 'data-tags="true"' in output
assert 'data-token-separators' in output

43
tests/test_views.py Normal file
View file

@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
import json
from django.core import signing
from django.core.urlresolvers import reverse
from django.utils.encoding import smart_text
from tests.testapp.forms import AlbumModelSelect2WidgetForm
class TestAutoResponseView(object):
def test_get(self, client, artists):
artist = artists[0]
form = AlbumModelSelect2WidgetForm()
assert form.as_p()
field_id = signing.dumps(id(form.fields['artist'].widget))
url = reverse('django_select2-json')
response = client.get(url, {'field_id': field_id, 'term': artist.title})
assert response.status_code == 200
data = json.loads(response.content.decode('utf-8'))
assert data['results']
assert {'id': artist.pk, 'text': smart_text(artist)} in data['results']
def test_no_field_id(self, client, artists):
artist = artists[0]
url = reverse('django_select2-json')
response = client.get(url, {'term': artist.title})
assert response.status_code == 404
def test_wrong_field_id(self, client, artists):
artist = artists[0]
url = reverse('django_select2-json')
response = client.get(url, {'field_id': 123, 'term': artist.title})
assert response.status_code == 404
def test_field_id_not_found(self, client, artists):
artist = artists[0]
field_id = signing.dumps(123456789)
url = reverse('django_select2-json')
response = client.get(url, {'field_id': field_id, 'term': artist.title})
assert response.status_code == 404

View file

@ -1,137 +0,0 @@
# -*- coding:utf-8 -*-
from __future__ import print_function, unicode_literals
import json
from collections import Iterable
import pytest
from django.core import signing
from django.core.urlresolvers import reverse
from django.db.models import QuerySet
from model_mommy import mommy
from selenium.common.exceptions import NoSuchElementException
from six import text_type
from django_select2.cache import cache
from django_select2.forms import ModelSelect2Widget
from tests.testapp.models import Genre
class TestWidgets(object):
url = ""
def test_is_hidden_multiple(self):
from django_select2.forms import HeavySelect2MultipleWidget
new_widget = HeavySelect2MultipleWidget(data_url="/")
assert new_widget.is_hidden is False
def test_is_hidden(self):
from django_select2.forms import HeavySelect2Widget
new_widget = HeavySelect2Widget(data_url="/")
assert new_widget.is_hidden is False
class TestSelect2Widget(object):
url = reverse('select2_widget')
def test_selecting(self, db, client, live_server, driver):
driver.get(live_server + self.url)
dropdown = driver.find_element_by_css_selector('.select2-results')
assert dropdown.is_displayed() is False
elem = driver.find_element_by_css_selector('.select2-choice')
elem.click()
assert dropdown.is_displayed() is True
with pytest.raises(NoSuchElementException):
error = driver.find_element_by_xpath('//body[@JSError]')
pytest.fail(error.get_attribute('JSError'))
class TestHeavySelect2Widget(object):
url = reverse('heavy_select2_widget')
def test_heavy_select(self, db, client, live_server, driver):
driver.get(live_server + self.url)
dropdown = driver.find_element_by_css_selector('.select2-results')
assert dropdown.is_displayed() is False
elem = driver.find_element_by_css_selector('.select2-choice')
elem.click()
assert dropdown.is_displayed() is True
with pytest.raises(NoSuchElementException):
error = driver.find_element_by_xpath('//body[@JSError]')
pytest.fail(error.get_attribute('JSError'))
class TestHeavySelect2MultipleWidget(object):
url = reverse('heavy_select2_multiple_widget')
def test_heavy_select_multiple(self, db, client, live_server, driver):
driver.get(live_server + self.url)
dropdown = driver.find_element_by_css_selector('.select2-results')
assert dropdown.is_displayed() is False
elem = driver.find_element_by_css_selector('.select2-choices')
elem.click()
assert dropdown.is_displayed() is True
with pytest.raises(NoSuchElementException):
error = driver.find_element_by_xpath('//body[@JSError]')
pytest.fail(error.get_attribute('JSError'))
class TestHeavySelect2Mixin(object):
@pytest.fixture(autouse=True)
def genres(self, db):
mommy.make(Genre, 100)
def test_get_queryset(self):
widget = ModelSelect2Widget()
with pytest.raises(NotImplementedError):
widget.get_queryset()
widget.model = Genre
assert isinstance(widget.get_queryset(), QuerySet)
widget.model = None
widget.queryset = Genre.objects.all()
assert isinstance(widget.get_queryset(), QuerySet)
def test_get_search_fields(self):
widget = ModelSelect2Widget()
with pytest.raises(NotImplementedError):
widget.get_search_fields()
widget.search_fields = ['title__icontains']
assert isinstance(widget.get_search_fields(), Iterable)
assert all(isinstance(x, text_type) for x in widget.get_search_fields())
def test_model_kwarg(self):
widget = ModelSelect2Widget(model=Genre, search_fields=['title__icontains'])
genre = Genre.objects.last()
result = widget.filter_queryset(genre.title)
assert result.exists()
def test_queryset_kwarg(self):
widget = ModelSelect2Widget(queryset=Genre.objects, search_fields=['title__icontains'])
genre = Genre.objects.last()
result = widget.filter_queryset(genre.title)
assert result.exists()
def test_widget_id(self):
widget = ModelSelect2Widget()
widget.render('name', 'value')
assert widget.widget_id
assert signing.loads(widget.widget_id) == id(widget)
def test_render(self):
widget = ModelSelect2Widget()
widget.render('name', 'value')
cached_widget = cache.get(widget._get_cache_key())
assert isinstance(cached_widget, ModelSelect2Widget)
assert cached_widget.widget_id == widget.widget_id
def test_ajax_view_registration(self, client):
widget = ModelSelect2Widget(queryset=Genre.objects, search_fields=['title__icontains'])
widget.render('name', 'value')
url = reverse('django_select2_central_json')
genre = Genre.objects.last()
response = client.get(url, data=dict(field_id=widget.widget_id, term=genre.title))
assert response.status_code == 200, response.content
data = json.loads(response.content.decode('utf-8'))
assert data['results']
assert genre.pk in [result['id'] for result in data['results']]

View file

@ -4,76 +4,137 @@ from __future__ import absolute_import, unicode_literals
from django import forms
from django_select2.forms import (
HeavySelect2MultipleWidget, HeavySelect2Widget, Select2MultipleWidget,
Select2Widget,
ModelSelect2MultipleWidget, ModelSelect2Widget)
HeavySelect2MultipleWidget, HeavySelect2Widget, ModelSelect2MultipleWidget,
ModelSelect2TagWidget, ModelSelect2Widget, Select2MultipleWidget,
Select2Widget
)
from tests.testapp import models
from tests.testapp.models import Album
class GenreModelForm(forms.ModelForm):
class TitleSearchFieldMixin(object):
search_fields = [
'title__icontains'
]
class TitleModelSelect2Widget(TitleSearchFieldMixin, ModelSelect2Widget):
pass
class TitleModelSelect2MultipleWidget(TitleSearchFieldMixin, ModelSelect2MultipleWidget):
pass
class GenreSelect2TagWidget(TitleSearchFieldMixin, ModelSelect2TagWidget):
model = models.Genre
def create_value(self, value):
self.get_queryset().create(title=value)
class AlbumSelect2WidgetForm(forms.ModelForm):
class Meta:
model = models.Genre
model = models.Album
fields = (
'title',
)
class GenreForm(forms.Form):
title = forms.CharField(max_length=50)
class ArtistModelForm(forms.ModelForm):
test = forms.BooleanField('asdf')
class Meta:
model = models.Artist
fields = (
'title',
'genres',
'artist',
'primary_genre',
)
widgets = {
'genres': Select2MultipleWidget
'artist': Select2Widget,
'primary_genre': Select2Widget,
}
class ArtistForm(forms.Form):
class AlbumSelect2MultipleWidgetForm(forms.ModelForm):
class Meta:
model = models.Album
fields = (
'genres',
'featured_artists',
)
widgets = {
'genres': Select2MultipleWidget,
'featured_artists': Select2MultipleWidget,
}
class AlbumModelSelect2WidgetForm(forms.ModelForm):
class Meta:
model = models.Album
fields = (
'artist',
'primary_genre',
)
widgets = {
'artist': ModelSelect2Widget(
model=models.Artist,
search_fields=['title__icontains']
),
'primary_genre': ModelSelect2Widget(
model=models.Genre,
search_fields=['title__icontains']
),
}
class AlbumModelSelect2MultipleWidgetRequiredForm(forms.ModelForm):
class Meta:
model = Album
fields = (
'genres',
'featured_artists',
)
widgets = {
'genres': TitleModelSelect2MultipleWidget,
'featured_artists': TitleModelSelect2MultipleWidget,
}
class ArtistModelSelect2MultipleWidgetForm(forms.Form):
title = forms.CharField(max_length=50)
genres = forms.ModelMultipleChoiceField(widget=ModelSelect2MultipleWidget(
queryset=models.Genre.objects.all(),
search_fields=['title__icontains'],
), queryset=models.Genre.objects.all())
), queryset=models.Genre.objects.all(), required=False)
class AlbumModelForm(forms.ModelForm):
class Meta:
model = models.Album
fields = (
'title',
'artist',
)
class AlbumForm(forms.Form):
title = forms.CharField(max_length=255)
artist = forms.ModelChoiceField(widget=ModelSelect2Widget(
model=models.Artist,
search_fields=['title__icontains']
), queryset=models.Artist.objects.all())
NUMBER_CHOICES = [
(1, 'One'),
(2, 'Two'),
(3, 'Three'),
(4, 'Four'),
]
class Select2WidgetForm(forms.Form):
NUMBER_CHOICES = [
(1, 'One'),
(2, 'Two'),
(3, 'Three'),
(4, 'Four'),
]
number = forms.ChoiceField(widget=Select2Widget(), choices=NUMBER_CHOICES)
number = forms.ChoiceField(widget=Select2Widget, choices=NUMBER_CHOICES, required=False)
class HeavySelect2WidgetForm(forms.Form):
heavy_number = forms.ChoiceField(widget=HeavySelect2Widget(data_view='heavy_data'))
artist = forms.ChoiceField(
widget=HeavySelect2Widget(data_view='heavy_data', choices=NUMBER_CHOICES)
)
primary_genre = forms.ChoiceField(
widget=HeavySelect2Widget(data_view='heavy_data', choices=NUMBER_CHOICES),
required=False
)
class HeavySelect2MultipleWidgetForm(forms.Form):
heavy_number = forms.MultipleChoiceField(widget=HeavySelect2MultipleWidget(data_view='heavy_data'))
genres = forms.MultipleChoiceField(
widget=HeavySelect2MultipleWidget(data_view='heavy_data', choices=NUMBER_CHOICES)
)
featured_artists = forms.MultipleChoiceField(
widget=HeavySelect2MultipleWidget(data_view='heavy_data', choices=NUMBER_CHOICES),
required=False
)
class ModelSelect2TagWidgetForm(forms.ModelForm):
class Meta:
model = Album
fields = ['genres']
widgets = {
'genres': GenreSelect2TagWidget
}

View file

@ -26,17 +26,9 @@ class Artist(models.Model):
class Album(models.Model):
title = models.CharField(max_length=255)
artist = models.ForeignKey(Artist)
def __str__(self):
return self.title
@python_2_unicode_compatible
class Song(models.Model):
title = models.CharField(max_length=255)
album = models.ForeignKey(Album, blank=True, null=True)
artist = models.ForeignKey(Artist)
genres = models.ManyToManyField(Genre, blank=True, null=True)
featured_artists = models.ManyToManyField(Artist, blank=True, related_name='featured_album_set')
primary_genre = models.ForeignKey(Genre, blank=True, null=True, related_name='primary_album_set')
genres = models.ManyToManyField(Genre)
def __str__(self):
return self.title

View file

@ -6,7 +6,7 @@ DEBUG = True
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'testdb.sqlite',
'NAME': ':memory:',
}
}
@ -48,5 +48,3 @@ if os.environ.get('TRAVIS'):
'LOCATION': 'localhost:11211',
}
}
SELECT2_BOOTSTRAP = True

File diff suppressed because one or more lines are too long

View file

@ -3,7 +3,11 @@
<html>
<head>
{{ form.media.css }}
<style type="text/css">select{width:200px}</style>
<style type="text/css">
select {
width: 200px;
}
</style>
</head>
<body>
<form method="post" action="">
@ -11,7 +15,7 @@
{{ form }}
<input type="submit" value="Submit Form"/>
</form>
<script src="{% static 'jquery-2.1.4.min.js' %}"></script>
<script src="{% static '//code.jquery.com/jquery-2.1.4.min.js' %}"></script>
<script type="text/javascript">
window.onerror = function (msg) {
$("body").attr("JSError", msg);

View file

@ -4,8 +4,8 @@ from __future__ import absolute_import, unicode_literals
from django.conf.urls import include, patterns, url
from .forms import (
ArtistForm, HeavySelect2MultipleWidgetForm, HeavySelect2WidgetForm,
Select2WidgetForm
AlbumModelSelect2WidgetForm, HeavySelect2MultipleWidgetForm,
HeavySelect2WidgetForm, ModelSelect2TagWidgetForm, Select2WidgetForm
)
from .views import TemplateFormView, heavy_data
@ -16,11 +16,18 @@ urlpatterns = patterns(
url(r'^heavy_select2_widget/$',
TemplateFormView.as_view(form_class=HeavySelect2WidgetForm), name='heavy_select2_widget'),
url(r'^heavy_select2_multiple_widget/$',
TemplateFormView.as_view(form_class=HeavySelect2MultipleWidgetForm), name='heavy_select2_multiple_widget'),
url(r'^single_value_model_field/$',
TemplateFormView.as_view(form_class=ArtistForm), name='single_value_model_field'),
url(r'^heavy_data/$',
heavy_data, name='heavy_data'),
TemplateFormView.as_view(form_class=HeavySelect2MultipleWidgetForm),
name='heavy_select2_multiple_widget'),
url(r'^model_select2_widget/$',
TemplateFormView.as_view(form_class=AlbumModelSelect2WidgetForm),
name='model_select2_widget'),
url(r'^model_select2_tag_widget/$',
TemplateFormView.as_view(form_class=ModelSelect2TagWidgetForm),
name='model_select2_tag_widget'),
url(r'^heavy_data/$', heavy_data, name='heavy_data'),
url(r'^select2/', include('django_select2.urls')),
)