New upstream version 1.7.0
Brian May
6 years ago
0 | 0 | # Change Log |
1 | ||
2 | ## [1.6.1](https://github.com/crucialfelix/django-ajax-selects/tree/1.6.1) (2017-09-09) | |
3 | [Full Changelog](https://github.com/crucialfelix/django-ajax-selects/compare/1.6.0...1.6.1) | |
4 | ||
5 | **Fixed bugs:** | |
6 | ||
7 | - Fix Lookup.get\_objects for inherited models [\#212](https://github.com/crucialfelix/django-ajax-selects/pull/212) ([crucialfelix](https://github.com/crucialfelix)) | |
8 | ||
9 | **Merged pull requests:** | |
10 | ||
11 | - Use DjangoJSONEncoder - which handles additional django types [\#206](https://github.com/crucialfelix/django-ajax-selects/pull/206) ([mzdeb](https://github.com/mzdeb)) | |
1 | 12 | |
2 | 13 | ## [1.6.0](https://github.com/crucialfelix/django-ajax-selects/tree/1.6.0) (2017-05-17) |
3 | 14 | [Full Changelog](https://github.com/crucialfelix/django-ajax-selects/compare/1.5.2...1.6.0) |
0 | 0 | Metadata-Version: 1.1 |
1 | 1 | Name: django-ajax-selects |
2 | Version: 1.6.0 | |
2 | Version: 1.7.0 | |
3 | 3 | Summary: Edit ForeignKey, ManyToManyField and CharField in Django Admin using jQuery UI AutoComplete. |
4 | 4 | Home-page: https://github.com/crucialfelix/django-ajax-selects/ |
5 | 5 | Author: Chris Sattinger |
16 | 16 | - Integrate with other UI elements elsewhere on the page using the javascript API |
17 | 17 | - Works in Admin as well as in normal views |
18 | 18 | |
19 | - Django >=1.7, <=2 | |
19 | - Django >=1.8, <=2.1 | |
20 | 20 | - Python >=2.7, <=3.7 |
21 | 21 | |
22 | 22 | Platform: UNKNOWN |
0 | ||
1 | Edit `ForeignKey`, `ManyToManyField` and `CharField` in Django Admin using jQuery UI AutoComplete. | |
0 | # Edit `ForeignKey`, `ManyToManyField` and `CharField` in Django Admin using jQuery UI AutoComplete. | |
2 | 1 | |
3 | 2 | [![Build Status](https://travis-ci.org/crucialfelix/django-ajax-selects.svg?branch=master)](https://travis-ci.org/crucialfelix/django-ajax-selects) [![PyPI version](https://badge.fury.io/py/django-ajax-selects.svg)](https://badge.fury.io/py/django-ajax-selects) |
4 | 3 | |
8 | 7 | |
9 | 8 | ![selected](/docs/source/_static/kiss-all.png?raw=true) |
10 | 9 | |
11 | ||
12 | Documentation | |
13 | ------------------ | |
10 | ## Documentation | |
14 | 11 | |
15 | 12 | http://django-ajax-selects.readthedocs.org/en/latest/ |
16 | 13 | |
17 | ||
18 | ||
19 | Quick Usage | |
20 | ----------- | |
14 | ## Quick Usage | |
21 | 15 | |
22 | 16 | Define a lookup channel: |
23 | 17 | |
42 | 36 | |
43 | 37 | ```python |
44 | 38 | # yourapp/forms.py |
39 | from ajax_select.fields import AutoCompleteSelectMultipleField | |
40 | ||
45 | 41 | class DocumentForm(ModelForm): |
46 | 42 | |
47 | 43 | class Meta: |
50 | 46 | tags = AutoCompleteSelectMultipleField('tags') |
51 | 47 | ``` |
52 | 48 | |
49 | ## Fully customizable | |
53 | 50 | |
51 | * Customize search query | |
52 | * Query other resources besides Django ORM | |
53 | * Format results with HTML | |
54 | * Customize styling | |
55 | * Customize security policy | |
56 | * Add additional custom UI alongside widget | |
57 | * Integrate with other UI elements elsewhere on the page using the javascript API | |
58 | * Works in Admin as well as in normal views | |
54 | 59 | |
55 | Fully customizable | |
56 | ------------------ | |
60 | ## Assets included by default | |
57 | 61 | |
58 | - Customize search query | |
59 | - Query other resources besides Django ORM | |
60 | - Format results with HTML | |
61 | - Customize styling | |
62 | - Customize security policy | |
63 | - Add additional custom UI alongside widget | |
64 | - Integrate with other UI elements elsewhere on the page using the javascript API | |
65 | - Works in Admin as well as in normal views | |
62 | * //ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js | |
63 | * //code.jquery.com/ui/1.10.3/jquery-ui.js | |
64 | * //code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css | |
66 | 65 | |
66 | ## Compatibility | |
67 | 67 | |
68 | Assets included by default | |
69 | ------------------- | |
68 | * Django >=1.8, <=2.1 | |
69 | * Python >=2.7, 3.3+ | |
70 | 70 | |
71 | - //ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js | |
72 | - //code.jquery.com/ui/1.10.3/jquery-ui.js | |
73 | - //code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css | |
74 | ||
75 | Compatibility | |
76 | ------------- | |
77 | ||
78 | - Django >=1.6, <=1.10 | |
79 | - Python >=2.7, 3.3-3.5 | |
80 | ||
81 | ||
82 | Contributors | |
83 | ------------ | |
71 | ## Contributors | |
84 | 72 | |
85 | 73 | Many thanks to all contributors and pull requesters ! |
86 | 74 | |
87 | 75 | https://github.com/crucialfelix/django-ajax-selects/graphs/contributors |
88 | 76 | |
89 | ||
90 | License | |
91 | ------- | |
77 | ## License | |
92 | 78 | |
93 | 79 | Dual licensed under the MIT and GPL licenses: |
94 | - http://www.opensource.org/licenses/mit-license.php | |
95 | - http://www.gnu.org/licenses/gpl.html | |
80 | ||
81 | * http://www.opensource.org/licenses/mit-license.php | |
82 | * http://www.gnu.org/licenses/gpl.html |
0 | 0 | """JQuery-Ajax Autocomplete fields for Django Forms.""" |
1 | __version__ = "1.6.0" | |
1 | __version__ = "1.7.0" | |
2 | 2 | __author__ = "crucialfelix" |
3 | 3 | __contact__ = "crucialfelix@gmail.com" |
4 | 4 | __homepage__ = "https://github.com/crucialfelix/django-ajax-selects/" |
7 | 7 | from ajax_select.helpers import make_ajax_form, make_ajax_field # noqa |
8 | 8 | from ajax_select.lookup_channel import LookupChannel # noqa |
9 | 9 | |
10 | try: | |
11 | # django 1.7+ will use the new AppConfig api | |
12 | # It will load all your lookups.py modules | |
13 | # and any specified in settings.AJAX_LOOKUP_CHANNELS | |
14 | # It will do this after all apps are imported. | |
15 | from django.apps import AppConfig # noqa | |
16 | default_app_config = 'ajax_select.apps.AjaxSelectConfig' | |
17 | except ImportError: | |
18 | # Previous django versions should load now | |
19 | # using settings.AJAX_LOOKUP_CHANNELS | |
20 | registry.load_channels() | |
10 | # django 1.7+ will use the new AppConfig api | |
11 | # It will load all your lookups.py modules | |
12 | # and any specified in settings.AJAX_LOOKUP_CHANNELS | |
13 | # It will do this after all apps are imported. | |
14 | from django.apps import AppConfig # noqa | |
15 | default_app_config = 'ajax_select.apps.AjaxSelectConfig' |
4 | 4 | |
5 | 5 | """ |
6 | 6 | Django 1.7+ enables initializing installed applications |
7 | and autodiscovering modules | |
7 | and autodiscovering modules. | |
8 | 8 | |
9 | 9 | On startup, search for and import any modules called `lookups.py` in all installed apps. |
10 | 10 | Your LookupClass subclass may register itself. |
0 | 0 | from __future__ import unicode_literals |
1 | ||
1 | 2 | import json |
2 | from ajax_select.registry import registry | |
3 | ||
3 | 4 | from django import forms |
4 | 5 | from django.conf import settings |
5 | 6 | from django.contrib.contenttypes.models import ContentType |
6 | from django.db.models.query import QuerySet | |
7 | from django.db.models import Model | |
7 | 8 | from django.forms.utils import flatatt |
8 | 9 | from django.template.defaultfilters import force_escape |
9 | 10 | from django.template.loader import render_to_string |
11 | 12 | from django.utils.safestring import mark_safe |
12 | 13 | from django.utils.six import text_type |
13 | 14 | from django.utils.translation import ugettext as _ |
15 | from django.utils.module_loading import import_string | |
16 | ||
17 | from ajax_select.registry import registry | |
18 | ||
14 | 19 | try: |
15 | 20 | from django.urls import reverse |
16 | 21 | except ImportError: |
34 | 39 | return forms.Media(css={'all': ('ajax_select/css/ajax_select.css',)}, js=js) |
35 | 40 | |
36 | 41 | |
42 | json_encoder = import_string(getattr(settings, 'AJAX_SELECT_JSON_ENCODER', | |
43 | 'django.core.serializers.json.DjangoJSONEncoder')) | |
44 | ||
45 | ||
37 | 46 | ############################################################################### |
38 | 47 | |
39 | 48 | |
95 | 104 | 'func_slug': self.html_id.replace("-", ""), |
96 | 105 | 'add_link': self.add_link, |
97 | 106 | } |
98 | context.update(make_plugin_options(lookup, self.channel, self.plugin_options, initial)) | |
107 | context.update( | |
108 | make_plugin_options(lookup, self.channel, self.plugin_options, initial)) | |
99 | 109 | templates = ( |
100 | 110 | 'ajax_select/autocompleteselect_%s.html' % self.channel, |
101 | 111 | 'ajax_select/autocompleteselect.html') |
126 | 136 | ) |
127 | 137 | widget_kwargs.update(kwargs.pop('widget_options', {})) |
128 | 138 | kwargs["widget"] = AutoCompleteSelectWidget(**widget_kwargs) |
129 | super(AutoCompleteSelectField, self).__init__(max_length=255, *args, **kwargs) | |
139 | super(AutoCompleteSelectField, self).__init__( | |
140 | max_length=255, *args, **kwargs) | |
130 | 141 | |
131 | 142 | def clean(self, value): |
132 | 143 | if value: |
137 | 148 | # or your channel is faulty |
138 | 149 | # out of the scope of this field to do anything more than |
139 | 150 | # tell you it doesn't exist |
140 | raise forms.ValidationError("%s cannot find object: %s" % (lookup, value)) | |
151 | raise forms.ValidationError( | |
152 | "%s cannot find object: %s" % (lookup, value)) | |
141 | 153 | return objs[0] |
142 | 154 | else: |
143 | 155 | if self.required: |
193 | 205 | |
194 | 206 | lookup = registry.get(self.channel) |
195 | 207 | |
196 | if isinstance(value, QuerySet): | |
197 | objects = value | |
198 | else: | |
199 | objects = lookup.get_objects(value) | |
208 | values = list(value) | |
209 | if all([isinstance(v, Model) for v in values]): | |
210 | objects = values | |
211 | else: | |
212 | objects = lookup.get_objects(values) | |
200 | 213 | |
201 | 214 | current_ids = pack_ids([obj.pk for obj in objects]) |
202 | 215 | |
216 | 229 | 'html_id': self.html_id, |
217 | 230 | 'current': value, |
218 | 231 | 'current_ids': current_ids, |
219 | 'current_reprs': mark_safe(json.dumps(initial)), | |
232 | 'current_reprs': mark_safe( | |
233 | json.dumps(initial, cls=json_encoder) | |
234 | ), | |
220 | 235 | 'help_text': help_text, |
221 | 236 | 'extra_attrs': mark_safe(flatatt(final_attrs)), |
222 | 237 | 'func_slug': self.html_id.replace("-", ""), |
223 | 238 | 'add_link': self.add_link, |
224 | 239 | } |
225 | context.update(make_plugin_options(lookup, self.channel, self.plugin_options, initial)) | |
240 | context.update( | |
241 | make_plugin_options(lookup, self.channel, self.plugin_options, initial)) | |
226 | 242 | templates = ('ajax_select/autocompleteselectmultiple_%s.html' % self.channel, |
227 | 'ajax_select/autocompleteselectmultiple.html') | |
243 | 'ajax_select/autocompleteselectmultiple.html') | |
228 | 244 | out = render_to_string(templates, context) |
229 | 245 | return mark_safe(out) |
230 | 246 | |
268 | 284 | dh = 'Hold down "Control", or "Command" on a Mac, to select more than one.' |
269 | 285 | django_default_help = _(dh).translate(settings.LANGUAGE_CODE) |
270 | 286 | if django_default_help in translated: |
271 | cleaned_help = translated.replace(django_default_help, '').strip() | |
287 | cleaned_help = translated.replace( | |
288 | django_default_help, '').strip() | |
272 | 289 | # probably will not show up in translations |
273 | 290 | if cleaned_help: |
274 | 291 | help_text = cleaned_help |
357 | 374 | 'extra_attrs': mark_safe(flatatt(final_attrs)), |
358 | 375 | 'func_slug': self.html_id.replace("-", ""), |
359 | 376 | } |
360 | context.update(make_plugin_options(lookup, self.channel, self.plugin_options, initial)) | |
377 | context.update( | |
378 | make_plugin_options(lookup, self.channel, self.plugin_options, initial)) | |
361 | 379 | templates = ('ajax_select/autocomplete_%s.html' % self.channel, |
362 | 380 | 'ajax_select/autocomplete.html') |
363 | 381 | return mark_safe(render_to_string(templates, context)) |
364 | 382 | |
365 | 383 | |
366 | 384 | class AutoCompleteField(forms.CharField): |
385 | ||
367 | 386 | """ |
368 | 387 | A CharField that uses an AutoCompleteWidget to lookup matching |
369 | 388 | and stores the result as plain text. |
410 | 429 | if can_add: |
411 | 430 | app_label = related_model._meta.app_label |
412 | 431 | model = related_model._meta.object_name.lower() |
413 | self.widget.add_link = reverse('admin:%s_%s_add' % (app_label, model)) + '?_popup=1' | |
432 | self.widget.add_link = reverse( | |
433 | 'admin:%s_%s_add' % (app_label, model)) + '?_popup=1' | |
414 | 434 | |
415 | 435 | |
416 | 436 | def autoselect_fields_check_can_add(form, model, user): |
422 | 442 | for name, form_field in form.declared_fields.items(): |
423 | 443 | if isinstance(form_field, (AutoCompleteSelectMultipleField, AutoCompleteSelectField)): |
424 | 444 | db_field = model._meta.get_field(name) |
425 | form_field.check_can_add(user, db_field.rel.to) | |
445 | if hasattr(db_field, "remote_field"): | |
446 | form_field.check_can_add(user, db_field.remote_field.model) | |
447 | else: | |
448 | form_field.check_can_add(user, db_field.rel.to) | |
426 | 449 | |
427 | 450 | |
428 | 451 | def make_plugin_options(lookup, channel_name, widget_plugin_options, initial): |
440 | 463 | po['html'] = True |
441 | 464 | |
442 | 465 | return { |
443 | 'plugin_options': mark_safe(json.dumps(po)), | |
444 | 'data_plugin_options': force_escape(json.dumps(po)) | |
466 | 'plugin_options': mark_safe(json.dumps(po, cls=json_encoder)), | |
467 | 'data_plugin_options': force_escape( | |
468 | json.dumps(po, cls=json_encoder) | |
469 | ) | |
445 | 470 | } |
446 | 471 | |
447 | 472 |
0 | 0 | from django.db.models.fields.related import ForeignKey, ManyToManyField |
1 | 1 | from django.forms.models import ModelForm |
2 | from django.utils.encoding import force_text | |
2 | 3 | from django.utils.text import capfirst |
3 | from django.utils.encoding import force_text | |
4 | 4 | from django.utils.translation import ugettext_lazy as _ |
5 | 5 | |
6 | 6 | |
83 | 83 | (AutoCompleteField, AutoCompleteSelectField, AutoCompleteSelectMultipleField): field |
84 | 84 | """ |
85 | 85 | from ajax_select.fields import AutoCompleteField, \ |
86 | AutoCompleteSelectMultipleField, \ | |
87 | AutoCompleteSelectField | |
86 | AutoCompleteSelectMultipleField, \ | |
87 | AutoCompleteSelectField | |
88 | 88 | |
89 | 89 | field = related_model._meta.get_field(fieldname_on_model) |
90 | 90 | if 'label' not in kwargs: |
93 | 93 | Returns: |
94 | 94 | list: list of Model objects |
95 | 95 | """ |
96 | if self.model._meta.pk.rel is not None: | |
96 | # Inherited models have a OneToOneField (rather than eg AutoField) | |
97 | if getattr(self.model._meta.pk, "remote_field", False): | |
98 | # Use the type of the field being referenced (2.0+) | |
99 | pk_type = self.model._meta.pk.remote_field.field.to_python | |
100 | elif getattr(self.model._meta.pk, "rel", False): | |
97 | 101 | # Use the type of the field being referenced |
98 | pk_type = self.model._meta.pk.target_field.to_python | |
102 | pk_type = self.model._meta.pk.rel.field.to_python | |
99 | 103 | else: |
100 | 104 | pk_type = self.model._meta.pk.to_python |
101 | 105 |
0 | """ | |
1 | Blank file so that Django recognizes the app. | |
2 | ||
3 | This is only required for Django < 1.7 | |
4 | """ |
0 | from django.apps import apps | |
1 | from django.conf import settings | |
0 | 2 | from django.core.exceptions import ImproperlyConfigured |
1 | from django.conf import settings | |
3 | from django.utils.module_loading import autodiscover_modules | |
2 | 4 | |
3 | 5 | |
4 | 6 | class LookupChannelRegistry(object): |
16 | 18 | Called when loading the application. Cannot be called a second time, |
17 | 19 | (eg. for testing) as Django will not re-import and re-register anything. |
18 | 20 | """ |
19 | self._registry = {} | |
20 | try: | |
21 | from django.utils.module_loading import autodiscover_modules | |
22 | except ImportError: | |
23 | pass | |
24 | else: | |
25 | autodiscover_modules('lookups') | |
21 | autodiscover_modules('lookups') | |
26 | 22 | |
27 | 23 | if hasattr(settings, 'AJAX_LOOKUP_CHANNELS'): |
28 | 24 | self.register(settings.AJAX_LOOKUP_CHANNELS) |
111 | 107 | |
112 | 108 | def get_model(app_label, model_name): |
113 | 109 | """Loads the model given an 'app_label' 'ModelName'""" |
114 | try: | |
115 | # django >= 1.7 | |
116 | from django.apps import apps | |
117 | except ImportError: | |
118 | # django < 1.7 | |
119 | from django.db import models | |
120 | return models.get_model(app_label, model_name) | |
121 | else: | |
122 | return apps.get_model(app_label, model_name) | |
123 | ||
124 | ||
125 | def can_autodiscover(): | |
126 | try: | |
127 | from django.apps import AppConfig # noqa | |
128 | except ImportError: | |
129 | return False | |
130 | return True | |
110 | return apps.get_model(app_label, model_name) | |
131 | 111 | |
132 | 112 | |
133 | 113 | def register(channel): |
0 | 0 | Metadata-Version: 1.1 |
1 | 1 | Name: django-ajax-selects |
2 | Version: 1.6.0 | |
2 | Version: 1.7.0 | |
3 | 3 | Summary: Edit ForeignKey, ManyToManyField and CharField in Django Admin using jQuery UI AutoComplete. |
4 | 4 | Home-page: https://github.com/crucialfelix/django-ajax-selects/ |
5 | 5 | Author: Chris Sattinger |
16 | 16 | - Integrate with other UI elements elsewhere on the page using the javascript API |
17 | 17 | - Works in Admin as well as in normal views |
18 | 18 | |
19 | - Django >=1.7, <=2 | |
19 | - Django >=1.8, <=2.1 | |
20 | 20 | - Python >=2.7, <=3.7 |
21 | 21 | |
22 | 22 | Platform: UNKNOWN |
12 | 12 | ajax_select/fields.py |
13 | 13 | ajax_select/helpers.py |
14 | 14 | ajax_select/lookup_channel.py |
15 | ajax_select/models.py | |
16 | 15 | ajax_select/registry.py |
17 | 16 | ajax_select/urls.py |
18 | 17 | ajax_select/views.py |
0 | 0 | #!/usr/bin/env python |
1 | 1 | |
2 | try: | |
3 | from setuptools import setup | |
4 | except ImportError: | |
5 | from ez_setup import use_setuptools | |
6 | use_setuptools() | |
7 | from setuptools import setup | |
2 | from setuptools import setup | |
8 | 3 | |
9 | 4 | setup( |
10 | 5 | name='django-ajax-selects', |
11 | version='1.6.0', | |
6 | version='1.7.0', | |
12 | 7 | description='Edit ForeignKey, ManyToManyField and CharField in Django Admin using jQuery UI AutoComplete.', |
13 | 8 | author='Chris Sattinger', |
14 | 9 | author_email='crucialfelix@gmail.com', |
15 | 10 | url='https://github.com/crucialfelix/django-ajax-selects/', |
16 | 11 | packages=['ajax_select'], |
17 | package_data={'ajax_select': | |
12 | package_data={ | |
13 | 'ajax_select': | |
18 | 14 | [ |
19 | 15 | '*.py', |
20 | 16 | '*.txt', |
53 | 49 | - Integrate with other UI elements elsewhere on the page using the javascript API |
54 | 50 | - Works in Admin as well as in normal views |
55 | 51 | |
56 | - Django >=1.7, <=2 | |
52 | - Django >=1.8, <=2.1 | |
57 | 53 | - Python >=2.7, <=3.7 |
58 | 54 | """ |
59 | 55 | ) |
2 | 2 | |
3 | 3 | Should not be used by other tests. |
4 | 4 | """ |
5 | from django.contrib.auth.models import User | |
5 | 6 | from django.utils.html import escape |
6 | from django.contrib.auth.models import User | |
7 | from tests.models import Person, Author | |
7 | ||
8 | 8 | import ajax_select |
9 | ||
10 | from tests.models import Author, Person, PersonWithTitle | |
9 | 11 | |
10 | 12 | |
11 | 13 | @ajax_select.register('person') |
24 | 26 | |
25 | 27 | def format_item_display(self, obj): |
26 | 28 | return "%s<div><i>%s</i></div>" % (escape(obj.name), escape(obj.email)) |
29 | ||
30 | ||
31 | @ajax_select.register('person-with-title') | |
32 | class PersonWithTitleLookup(ajax_select.LookupChannel): | |
33 | ||
34 | model = PersonWithTitle | |
35 | ||
36 | def get_query(self, q, request): | |
37 | return self.model.objects.filter(title__icontains=q) | |
38 | ||
39 | def get_result(self, obj): | |
40 | return "{} {}".format(obj.name, obj.title) | |
27 | 41 | |
28 | 42 | |
29 | 43 | @ajax_select.register('user') |
5 | 5 | |
6 | 6 | name = models.CharField(max_length=50) |
7 | 7 | email = models.EmailField(null=True, blank=True) |
8 | ||
9 | class Meta: | |
10 | app_label = 'tests' | |
11 | ||
12 | ||
13 | class PersonWithTitle(Person): | |
14 | ||
15 | """ | |
16 | Testing an inherited model (multi-table) | |
17 | """ | |
18 | ||
19 | title = models.CharField(max_length=150) | |
8 | 20 | |
9 | 21 | class Meta: |
10 | 22 | app_label = 'tests' |
22 | 34 | |
23 | 35 | """ Book has no admin, its an inline in the Author admin""" |
24 | 36 | |
25 | author = models.ForeignKey(Author, null=True) | |
37 | author = models.ForeignKey(Author, null=True, on_delete=models.CASCADE) | |
26 | 38 | name = models.CharField(max_length=50) |
27 | 39 | mentions_persons = models.ManyToManyField(Person, help_text="MENTIONS PERSONS HELP TEXT") |
28 | 40 |
17 | 17 | "tests" |
18 | 18 | ] |
19 | 19 | SITE_ID = 1 |
20 | MIDDLEWARE_CLASSES = ( | |
20 | MIDDLEWARE = MIDDLEWARE_CLASSES = ( | |
21 | 21 | 'django.contrib.sessions.middleware.SessionMiddleware', |
22 | 22 | 'django.contrib.auth.middleware.AuthenticationMiddleware', |
23 | 23 | 'django.contrib.messages.middleware.MessageMiddleware' |
8 | 8 | import django |
9 | 9 | from django.forms.models import ModelForm |
10 | 10 | from django.test import TestCase, Client |
11 | from django.core.urlresolvers import reverse | |
12 | 11 | from django.contrib.auth.models import User |
13 | 12 | |
14 | 13 | from tests.models import Book, Author, Person |
15 | 14 | from ajax_select import fields |
15 | try: | |
16 | from django.urls import reverse | |
17 | except ImportError: | |
18 | from django.core.urlresolvers import reverse | |
16 | 19 | |
17 | 20 | # Other versions will autoload |
18 | 21 | if django.VERSION[1] < 7: |
47 | 50 | def _make_instance(self): |
48 | 51 | author = Author.objects.create(name="author") |
49 | 52 | book = Book.objects.create(name="book", author=author) |
50 | book.mentions_persons = [Person.objects.create(name='person')] | |
53 | book.mentions_persons.add(Person.objects.create(name='person')) | |
51 | 54 | return book |
52 | 55 | |
53 | 56 | def _book_data(self, book): |
0 | 0 | |
1 | from django.contrib.auth.models import User | |
1 | 2 | from django.test import TestCase |
2 | from django.contrib.auth.models import User | |
3 | from .lookups import UserLookup | |
3 | ||
4 | from tests.lookups import PersonWithTitleLookup, UserLookup | |
5 | from tests.models import PersonWithTitle | |
4 | 6 | |
5 | 7 | |
6 | 8 | class TestLookups(TestCase): |
7 | 9 | |
8 | 10 | def test_get_objects(self): |
9 | 11 | user1 = User.objects.create(username='user1', |
10 | email='user1@example.com', | |
11 | password='password') | |
12 | email='user1@example.com', | |
13 | password='password') | |
12 | 14 | user2 = User.objects.create(username='user2', |
13 | email='user2@example.com', | |
14 | password='password') | |
15 | email='user2@example.com', | |
16 | password='password') | |
15 | 17 | lookup = UserLookup() |
18 | # deliberately asking for them backwards: | |
16 | 19 | users = lookup.get_objects([user2.id, user1.id]) |
17 | 20 | self.assertEqual(len(users), 2) |
21 | # to make sure they come back in the order requested | |
18 | 22 | u2, u1 = users |
19 | 23 | self.assertEqual(u1, user1) |
20 | 24 | self.assertEqual(u2, user2) |
25 | ||
26 | def test_get_objects_inherited_model(self): | |
27 | """ | |
28 | Tests that get_objects works with inherited models | |
29 | """ | |
30 | one = PersonWithTitle.objects.create(name='one', title='The One') | |
31 | two = PersonWithTitle.objects.create(name='two', title='The Other') | |
32 | lookup = PersonWithTitleLookup() | |
33 | users = lookup.get_objects([one.id, two.id]) | |
34 | self.assertEqual(len(users), 2) | |
35 | u1, u2 = users | |
36 | self.assertEqual(u1, one) | |
37 | self.assertEqual(u2, two) |
0 | 0 | |
1 | 1 | from django.test import TestCase |
2 | 2 | import ajax_select |
3 | from ajax_select.registry import can_autodiscover | |
4 | 3 | |
5 | 4 | |
6 | 5 | class TestRegistry(TestCase): |
8 | 7 | def test_lookup_py_is_autoloaded(self): |
9 | 8 | """Django >= 1.7 autoloads tests/lookups.py""" |
10 | 9 | is_registered = ajax_select.registry.is_registered('person') |
11 | if can_autodiscover(): | |
12 | self.assertTrue(is_registered) | |
13 | else: | |
14 | # person is not in settings and this django will not autoload lookups.py | |
15 | # self.assertFalse(is_registered) | |
16 | # test_integration is more important and requires that lookup.py be loaded | |
17 | # Will drop support for 1.6 soon anyway and we know that it does work | |
18 | pass | |
10 | self.assertTrue(is_registered) | |
19 | 11 | |
20 | 12 | def test_back_compatible_loads_by_settings(self): |
21 | 13 | """a module and class specified in settings""" |
28 | 20 | def test_unsetting_a_channel(self): |
29 | 21 | """settings can unset a channel that was specified in a lookups.py""" |
30 | 22 | # self.assertFalse(ajax_select.registry.is_registered('user')) |
31 | self.assertFalse(ajax_select.registry.is_registered('was-never-a-channel')) | |
23 | self.assertFalse( | |
24 | ajax_select.registry.is_registered('was-never-a-channel')) | |
32 | 25 | |
33 | 26 | # def test_reimporting_lookup(self): |
34 | 27 | # """ |