/cilcdjango/medialibrary/forms.py

https://github.com/cilcoberlin/cilcdjango · Python · 199 lines · 122 code · 42 blank · 35 comment · 17 complexity · ae189a0135130affa13712c3419e174e MD5 · raw file

  1. from django import forms
  2. from django.utils.translation import ugettext_lazy as _
  3. from cilcdjango.core.fields import YesNoField
  4. from cilcdjango.core.forms import DjangoForm, DjangoModelForm
  5. from cilcdjango.core.media import SharedMediaMixin
  6. from cilcdjango.medialibrary.models import MediaLibraryGroup, MediaItem
  7. import copy
  8. class MediaLibraryForm(DjangoForm, SharedMediaMixin):
  9. """
  10. The selection form for the media library which.
  11. Through client-side Ajax, this can also display the media addition form.
  12. """
  13. _FILTER_COLUMN_SIZE = 10
  14. _GROUP_EMPTY_LABEL = _("all groups")
  15. _MEDIA_TYPE_CHOICES = [('any', _('any type')), ('files', _('files')), ('urls', _('urls'))]
  16. _SUBTYPE_DEFAULT_CHOICE = [('any', _("any subtype"))]
  17. def __init__(self, library, *args, **kwargs):
  18. """Requires a MediaLibrary instance as its first argument."""
  19. super(MediaLibraryForm, self).__init__(*args, **kwargs)
  20. self.library = library
  21. widget_args = {
  22. 'attrs': {'size': 10}
  23. }
  24. # Add the group filter
  25. self.fields['group_filter'] = forms.ModelChoiceField(
  26. empty_label=self._GROUP_EMPTY_LABEL,
  27. queryset=library.groups.all().order_by('name'),
  28. widget=forms.Select(**widget_args),
  29. required=False,
  30. initial=""
  31. )
  32. # Add the type filter for choosing files or URLs
  33. self.fields['type_filter'] = forms.ChoiceField(
  34. choices=self._MEDIA_TYPE_CHOICES,
  35. widget=forms.Select(**widget_args),
  36. required=False,
  37. initial='any'
  38. )
  39. # Add filters for a subtype of the selected media type
  40. self.fields['subtype_filter'] = forms.ChoiceField(
  41. choices=self._make_subtype_filter_choices(library.all_media_types()),
  42. widget=forms.Select(**widget_args),
  43. required=False,
  44. initial='any'
  45. )
  46. # Add the file list
  47. self.fields['file_list'] = forms.ModelChoiceField(
  48. queryset=library.media.order_by('title'),
  49. widget=forms.Select(**widget_args),
  50. required=False
  51. )
  52. # Remove any POST data with a null value, which is used by
  53. # ModelChoiceFields to indicate that no value was selected
  54. data = self.data.copy()
  55. for key, value in data.iteritems():
  56. if value == 'null':
  57. del data[key]
  58. self.data = data
  59. def _make_subtype_filter_choices(self, subtypes):
  60. """
  61. Transform a QuerySet of media types into an iterable suitable to pass as
  62. the `choices` kwarg of a selection field.
  63. """
  64. return self._SUBTYPE_DEFAULT_CHOICE + [(s.name, s.name) for s in subtypes]
  65. def clean(self):
  66. """Apply the requested filters to the media available in this library."""
  67. # Use the requested filters to generate choices for each of the filters
  68. type_filter = self.cleaned_data.get('type_filter')
  69. if type_filter == "any":
  70. local_filter = None
  71. elif type_filter == "files":
  72. local_filter = True
  73. else:
  74. local_filter = False
  75. subtype_filter = self.cleaned_data.get('subtype_filter')
  76. if subtype_filter == "any":
  77. subtype_filter = None
  78. filtered = self.library.filter_media(
  79. local=local_filter,
  80. media_type=subtype_filter,
  81. group=self.cleaned_data.get('group_filter', None)
  82. )
  83. # Update the subtypes and media list with the the filtered data
  84. self.fields['file_list'].queryset = filtered['media']
  85. self.fields['subtype_filter'].choices = self._make_subtype_filter_choices(filtered['types'])
  86. return self.cleaned_data
  87. class SharedMedia:
  88. js = (
  89. 'core/js/libs/jquery/jquery.simplemodal.js',
  90. 'core/js/libs/jquery/jquery.form.js',
  91. 'medialibrary/js/library.js'
  92. )
  93. class AddMediaGroupForm(DjangoModelForm):
  94. """A form for adding a media group."""
  95. class ErrorText:
  96. name = _("you must provide a group name")
  97. class Meta:
  98. model = MediaLibraryGroup
  99. exclude = ('media',)
  100. def __init__(self, library, *args, **kwargs):
  101. """Requires a MediaLibrary instance as its first argument."""
  102. super(AddMediaGroupForm, self).__init__(*args, **kwargs)
  103. self.library = library
  104. class AddMediaForm(DjangoModelForm):
  105. """A form for adding media to a media library."""
  106. is_file = YesNoField(label=_("media type"), initial=True, yes=_("file"), no=_("url"))
  107. new_group_name = forms.CharField(label=_("group name"), required=False)
  108. class ErrorText:
  109. title = _("you must provide a title")
  110. class Meta:
  111. model = MediaItem
  112. exclude = ('type',)
  113. def __init__(self, library, *args, **kwargs):
  114. """Requires a MediaLibrary instance as the first argument."""
  115. super(AddMediaForm, self).__init__(*args, **kwargs)
  116. self.library = library
  117. group_args = {
  118. 'queryset': MediaLibraryGroup.objects.filter(library=library).order_by('name'),
  119. 'required': False
  120. }
  121. # Add a group selection form for the media library's groups
  122. self.fields['groups'] = forms.ModelMultipleChoiceField(label=_("groups"), **group_args)
  123. def clean(self):
  124. """
  125. Verify that the media type that has been specified is paired with a
  126. valid medium of the selected type.
  127. """
  128. # Verify that the user is submitting a medium of the chosen type
  129. is_file = self.cleaned_data.get('is_file', None)
  130. if is_file:
  131. if not self.cleaned_data.get('file'):
  132. raise forms.ValidationError(_("you must provide a file"))
  133. elif is_file is not None:
  134. if not self.cleaned_data.get('url'):
  135. raise forms.ValidationError(_("you must provide a URL"))
  136. else:
  137. raise forms.ValidationError(_("you must select an upload type"))
  138. # Remove any cleaned data on non-selected media
  139. try:
  140. if is_file:
  141. del self.cleaned_data['url']
  142. else:
  143. del self.cleaned_data['file']
  144. except KeyError:
  145. pass
  146. return self.cleaned_data
  147. def save(self, *args, **kwargs):
  148. """
  149. Link the medium to any requested media groups after it has committed to
  150. the database.
  151. """
  152. # Add the medium to each selected group
  153. medium = super(AddMediaForm, self).save(*args, **kwargs)
  154. for group in self.cleaned_data['groups']:
  155. group.media.add(medium)
  156. return medium