relfield.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. from django.db import models
  2. from django.forms.utils import flatatt
  3. from django.utils.html import escape, format_html
  4. from django.utils.safestring import mark_safe
  5. from django.utils.text import Truncator
  6. from django.utils.translation import ugettext as _
  7. from django import forms
  8. from xadmin.sites import site
  9. from xadmin.views import BaseAdminPlugin, ModelFormAdminView
  10. from xadmin.util import vendor
  11. class ForeignKeySearchWidget(forms.Widget):
  12. def __init__(self, rel, admin_view, attrs=None, using=None):
  13. self.rel = rel
  14. self.admin_view = admin_view
  15. self.db = using
  16. super(ForeignKeySearchWidget, self).__init__(attrs)
  17. def build_attrs(self, attrs={}, extra_attrs=None, **kwargs):
  18. to_opts = self.rel.model._meta
  19. if "class" not in attrs:
  20. attrs['class'] = 'select-search'
  21. else:
  22. attrs['class'] = attrs['class'] + ' select-search'
  23. attrs['data-search-url'] = self.admin_view.get_admin_url(
  24. '%s_%s_changelist' % (to_opts.app_label, to_opts.model_name))
  25. attrs['data-placeholder'] = _('Search %s') % to_opts.verbose_name
  26. attrs['data-choices'] = '?'
  27. if self.rel.limit_choices_to:
  28. for i in list(self.rel.limit_choices_to):
  29. attrs['data-choices'] += "&_p_%s=%s" % (i, self.rel.limit_choices_to[i])
  30. attrs['data-choices'] = format_html(attrs['data-choices'])
  31. attrs.update(kwargs)
  32. return super(ForeignKeySearchWidget, self).build_attrs(attrs, extra_attrs=extra_attrs)
  33. def render(self, name, value, attrs=None):
  34. final_attrs = self.build_attrs(attrs, extra_attrs={'name': name})
  35. output = [format_html('<select{0}>', flatatt(final_attrs))]
  36. if value:
  37. output.append(format_html('<option selected="selected" value="{0}">{1}</option>', value, self.label_for_value(value)))
  38. output.append('</select>')
  39. return mark_safe('\n'.join(output))
  40. def label_for_value(self, value):
  41. key = self.rel.get_related_field().name
  42. try:
  43. obj = self.rel.to._default_manager.using(
  44. self.db).get(**{key: value})
  45. return '%s' % escape(Truncator(obj).words(14, truncate='...'))
  46. except (ValueError, self.rel.to.DoesNotExist):
  47. return ""
  48. @property
  49. def media(self):
  50. return vendor('select.js', 'select.css', 'xadmin.widget.select.js')
  51. class ForeignKeySelectWidget(ForeignKeySearchWidget):
  52. def build_attrs(self, attrs={}, **kwargs):
  53. attrs = super(ForeignKeySelectWidget, self).build_attrs(attrs, **kwargs)
  54. if "class" not in attrs:
  55. attrs['class'] = 'select-preload'
  56. else:
  57. attrs['class'] = attrs['class'] + ' select-preload'
  58. attrs['data-placeholder'] = _('Select %s') % self.rel.model._meta.verbose_name
  59. return attrs
  60. class RelateFieldPlugin(BaseAdminPlugin):
  61. def get_field_style(self, attrs, db_field, style, **kwargs):
  62. # search able fk field
  63. if style in ('fk-ajax', 'fk-select') and isinstance(db_field, models.ForeignKey):
  64. if (db_field.remote_field.to in self.admin_view.admin_site._registry) and \
  65. self.has_model_perm(db_field.remote_field.to, 'view'):
  66. db = kwargs.get('using')
  67. return dict(attrs or {},
  68. widget=(style == 'fk-ajax' and ForeignKeySearchWidget or ForeignKeySelectWidget)(db_field.remote_field, self.admin_view, using=db))
  69. return attrs
  70. site.register_plugin(RelateFieldPlugin, ModelFormAdminView)