class Meta: model = Profile fields = ['name', 'about', 'organization', 'timezone', 'language', 'ace_theme'] widgets = {'name': TextInput(attrs={'style': 'width: 100%; box-sizing: border-box'})} if Select2Widget is not None: widgets['timezone'] = Select2Widget(attrs={'style': 'width: 200px'}) widgets['language'] = Select2Widget(attrs={'style': 'width: 300px'}) widgets['ace_theme'] = Select2Widget(attrs={'style': 'width: 300px'}) widgets['organization'] = Select2Widget(attrs={'style': 'width: 300px'})
class Meta: if use_select2: widgets = { 'contest': Select2Widget(), 'profile': HeavySelect2Widget(data_view='contest_profile_select2'), }
def __init__(self, *args, **kwargs): """ init(me). """ super(ManageSubscriptionForm, self).__init__(*args, **kwargs) folders_queryset = self.instance.user.folders_tree preferences = self.instance.user.preferences if preferences.selector.subscriptions_in_multiple_folders: self.fields['folders'] = OnlyNameMultipleChoiceField( queryset=folders_queryset, required=False, label=_(u'Folders'), widget=Select2MultipleWidget(), initial=self.instance.folders.all()) # no empty_label here. else: self.fields['folders'] = OnlyNameChoiceField( queryset=folders_queryset, required=False, widget=Select2Widget(), label=_(u'Folder'), empty_label=_(u'(None)')) try: self.fields['folders'].initial = self.instance.folders.all()[0] except IndexError: # Subscription is not in any folder yet. pass
class TreatInline(admin.TabularInline): formfield_overrides = { models.ForeignKey: { 'widget': Select2Widget(attrs={"style": "width: 300px;"}) }, } verbose_name = "treatment samples" name = verbose_name model = Datasets.treats.through extra = 1 def formfield_for_foreignkey(self, db_field, request=None, **kwargs): if request._dataset_: series_id = request._dataset_.treats.all()[0].series_id else: series_id = None field = super(TreatInline, self).formfield_for_foreignkey(db_field, request, **kwargs) if not series_id: return field if db_field.name == 'samples': field.queryset = Samples.objects.filter(series_id=series_id) elif db_field.name == 'datasets': field.queryset = Datasets.objects.filter( treats__series_id=series_id) else: dn = db_field.name raise return field
class GroupForm(forms.ModelForm): sex = Select2ChoiceField(required=False, choices=Animal.SEX_CHOICES, widget=Select2Widget(select2_options={'minimumInputLength': 0})) start_birth_date = forms.DateField(required=False, widget=DateTimePicker(options={'format': 'YYYY-MM-DD', 'pickTime': False})) end_birth_date = forms.DateField(required=False, widget=DateTimePicker(options={'format': 'YYYY-MM-DD', 'pickTime': False})) sire = BullField(required=False, widget=AutoHeavySelect2Widget(select2_options={'minimumInputLength': 0})) dam = CowField(required=False, widget=AutoHeavySelect2Widget(select2_options={'minimumInputLength': 0})) class Meta: model = Group exclude = ('is_active', 'created_by', 'created_on', 'modified_by', 'modified_on')
class AliasAdmin(admin.ModelAdmin): formfield_overrides = { models.ForeignKey: { 'widget': Select2Widget(attrs={"style": "width: 300px;"}) }, } list_display = ['id', 'name', 'factor'] search_fields = ['id', 'name'] list_per_page = 100 search_field = ['name', 'factor__name'] list_max_show_all = 5000
class Meta: widgets = { 'status_description': RedactorWidget( editor_options={ 'lang': 'en', 'buttons': [ 'html', '|', 'formatting', '|', 'bold', 'italic', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent', 'alignment', 'horizontalrule', 'underline', '|', 'image', '|' ], 'imageUpload': '/clients/redactor/image/', 'toolbarOverflow': True, }), 'todo_description': RedactorWidget( editor_options={ 'lang': 'en', 'buttons': [ 'html', '|', 'formatting', '|', 'bold', 'italic', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent', 'alignment', 'horizontalrule', 'underline', '|', 'image', '|' ], 'imageUpload': '/clients/redactor/image/', 'toolbarOverflow': True, }), 'amount': NumberInput(attrs={'min': '0'}), 'amount': EnclosedInput(prepend='$'), 'email': EnclosedInput(prepend='icon-envelope'), 'delivered_at': SuitSplitDateTimeWidget, 'brand': Select2Widget(select2_options={'width': '220px'}), 'model': SfWidget(app_name='phone', model_name='model', chain_field='brand', model_field='brand', show_all=False, auto_choose=False, attrs={'class': 'form-control'}, select2_options={"width": "220px"}), }
class CourseForm(forms.Form): all = Course.objects.all().values() idList = [] idList = [('', '')] + [(course['courseID'], course['courseID'] + ' - ' + course['name']) for course in all] id = forms.ChoiceField(label=u'', choices=idList, required=True, error_messages={'required': 'You forgot to choose a course !'}, widget=Select2Widget(attrs={'placeholder': 'Select a Course', 'class': 'choiceWidget'}, select2_options={ 'width': '600px', 'allowClear': 'True', }))
class Meta: model = F101 exclude = ['deleted', 'NRYY', 'NRMM', 'NDYY', 'NDMM'] widgets = dict( (field, Select2Widget()) for field in fields_with_choices(F101)) widgets.update({ 'Informer': Textarea, 'RCIR': Textarea, 'RHC': _Select2Widget, 'Hospital': Select2Widget })
class AnimalForm(forms.ModelForm): sex = Select2ChoiceField( choices=Animal.SEX_CHOICES, widget=Select2Widget(select2_options={'minimumInputLength': 0})) color = ColorField(required=False, widget=AutoHeavySelect2Widget( select2_options={'minimumInputLength': 0})) sire = BullField( required=False, widget=AutoHeavySelect2Widget(select2_options={ 'minimumInputLength': 0, 'width': '40px' }), attrs={ 'add_button': mark_safe( '<button id="comment-button" class="btn btn-primary" type="button"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add Category</button>' ) }) dam = CowField(required=False, widget=AutoHeavySelect2Widget( select2_options={'minimumInputLength': 0}), help_text='') breeder = BreederField(required=False, widget=AutoHeavySelect2Widget( select2_options={'minimumInputLength': 0})) birth_date = forms.DateField(widget=DateTimePicker(options={ 'format': 'YYYY-MM-DD', 'pickTime': False })) weaning_date = forms.DateField(widget=DateTimePicker(options={ 'format': 'YYYY-MM-DD', 'pickTime': False }), required=False) yearling_date = forms.DateField(widget=DateTimePicker(options={ 'format': 'YYYY-MM-DD', 'pickTime': False }), required=False) def __init__(self, *args, **kwargs): super(AnimalForm, self).__init__(*args, **kwargs) for field_name, field in self.fields.items(): if field_name not in ('group', 'sire', 'dam'): field.widget.attrs['class'] = 'form-control' class Meta: model = Animal fields = ('ear_tag', 'name', 'color', 'sex', 'breed', 'sire', 'dam', 'breeder', 'birth_date', 'birth_weight', 'weaning_date', 'weaning_weight', 'yearling_date', 'yearling_weight')
class Meta: model = F201 exclude = ['deleted', 'DDY', 'DDM', 'DRY', 'DRM'] widgets = dict( (field, Select2Widget()) for field in fields_with_choices(F201)) widgets.update({ 'RCIR': Textarea, 'Informant_name': Textarea, 'RHC': _Select2Widget, 'Hospital': Select2Widget, 'AGE_CODE': forms.HiddenInput(), 'EXTRA_AGE_CODE': forms.HiddenInput() })
class Meta: model = Component exclude = ('deleted', 'shop') widgets = { 'image': forms.FileInput(attrs={'class': 'form-control'}), 'title': forms.TextInput(attrs={ 'class': 'form-control', 'placeholder': 'Title' }), 'brand': Select2Widget(select2_options={'width': '100%'}), 'model': SfWidget( app_name='phone', model_name='model', chain_field='brand', model_field='brand', show_all=False, auto_choose=False, # attrs={'class': 'form-control'}, select2_options={'width': '100%'}), 'type': Select2Widget(select2_options={'width': '100%'}), 'description': forms.Textarea(attrs={'class': 'form-control'}), 'price': forms.NumberInput(attrs={ 'class': 'form-control', 'min': '0' }), 'currency': forms.Select(attrs={ 'class': 'form-control', }), }
class Meta: widgets = { 'image': AdminImageWidget(), 'description': RedactorWidget( editor_options={ 'lang': 'en', 'buttons': [ 'html', '|', 'formatting', '|', 'bold', 'italic', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent', 'alignment', 'horizontalrule', 'underline', '|', 'image', '|', 'link' ], 'imageUpload': '/clients/redactor/image/', }), 'price': NumberInput(attrs={'min': '0'}), 'price': EnclosedInput(prepend='$'), 'brand': Select2Widget(select2_options={'width': '220px'}), 'model': SfWidget(app_name='phone', model_name='model', chain_field='brand', model_field='brand', show_all=False, auto_choose=False, attrs={'class': 'form-control'}, select2_options={"width": "220px"}), 'type': Select2Widget(select2_options={'width': '220px'}), }
class Meta: model = Samples exclude = ("dc_collect_date", "dc_upload_date", "geo_last_update_date", "geo_release_date", "user", "paper", "fastq_file", "fastq_file_url", "bam_file", "platform", "paper") widgets = { # 'paper': Select2Widget(attrs={"style": "width: 300px;"}), 'factor': Select2Widget(attrs={"style": "width: 300px;"}), 'cell_line': Select2Widget(attrs={"style": "width: 300px;"}), 'cell_type': Select2Widget(attrs={"style": "width: 300px;"}), 'cell_pop': Select2Widget(attrs={"style": "width: 300px;"}), 'condition': Select2Widget(attrs={"style": "width: 300px;"}), 'strain': Select2Widget(attrs={"style": "width: 300px;"}), 'disease_state': Select2Widget(attrs={"style": "width: 300px;"}), 'tissue_type': Select2Widget(attrs={"style": "width: 300px;"}), 'antibody': Select2Widget(attrs={"style": "width: 300px;"}), # 'platform': Select2Widget(attrs={"style": "width: 300px;"}), # 'species': Select2Widget(attrs={"style": "width: 300px;"}), # 'assembly': Select2Widget(attrs={"style": "width: 300px;"}), }
def get_widget(self): if not self._dynamic_field_options.multiple: return Select2Widget(select2_options={'allowClear': False}) return None
class Select2WidgetForm(forms.Form): NUMBER_CHOICES = [(1, 'One'), (2, 'Two'), (3, 'Three'), (4, 'Four')] number = forms.ChoiceField(widget=Select2Widget(), choices=NUMBER_CHOICES)
class DatasetAdmin(admin.ModelAdmin): class Media: js = ("new_admin.js", ) mass_update_form = DatasetMassUpdateForm formfield_overrides = { models.ForeignKey: { 'widget': Select2Widget(attrs={"style": "width: 300px;"}) }, } list_display = [ 'custom_id', 'paper', 'status', 'journal_name', 'journal_impact_factor', 'factor', 'custom_treats', 'custom_conts', 'custom_gse', 'action' ] list_filter = [ 'status', 'paper__journal', 'treats__factor__name', 'treats__factor__type', ImpactFactorFilter, EmptyFilter ] search_fields = [ 'id', 'paper__title', 'paper__pmid', 'paper__journal__name', 'treats__factor__name', 'treats__unique_id', 'conts__unique_id', 'treats__series_id', 'conts__series_id' ] list_per_page = 100 list_display_links = ['action'] list_max_show_all = 5000 def change_view(self, request, object_id, form_url='', extra_context=None): self.inlines = [ TreatInline, ContInline, ] self.fields = [ 'user', 'paper', 'date_created', 'status', 'comments', 'full_text' ] return super(DatasetAdmin, self).change_view(request, object_id, form_url, extra_context) def add_view(self, request, form_url='', extra_context=None): self.inlines = [] self.form = DatasetAddForm self.fields = [ 'user', 'paper', 'treats', 'conts', 'date_created', 'status', 'comments', ] return super(DatasetAdmin, self).add_view(request, form_url, extra_context) def suit_row_attributes(self, obj): css_class = { 'validated': 'success', 'complete': 'success' }.get(obj.status) if css_class: return {'class': css_class} def get_form(self, request, obj=None, **kwargs): # just save sample reference for future processing in Treatment & Control Inline request._dataset_ = obj return super(DatasetAdmin, self).get_form(request, obj, **kwargs) def action(self, obj): return "Change" def custom_id(self, obj): return '<a href="http://cistrome.org/finder/util/meta?did=%s" target="_blank">%s</a>' % ( obj.id, obj.id) geo_link_template = '<a href="http://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=%s" target="_blank">%s</a>' \ '<a href="http://cistrome.org/dc/new_admin/datacollection/samples/?q=%s" target="_blank"><i class="icon-search"></i></a></br> %s' def custom_treats(self, obj): treats_list = obj.treats.all().order_by('unique_id') return "</br>".join([ DatasetAdmin.geo_link_template % (i.unique_id, i.unique_id, " ".join(re.findall( r"\d+", i.unique_id)), i.name) for i in treats_list ]) gse_link_template = '<a href="http://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE%s" target="_blank">GSE%s</a>' \ '<a href="http://cistrome.org/dc/new_admin/datacollection/samples/?q=%s" target="_blank"><i class="icon-search"></i></a></br>' \ '<a href="http://cistrome.org/dc/new_admin/datacollection/datasets/?q=GSE%s" target="_blank"><i class="icon-magnet"></i></a></br>' def custom_gse(self, obj): treats_list = obj.treats.all() if treats_list: try: gse_id = json.loads( treats_list[0].other_ids)['gse'].strip()[-5:] return DatasetAdmin.gse_link_template % (gse_id, gse_id, gse_id, gse_id) except: return "" return "" def custom_conts(self, obj): conts_list = obj.conts.all().order_by('unique_id') return "</br>".join([ DatasetAdmin.geo_link_template % (i.unique_id, i.unique_id, " ".join(re.findall( r"\d+", i.unique_id)), i.name) for i in conts_list ]) custom_id.allow_tags = True custom_id.short_description = 'ID' custom_id.ordering = 'id' custom_treats.allow_tags = True custom_treats.short_description = "Treatment IDs" custom_conts.allow_tags = True custom_conts.short_description = "Control IDs" custom_gse.allow_tags = True custom_gse.short_description = "GSE ID"
class BaseTagObjectForm(GroupKwargModelFormMixin, UserKwargModelFormMixin, forms.ModelForm): like = forms.BooleanField(label=_('Like'), required=False) approach = Select2ChoiceField(choices=TagObject.APPROACH_CHOICES, required=False) topics = CommaSeparatedSelect2MultipleChoiceField( choices=TagObject.TOPIC_CHOICES, required=False) visibility = Select2ChoiceField( choices=TagObject.VISIBILITY_CHOICES, required=False, widget=Select2Widget(select2_options={'allowClear': False}) ) # the widget currently ignores the allowClear setting! # persons = will be defined in __init__ class Meta(object): model = TagObject exclude = ( 'group', 'likes', 'likers', ) widgets = { 'location_lat': forms.HiddenInput(), 'location_lon': forms.HiddenInput(), } def __init__(self, *args, **kwargs): """ Initialize and populate the select2 tags field """ super(BaseTagObjectForm, self).__init__(*args, **kwargs) # needs to be initialized here because using reverser_lazy() at model instantiation time causes problems self.fields['tags'] = TagSelect2Field( required=False, data_url=reverse_lazy('cosinnus:select2:tags')) # inherit tags from group for new TaggableObjects preresults = [] if self.instance.pk: preresults = self.instance.tags.values_list('name', 'name').all() elif self.group: preresults = self.group.media_tag.tags.values_list('name', 'name').all() if preresults: self.fields['tags'].choices = preresults self.fields['tags'].initial = [ key for key, val in preresults ] #[tag.name for tag in self.instance.tags.all()] self.initial['tags'] = self.fields['tags'].initial # if no media tag data was supplied the object was created directly and not through a frontend form # we then manually inherit the group's media_tag topics by adding them to the data # (usually they would have been added into the form's initial data) if self.data and not any( [key.startswith('media_tag-') for key in list(self.data.keys())] ) and self.group and self.group.media_tag and self.group.media_tag.topics: self.data._mutable = True self.data.setlist('media_tag-topics', self.group.media_tag.topics.split(',')) if self.group and not self.instance.pk: # for new TaggableObjects (not groups), set the default visibility corresponding to the group's public status self.fields[ 'visibility'].initial = get_inherited_visibility_from_group( self.group) if self.group: data_url = group_aware_reverse('cosinnus:select2:group-members', kwargs={'group': self.group}) else: data_url = reverse('cosinnus:select2:all-members') # override the default persons field with select2 #self.fields['persons'] = HeavySelect2MultipleChoiceField(label=_("Persons"), help_text='', required=False, data_url=data_url) self.fields['persons'] = UserSelect2MultipleChoiceField( label=_("Persons"), help_text='', required=False, data_url=data_url) if self.instance.pk: # choices and initial must be set so pre-existing form fields can be prepopulated preresults = get_user_select2_pills(self.instance.persons.all(), text_only=False) self.fields['persons'].choices = preresults self.fields['persons'].initial = [key for key, val in preresults] self.initial['persons'] = self.fields['persons'].initial if self.group and self.group.media_tag_id: group_media_tag = self.group.media_tag if group_media_tag and group_media_tag is not self.instance: # We must only take data from the group's media tag iff we are # working on a TaggableObjectModel, not on a group opts = self._meta # 1. Use all the data from the group's media tag # 2. Use the explicitly defined initial data (self.initial) and # override the data from the group media tag # 3. Set the combined data as new initial data group_data = forms.model_to_dict(group_media_tag, opts.fields, opts.exclude) group_data.update(self.initial) old_initial = self.initial self.initial = group_data # the default visibility corresponds to group's public setting if 'visibility' in old_initial: self.initial['visibility'] = old_initial['visibility'] else: self.initial[ 'visibility'] = get_inherited_visibility_from_group( self.group) if (self.user and self.instance.pk and self.instance.likers.filter(id=self.user.id).exists()): self.fields['like'].initial = True # use select2 widgets for m2m fields for field in [ self.fields['text_topics'], ]: if type(field.widget) is SelectMultiple: field.widget = Select2MultipleWidget(choices=field.choices) # since the widget currently ignores the allowClear setting we have # to use this hack to remove the clear-button self.fields['visibility'].widget.is_required = True # save BBB room if self.instance.pk and self.instance.bbb_room: self.initial['bbb_room'] = self.instance.bbb_room def save(self, commit=True): self.instance = super(BaseTagObjectForm, self).save(commit=False) # restore BBB room if 'bbb_room' in self.initial: self.instance.bbb_room = self.initial['bbb_room'] # the tag inherits the visibility default from the instance's group # if no or no valid visibility has been selected in the form, visibility_data_value = get_int_or_None( self.cleaned_data.get('visibility', None)) if visibility_data_value not in BaseTagObject.VISIBILITY_VALID_VALUES: # check if our tag object belongs to a group (i.e: isn't itself a group, or a user): if hasattr(self.instance, 'group') and self.instance.group: self.instance.visibility = get_inherited_visibility_from_group( self.instance.group) if self.user: if not self.instance.pk: # We need to save the tag here to allow add/remove of the user self.instance.save() if self.cleaned_data.get('like', False): self.instance.likers.add(self.user) else: self.instance.likers.remove(self.user) # like count is updated in model.save() if commit: self.instance.save() # For future reference: we skip the call to `save_m2m` here, because the django-multiform `MultiModelForm` already calls it! # This should be safe, but maybe in a bug corner case it could cause the `save_m2m` call to be skipped entirely # self.save_m2m() return self.instance
class SampleAdmin(admin.ModelAdmin): class Media: js = ("new_admin.js", ) mass_update_form = SampleMassUpdateForm formfield_overrides = { models.ForeignKey: { 'widget': Select2Widget(attrs={"style": "width: 300px;"}) }, } list_display = [ 'id', 'unique_id_url', 'other_id', 'status', 'custom_name', 'factor', 'species', 'cell_category', 'cell_source', 'condition', 'custom_antibody', 'custom_description', 'paper', 'action', 'custom_recheck' ] search_fields = [ 'id', 'unique_id', 'other_ids', 'factor__name', 'species__name', 'cell_type__name', 'cell_line__name', 'cell_pop__name', 'strain__name', 'name', 'condition__name', 'disease_state__name', 'tissue_type__name', 'antibody__name', 'description', 'series_id' ] list_display_links = ['action'] list_filter = [ 'status', 'species__name', 'factor__name', 'factor__type', CellInfoFilter, FactorInfoFilter, GroupingInfoFilter, RecheckInfoFilter ] list_per_page = 200 def suit_row_attributes(self, obj, request): css_class = { 'imported': 'success', 'checked': 'success', 'new': 'warning', "ignored": 'info', }.get(obj.status) if css_class: return {'class': css_class} def custom_recheck(self, obj): ret = "" if obj.re_check: recheck_dict = json.loads(obj.re_check) for k in recheck_dict: ret += "<strong>%s</strong>: %s<br>" % (k.title(), recheck_dict[k]) return ret def custom_name(self, obj): if obj.name: return obj.name.replace("_", " ") def unique_id_url(self, obj): return '<a href="http://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=%s" target="_blank">%s</a>' % ( obj.unique_id, obj.unique_id) def other_id(self, obj): ret = "" try: other_ids = json.loads(obj.other_ids) except: return ret if other_ids['pmid']: pmid = other_ids['pmid'].strip() ret += '<a href="http://www.ncbi.nlm.nih.gov/pubmed/%s" target="_blank">P%s</a><br>' % ( pmid, pmid) if other_ids['gse']: gse = other_ids['gse'].strip()[-5:] ret += '<br><a href="http://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE%s" target="_blank">GSE%s</a>' % ( gse, gse) return ret def action(self, obj): return "Change" def custom_antibody(self, obj): return obj.antibody def custom_description(self, obj): ret = "" if obj.description: desc_dict = json.loads(obj.description) for k in desc_dict: ret += "<strong>%s</strong>: %s<br>" % (k.title(), desc_dict[k]) return ret def cell_source(self, obj): ret = "" if obj.cell_line: ret += "<strong>Cell Line</strong>: %s<br>" % obj.cell_line if obj.cell_pop: ret += "<strong>Cell Pop</strong>: %s<br>" % obj.cell_pop if obj.strain: ret += "<strong>Strain</strong>: %s<br>" % obj.strain return ret def cell_category(self, obj): ret = "" if obj.cell_type: ret += "<strong>Cell Type</strong>: %s<br>" % obj.cell_type if obj.disease_state: ret += "<strong>Disease</strong>: %s<br>" % obj.disease_state if obj.tissue_type: ret += "<strong>Tissue</strong>: %s<br>" % obj.tissue_type return ret custom_antibody.allow_tags = True custom_antibody.short_description = 'Antibody' custom_antibody.admin_order_field = 'antibody' custom_description.allow_tags = True custom_description.short_description = "Description" custom_recheck.allow_tags = True custom_recheck.short_description = "Recheck" custom_name.short_description = "Name" custom_name.admin_order_field = 'name' cell_source.allow_tags = True cell_category.allow_tags = True unique_id_url.short_description = 'Sample ID' unique_id_url.allow_tags = True unique_id_url.admin_order_field = 'unique_id' other_id.short_description = 'Other ID' other_id.allow_tags = True ordering = ['-id'] list_max_show_all = 5000
class ManageFolderForm(FileFormMixin, forms.ModelForm): """ Manage folder (in the modal). """ image = UploadedFileField(required=False) parent = OnlyNameChoiceField(queryset=Folder.objects.all(), empty_label=_(u'(None)'), label=_(u'Parent folder'), required=False, widget=Select2Widget()) subscriptions = OnlyNameMultipleChoiceField( label=_(u'Subscriptions'), queryset=Subscription.objects.none(), required=False, widget=Select2MultipleWidget(), help_text=_(u'These are the ones held directly by the folder; they ' u'are displayed above subfolders. There can be none, if ' u'you prefer dispatching your subscriptions in subfolders ' u'only.')) class Meta: model = Folder fields = ( 'name', 'slug', 'image_url', 'parent', # 'is_shared', 'is_moderated', 'is_restricted', # 'anonymous_membership', ) # widgets = { # 'name': forms.TextInput(), # } def __init__(self, *args, **kwargs): """ init(me). """ self.folder_owner = kwargs.pop('owner') super(ManageFolderForm, self).__init__(*args, **kwargs) folders_tree = self.folder_owner.get_folders_tree(for_parent=True) if self.instance.id: try: folders_tree.exclude(id=self.instance.id) except ValueError: pass else: for f in self.instance.children_tree: try: folders_tree.exclude(id=f.id) except ValueError: # ValueError: list.remove(x): x not in list # Happens when try to remove a level-N+ folder # from a list limited to level N-1 folder. No # need to continue, folders_tree return a # depth-aware list. break try: self.fields['subscriptions'].initial = \ self.folder_owner.subscriptions_by_folder[self.instance] except KeyError: # No subscriptions in this folder yet. pass self.fields['parent'].queryset = folders_tree self.fields['subscriptions'].queryset = \ self.folder_owner.subscriptions.order_by('name') def clean_parent(self): """ Return root if no parent selected. """ try: parent = self.cleaned_data['parent'] except: return self.folder_owner.root_folder if parent is None: return self.folder_owner.root_folder return parent def is_valid(self): """ Check a lot of internal stuff to be useful to the user. """ res = super(ManageFolderForm, self).is_valid() if not res: return False if self.instance.id is None: parent_folder = self.cleaned_data['parent'] try: Folder.objects.get(user=self.folder_owner, name=self.cleaned_data['name'], parent=parent_folder) except Folder.DoesNotExist: return True else: if parent_folder == self.folder_owner.root_folder: self._errors['already_exists'] = \ _(u'A top folder by that name already exists.') else: self._errors['already_exists'] = \ _(u'A folder by that name already exists ' u'at the same place.') return False return True def save(self, commit=True): """ Save folder and synchronize_subscriptions_folders(). """ if self.cleaned_data['image']: self.instance.image = self.cleaned_data['image'] else: self.instance.image = None parent_folder = self.cleaned_data.get('parent') parent_changed = False # id == None means creation, else we are editing. if self.instance.id: # We need to get the previous values; Django doesn't cache # them and self.instance is already updated with new values. old_folder = Folder.objects.get(id=self.instance.id) if old_folder.parent != parent_folder: # The form.save() will set the new parent, but # will not unset instance from parent.children. # We need to take care of this. try: old_folder.parent.children.remove(self.instance) except AttributeError: # A top folder is becoming a sub-folder. It had no parent. pass parent_changed = True else: # In "add folder" mode, parent has always changed, it's new! parent_changed = True folder = super(ManageFolderForm, self).save(commit=False) if self.instance.id is None: folder.user = self.folder_owner if commit: folder.save() if parent_changed: # In edit or create mode, we need to take care of the other # direction of the double-linked relation. This will imply # a superfluous write in case of an unchanged parent parent_folder.children.add(folder) self.synchronize_subscriptions_folders(folder) self.delete_temporary_files() return folder def synchronize_subscriptions_folders(self, folder): """ Move subscriptions from old folder to new, given user prefs. .. note:: `folder` is just self.instance passed through to avoid to look it up again. """ try: initial_subscriptions = \ self.folder_owner.subscriptions_by_folder[self.instance] except KeyError: initial_subscriptions = [] updated_subscriptions = self.cleaned_data['subscriptions'] for subscription in initial_subscriptions: if subscription not in updated_subscriptions: subscription.folders.remove(folder) if self.folder_owner.preferences.selector.subscriptions_in_multiple_folders: # NOQA replace_folders = False else: replace_folders = True for subscription in updated_subscriptions: # This will update more things than needed, but in the case of # a changed preference, this will make the subscription appear # in one folder only again. # TODO: when the preference has a trigger on save() that do # this automatically, uncomment the following line to simply # move new subscriptions to this folder, and not touch others. # # if subscription not in initial_subscriptions: if replace_folders: subscription.folders.clear() subscription.folders.add(folder)