1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
from django.core.exceptions import PermissionDenied
from django.utils.encoding import force_text
from django.utils.html import escape
class LookupChannel(object):
"""
Subclass this, setting the model and implementing methods to taste.
Attributes::
model (Model): The Django Model that this lookup channel will search for.
plugin_options (dict): Options passed to jQuery UI plugin that are specific to this channel.
min_length (int): Minimum number of characters user types before a search is initiated.
This is passed to the jQuery plugin_options.
It is used in jQuery's UI when filtering results from its own cache.
It is also used in the django view to prevent expensive database queries.
Large datasets can choke if they search too often with small queries.
Better to demand at least 2 or 3 characters.
"""
model = None
plugin_options = {}
min_length = 1
def get_query(self, q, request):
"""
Return a QuerySet searching for the query string `q`.
Note that you may return any iterable so you can return a list or even
use yield and turn this method into a generator.
Args:
q (str, unicode): The query string to search for.
request (Request): This can be used to customize the search by User
or to use additional GET variables.
Returns:
(QuerySet, list, generator): iterable of related_models
"""
kwargs = {"%s__icontains" % self.search_field: q}
return self.model.objects.filter(**kwargs).order_by(self.search_field)
def get_result(self, obj):
"""
The text result of autocompleting the entered query.
For a partial string that the user typed in, each matched result is
here converted to the fully completed text.
This is currently displayed only for a moment in the text field after
the user has selected the item.
Then the item is displayed in the item_display deck and the text field
is cleared.
Args:
obj (Model):
Returns:
str: The object as string
"""
return escape(force_text(obj))
def format_match(self, obj):
"""
(HTML) Format item for displaying in the dropdown.
Args:
obj (Model):
Returns:
str: formatted string, may contain HTML.
"""
return escape(force_text(obj))
def format_item_display(self, obj):
"""
(HTML) format item for displaying item in the selected deck area.
Args:
obj (Model):
Returns:
str: formatted string, may contain HTML.
"""
return escape(force_text(obj))
def get_objects(self, ids):
"""
This is used to retrieve the currently selected objects for either ManyToMany or ForeignKey.
Args:
ids (list): list of primary keys
Returns:
list: list of Model objects
"""
# Inherited models have a OneToOneField (rather than eg AutoField)
if getattr(self.model._meta.pk, "remote_field", False):
# Use the type of the field being referenced (2.0+)
pk_type = self.model._meta.pk.remote_field.field.to_python
elif getattr(self.model._meta.pk, "rel", False):
# Use the type of the field being referenced
pk_type = self.model._meta.pk.rel.field.to_python
else:
pk_type = self.model._meta.pk.to_python
# Return objects in the same order as passed in here
ids = [pk_type(pk) for pk in ids]
things = self.model.objects.in_bulk(ids)
return [things[aid] for aid in ids if aid in things]
def can_add(self, user, other_model):
"""
Check if the user has permission to add a ForeignKey or M2M model.
This enables the green popup + on the widget.
Default implentation is the standard django permission check.
Args:
user (User)
other_model (Model): the ForeignKey or M2M model to check if the User can add.
Returns:
bool
"""
from django.contrib.contenttypes.models import ContentType
ctype = ContentType.objects.get_for_model(other_model)
return user.has_perm("%s.add_%s" % (ctype.app_label, ctype.model))
def check_auth(self, request):
"""
By default only request.user.is_staff have access.
This ensures that nobody can get your data by simply knowing the lookup URL.
This is called from the ajax_lookup view.
Public facing forms (outside of the Admin) should implement this to
allow non-staff to use this LookupChannel.
Args:
request (Request)
Raises:
PermissionDenied
"""
if not request.user.is_staff:
raise PermissionDenied
|