def fields(self): fk = getattr(self.formset, "fk", None) empty_form = self.formset.empty_form meta_labels = empty_form._meta.labels or {} meta_help_texts = empty_form._meta.help_texts or {} for i, field_name in enumerate(flatten_fieldsets(self.fieldsets)): if fk and fk.name == field_name: continue if not self.has_change_permission or field_name in self.readonly_fields: yield { 'label': meta_labels.get(field_name) or label_for_field(field_name, self.opts.model, self.opts), 'widget': {'is_hidden': False}, 'required': False, 'help_text': meta_help_texts.get(field_name) or help_text_for_field(field_name, self.opts.model), } else: form_field = empty_form.fields[field_name] label = form_field.label if label is None: label = label_for_field(field_name, self.opts.model, self.opts) yield { 'label': label, 'widget': form_field.widget, 'required': form_field.required, 'help_text': form_field.help_text, }
def test_related_name(self): """ Regression test for #13963 """ self.assertEqual(label_for_field("location", Event, return_attr=True), ("location", None)) self.assertEqual(label_for_field("event", Location, return_attr=True), ("awesome event", None)) self.assertEqual(label_for_field("guest", Event, return_attr=True), ("awesome guest", None))
def fields(self): fk = getattr(self.formset, "fk", None) for i, field_name in enumerate(flatten_fieldsets(self.fieldsets)): if fk and fk.name == field_name: continue if field_name in self.readonly_fields: yield { 'label': label_for_field(field_name, self.opts.model, self.opts), 'widget': { 'is_hidden': False }, 'required': False, 'help_text': help_text_for_field(field_name, self.opts.model), } else: form_field = self.formset.form.base_fields[field_name] label = form_field.label if label is None: label = label_for_field(field_name, self.opts.model, self.opts) yield { 'label': label, 'widget': form_field.widget, 'required': form_field.required, 'help_text': form_field.help_text, }
def changelist_view(self, request, extra_context=None): response = super(TotalsumAdmin, self).changelist_view(request, extra_context) if not hasattr(response, 'context_data') or 'cl' not in response.context_data: return response filtered_query_set = response.context_data["cl"].queryset extra_context = extra_context or {} extra_context['totals'] = {} extra_context['unit_of_measure'] = self.unit_of_measure for elem in self.totalsum_list: try: self.model._meta.get_field(elem) # Checking if elem is a field total = filtered_query_set.aggregate(totalsum_field=Sum(elem))['totalsum_field'] if total is not None: extra_context['totals'][label_for_field(elem, self.model, self)] = round( total, self.totalsum_decimal_places) except FieldDoesNotExist: # maybe it's a property if hasattr(self.model, elem): total = 0 for f in filtered_query_set: total += getattr(f, elem, 0) extra_context['totals'][label_for_field(elem, self.model, self)] = round( total, self.totalsum_decimal_places) response.context_data.update(extra_context) return response
def test_list_label_abc(self): # Ensure model data is correct self.assertEqual(ConcreteModel._parler_meta.root_model._meta.get_field_by_name('tr_title')[0].verbose_name, "Translated Title") # See that the TranslatedFieldDescriptor of the concrete model properly routes to the proper model self.assertEqual(label_for_field('tr_title', ConcreteModel), "Translated Title") # See that the TranslatedFieldDescriptor of the abstract model handles the fallback properly. self.assertEqual(label_for_field('tr_title', AbstractModel), "Tr title")
def test_label_for_field_form_argument(self): class ArticleForm(forms.ModelForm): extra_form_field = forms.BooleanField() class Meta: fields = '__all__' model = Article self.assertEqual( label_for_field('extra_form_field', Article, form=ArticleForm()), 'Extra form field' ) msg = "Unable to lookup 'nonexistent' on Article or ArticleForm" with self.assertRaisesMessage(AttributeError, msg): label_for_field('nonexistent', Article, form=ArticleForm()),
def export_model_as_csv(modeladmin, request, queryset): if hasattr(modeladmin, 'exportable_fields'): field_list = modeladmin.exportable_fields else: # Copy modeladmin.list_display to remove action_checkbox field_list = list(modeladmin.list_display) response = HttpResponse(mimetype='text/csv') response['Content-Disposition'] = 'attachment; filename=%s-%s-export-%s.csv' % ( __package__.lower(), queryset.model.__name__.lower(), datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S'), ) writer = csv.writer(response) writer.writerow( [admin_util.label_for_field(f, queryset.model, modeladmin) for f in field_list], ) for obj in queryset: csv_line_values = [] for field in field_list: field_obj, attr, value = admin_util.lookup_field(field, obj, modeladmin) csv_line_values.append(value) writer.writerow(csv_line_values) return response
def test_related_name(self): """ Regression test for #13963 """ self.assertEqual( label_for_field('location', Event, return_attr=True), ('location', None), ) self.assertEqual( label_for_field('event', Location, return_attr=True), ('awesome event', None), ) self.assertEqual( label_for_field('guest', Event, return_attr=True), ('awesome guest', None), )
def test_list_label(self): # Ensure model data is correct self.assertEqual(SimpleModel._parler_meta.root_model._meta.get_field_by_name('tr_title')[0].verbose_name, "Translated Title") # See that adding a field to the admin list_display also receives the translated title # This happens by TranslatedFieldDescriptor.short_description self.assertEqual(label_for_field('tr_title', SimpleModel), "Translated Title")
def __init__(self, form, field, is_first, model_admin=None): # Make self.field look a little bit like a field. This means that # {{ field.name }} must be a useful class name to identify the field. # For convenience, store other field-related data here too. if callable(field): class_name = field.__name__ if field.__name__ != '<lambda>' else '' else: class_name = field if form._meta.labels and class_name in form._meta.labels: label = form._meta.labels[class_name] else: label = label_for_field(field, form._meta.model, model_admin) if form._meta.help_texts and class_name in form._meta.help_texts: help_text = form._meta.help_texts[class_name] else: help_text = help_text_for_field(class_name, form._meta.model) self.field = { 'name': class_name, 'label': label, 'help_text': help_text, 'field': field, } self.form = form self.model_admin = model_admin self.is_first = is_first self.is_checkbox = False self.is_readonly = True self.empty_value_display = model_admin.get_empty_value_display()
def set_options(list_display): labels = {k: label_for_field(k, MyModel, CustomizedListDisplayAdmin) for k, _ in list_display.items()} return format_html_join( '\n', mark_safe('<option value="{}"><strong>{}»</strong> {}</option>'), ((k, _('+ 显示') if v == 0 else _('- 隐藏'), labels.get(k) if labels.get(k) else k) for k, v in list_display.items()) )
def __init__(self, field, instance): if callable(field): class_name = field.__name__ != '<lambda>' and field.__name__ or '' else: class_name = field self.name = class_name self.label = label_for_field(field, instance.__class__) self.field_repr = get_field_value(field, instance) self.help_text = get_field_attr(field, instance, "help_text", "")
def label(self): # TODO: Add support for related fields (dotted or double underscore attributes) if not self._label: if self.attribute: self._label = label_for_field( name=self.attribute, model=self.source._meta.model ) else: self._label = 'Function' return self._label
def test_label_for_property(self): # NOTE: cannot use @property decorator, because of # AttributeError: 'property' object has no attribute 'short_description' class MockModelAdmin(object): def my_property(self): return "this if from property" my_property.short_description = 'property short description' test_from_property = property(my_property) self.assertEqual( label_for_field("test_from_property", Article, model_admin=MockModelAdmin), 'property short description' )
def batch_upload_response(self, request): output_fields = flatten_fieldsets(self.fieldsets) media_file_name = get_media_file_name(self, self.model) #Disabling exception handling here @olivierdalang's feedback: # try: latest_log_entry = LogEntry.objects.filter(action_flag=ADDITION).order_by('-action_time')[0] ct = ContentType.objects.get_for_id(latest_log_entry.content_type_id) obj = ct.get_object_for_this_type(pk=latest_log_entry.object_id) if obj: object_data = {} mime = MimeTypes() media_file = get_media_file(self, self.model, obj) media_file_url = media_file.url #urllib.pathname2url(media_file.url) #Not sure why i had this, but it's escaping the URL mime_type = mime.guess_type(media_file_url) edit_url = reverse('admin:%s_%s_change' %(obj._meta.app_label, obj._meta.model_name), args=[obj.id] ) object_data['media_file_url'] = media_file_url object_data['media_file_size'] = media_file.size object_data['media_file_type'] = mime_type[0] object_data['edit_url'] = mark_safe(edit_url) field_values = {} for output_field in output_fields: value = str(self.get_field_contents(output_field, obj)) label = str(label_for_field(output_field, self.model, self)) field_values[output_field] = { 'label':label, 'value':value } object_data['field_values'] = field_values data = { "success":True, "files":[ object_data ] } json_dumped = json.dumps(data) return HttpResponse(json_dumped, content_type='application/json')
def export_changelist_view(self, request, extra_context=None): delimiter = (extra_context or {}).get('export_delimiter', None) response = super(ExportableAdmin, self).changelist_view( request, extra_context) cl = response.context_data['cl'] # get headers res_headers = OrderedDict() for field_name in cl.list_display: if field_name == 'action_checkbox': continue label = label_for_field( field_name, cl.model, model_admin=cl.model_admin) res_headers[field_name] = label pseudo_buffer = Echo() # get result rows def generate_response(): csv = UnicodeWriter( pseudo_buffer, fieldnames=res_headers.values(), delimiter=str(delimiter)) for result in cl.queryset.iterator(): row = {} for field_name in cl.list_display: if field_name == 'action_checkbox': continue try: _, _, value = lookup_field( field_name, result, cl.model_admin) except ObjectDoesNotExist: value = None if isinstance(value, six.string_types): value = strip_tags(value) row[res_headers[field_name]] = value yield csv.writerow(row) # build response csv response = StreamingHttpResponse( generate_response(), content_type='text/csv') response['Content-Disposition'] = \ 'attachment; filename={0}.csv'.format( slugify(self.model._meta.verbose_name)) return response
def fields(self): fk = getattr(self.formset, "fk", None) for i, field_name in enumerate(flatten_fieldsets(self.fieldsets)): if fk and fk.name == field_name: continue if field_name in self.readonly_fields: yield { "label": label_for_field(field_name, self.opts.model, self.opts), "widget": {"is_hidden": False}, "required": False, "help_text": help_text_for_field(field_name, self.opts.model), } else: form_field = self.formset.form.base_fields[field_name] label = form_field.label if label is None: label = label_for_field(field_name, self.opts.model, self.opts) yield { "label": label, "widget": form_field.widget, "required": form_field.required, "help_text": form_field.help_text, }
def _label(self, field): """ Returns a pretty name for the given field. First check is the label_overrides dict. Remaining checks follow the django admin's pattern (including, for example, short_description support.) """ if field in self.label_overrides: return self.label_overrides[field] try: return label_for_field(field, self.model, self) except AttributeError: # Trust that it exists, for now. return pretty_name(field)
def labels(self): """ Get field label for fields """ if type(self.object_list) == type([]): model = self.formset.model else: model = self.object_list.model for field in self.visible_fields: name = None if self.formset: f = self.formset.empty_form.fields.get(field, None) if f: name = f.label if name is None: name = label_for_field(field, model) if name == model._meta.verbose_name: name = self.model_name and self.model_name or \ model._meta.verbose_name stype = None cur_sorted = False sortable = False if self.order_type: sortable = get_sort_field(field, model) stype = self.ASC # change order_type so that next sorting on the same # field will give reversed results if sortable and field == self.sort_field: cur_sorted = True if self.order_type == self.ASC: stype = self.DESC elif self.order_type == self.DESC: stype = self.ASC else: stype = self.ASC yield AdminListLabel(name, field, stype, cur_sorted, bool(sortable))
def changelist_view(self, request, *args, **kwargs): choices = [] for field_name in self.list_display_variants: text = label_for_field( field_name, self.model, model_admin=self ) choices.append((field_name, text)) opts = self.model._meta changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name) kwargs['extra_context'] = dict( list_display_form_action_url=reverse(changelist_url), list_display_form=self.field_select_form( choices, initial=dict(list_display_select=self.get_list_display(request)) ) ) return super(FieldSelectMixin, self).changelist_view(request, *args, **kwargs)
def test_admin_obj_mixin(self): # setup the admin site and id self.initiate() inner_admin = InnerAdmin(Inner, self.site) outer_admin = OuterAdmin(Outer, self.site) n1 = Nested.objects.create(name='n1') i1 = Inner.objects.create(name='i1', nested=n1) o1 = Outer.objects.create(name='o1', inner=i1) # check the basic __str__ named link from Inner to Nested html = self.field_value(inner_admin, i1, 'show_nested') url, text = parse_link(html) self.assertEqual('Nested(id=1 n1)', text) self.assertEqual('/admin/tests/nested/?id__exact=1', url) # check the template based name link of Inner from Outer html = self.field_value(outer_admin, o1, 'show_inner') url, text = parse_link(html) self.assertEqual('Inner.id=1', text) self.assertEqual('/admin/tests/inner/?id__exact=1', url) # check the double dereferenced Nested from Outer html = self.field_value(outer_admin, o1, 'show_nested') url, text = parse_link(html) self.assertEqual('Nested(id=1 n1)', text) self.assertEqual('/admin/tests/nested/?id__exact=1', url) # check the title got set correctly label = label_for_field('show_inner', o1, outer_admin) self.assertEqual(label, 'My Inner') # check that empty values work properly o2 = Outer.objects.create(name='o2') result = self.field_value(outer_admin, o2, 'show_nested') self.assertEqual('', result) i2 = Inner.objects.create(name='i2') o2.inner = i2 o2.save() result = self.field_value(outer_admin, o2, 'show_nested') self.assertEqual('', result)
def get_display_fields(self, models): """ :param models: List of models :return: List fields for display. Format [field name, field label] """ fields = [] field_names = [] for model_cls in models: admin_cls = admin.site._registry[model_cls] for field_name in admin_cls.list_display: if field_name not in field_names: if field_name == '__str__' or field_name == '__unicode__': field_label = _(u'Object name') fields.insert(0, [field_name, field_label]) else: field_label = unicode(label_for_field(field_name, model_cls, admin_cls)) fields.append([field_name, field_label]) field_names.append(field_name) return fields
def export_as_csv(modeladmin, request, queryset): """ Generic csv export admin action. based on http://djangosnippets.org/snippets/1697/ and /2020/ """ # TODO Also create export_as_csv for exporting all columns including list_display if not request.user.is_staff: raise PermissionDenied opts = modeladmin.model._meta field_names = modeladmin.list_display if 'action_checkbox' in field_names: field_names.remove('action_checkbox') response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = 'attachment; filename=%s.csv' % unicode(opts).replace('.', '_') writer = csv.writer(response) if header: headers = [] for field_name in list(field_names): label = label_for_field(field_name,modeladmin.model,modeladmin) label = str(label) if str.islower(label): label = str.title(label) headers.append(label) writer.writerow(headers) for row in queryset: values = [] for field in field_names: value = (getattr(row, field)) if callable(value): try: value = value() or '' except: value = 'Error retrieving value' if value is None: value = '' values.append(unicode(value).encode('utf-8')) writer.writerow(values) return response
def action_csv_export(self, request, queryset): result = '' def _quote_csv(col_html): u = html.strip_tags(str(col_html)) u = u.rstrip('\n\r') # remove trailing \n # drop spaces at the begining of the line: u = re.sub('^[ \t\n\r\f\v]+', '', u, flags=re.MULTILINE) u = re.sub('[ \t\n\r\f\v]*\n', '\n', u) # remove duplicates \n # Unquote u = u.replace('"', '"').replace(''', "'") # Do the actual escaping/quoting (quotes doubling for libreoffice) return '"' + u.replace('"', '""') + '"' header_done = False for row in queryset: if not header_done: for i, field_name in enumerate(self.list_display): text, attr = label_for_field( field_name, type(row), self, True) if i: # not first column result += ',' result += _quote_csv(text) result += '\n' header_done = True for i, field_name in enumerate(self.list_display): if i: # not first column result += ',' f, attr, value = lookup_field(field_name, row, self) if value is None: continue if f is None: col_html = display_for_value(value, False) else: col_html = display_for_field(value, f) result += _quote_csv(col_html) result += '\n' return HttpResponse(result, content_type='text/csv; charset=utf-8')
def set_columns_labels(model, columns): for col in columns: if 'columns' in col: set_columns_labels(model, col['columns']) elif 'label' not in col: col['label'] = label_for_field(col['field'], model)
def test_list_label_abc(self): # See that the TranslatedFieldDescriptor of the concrete model properly routes to the proper model self.assertEqual(label_for_field('tr_title', ConcreteModel), "Translated Title") # See that the TranslatedFieldDescriptor of the abstract model handles the fallback properly. self.assertEqual(label_for_field('tr_title', AbstractModel), "Tr title")
def test_label_for_field(self): """ Tests for label_for_field """ self.assertEqual( label_for_field("title", Article), "title" ) self.assertEqual( label_for_field("hist", Article), "History" ) self.assertEqual( label_for_field("hist", Article, return_attr=True), ("History", None) ) self.assertEqual( label_for_field("__str__", Article), "article" ) with self.assertRaisesMessage(AttributeError, "Unable to lookup 'unknown' on Article"): label_for_field("unknown", Article) def test_callable(obj): return "nothing" self.assertEqual( label_for_field(test_callable, Article), "Test callable" ) self.assertEqual( label_for_field(test_callable, Article, return_attr=True), ("Test callable", test_callable) ) self.assertEqual( label_for_field("test_from_model", Article), "Test from model" ) self.assertEqual( label_for_field("test_from_model", Article, return_attr=True), ("Test from model", Article.test_from_model) ) self.assertEqual( label_for_field("test_from_model_with_override", Article), "not What you Expect" ) self.assertEqual( label_for_field(lambda x: "nothing", Article), "--" ) self.assertEqual(label_for_field('site_id', Article), 'Site id') class MockModelAdmin: def test_from_model(self, obj): return "nothing" test_from_model.short_description = "not Really the Model" self.assertEqual( label_for_field("test_from_model", Article, model_admin=MockModelAdmin), "not Really the Model" ) self.assertEqual( label_for_field("test_from_model", Article, model_admin=MockModelAdmin, return_attr=True), ("not Really the Model", MockModelAdmin.test_from_model) )
def changelist_view(self, request, extra_context=None): response = super(TotalsumAdmin, self).changelist_view(request, extra_context) if not hasattr(response, "context_data") or "cl" not in response.context_data: return response filtered_query_set = response.context_data["cl"].queryset extra_context = extra_context or {} extra_context["totals"] = {} extra_context["unit_of_measure"] = self.unit_of_measure #import pdb; pdb.set_trace() if hasattr(self, 'totals_sum'): # added nc self.totalsum_list = self.totals_sum(self) #for elem in getattr(self, 'totals_sum', self.totalsum_list): x function not method for elem in self.totalsum_list: try: self.model._meta.get_field(elem) # Checking if elem is a field total = filtered_query_set.aggregate(totalsum_field=Sum(elem))[ "totalsum_field" ] if total is not None: extra_context["totals"][ label_for_field(elem, self.model, self) ] = round(total, self.totalsum_decimal_places) except FieldDoesNotExist: # maybe it's a model property (or later just search on the adminmodel i.e. self) #import pdb; pdb.set_trace() #entity = self # changed from self.model # label failing for annotations (annotations are dealt with here) try: '''this is a method on the model''' #if hasattr(self.model, elem): # changed from self.model total = 0 fired = False for f in filtered_query_set: qq = getattr(f, elem)#, 0) if not qq == '-': total += qq fired = True if fired: extra_context["totals"][ label_for_field(elem, self.model, self) # origional self.model ] = round(total, self.totalsum_decimal_places) except AttributeError: # added '''this is a function on the admin, we pass the query item as the obj argument''' #xelem = elem+'_totals' # what for?? #if hasattr(self, xelem): try: total = 0 fired = False for f in filtered_query_set: qq = getattr(self, elem)(f) if not qq == '-': #import pdb; pdb.set_trace() #if isintance(qq,str) and qq total += int(qq) fired = True if fired: extra_context["totals"][ label_for_field(elem, self.model, self) ] = round(total, self.totalsum_decimal_places) except: pass # fixme - check origional behavior response.context_data.update(extra_context) return response
def report(modeladmin, request, queryset): header = [] linhas = [] style = [] for field in fields: field_detail = field.split(':') field_name = field_detail[0] text, attr = label_for_field(field_name, modeladmin.model, model_admin=modeladmin, return_attr=True) if len(fields) < 3: align = "text-align: %s;" % 'left' width = '"width: %s; %s"' % ('400px', align) else: align = "text-align: %s;" % ( field_detail[2] if len(field_detail) > 2 else 'center') width = '"width: %s; %s"' % ( field_detail[1] if len(field_detail) > 1 else '300px', align) style.append(width) header.append( '<th class="border-top border-bottom" style=%s><b>%s</b></th>' % (width, text)) for obj in queryset: line = '' fieldno = 0 for field in fields: field_detail = field.split(':') field_name = field_detail[0] f, attr, value = lookup_field(field_name, obj, modeladmin) #print(f, attr, value) if f is None or f.auto_created: boolean = getattr(attr, 'boolean', False) result_repr = display_for_value(value, boolean) else: if isinstance(f.rel, models.ManyToOneRel): field_val = getattr(obj, f.name) if field_val is None: result_repr = ' ' else: result_repr = field_val else: result_repr = display_for_field(value, f, None) result_repr = nvl(strip_tags(result_repr), ' ') line += '<td style=%s>%s</td>' % (style[fieldno], result_repr) fieldno += 1 linhas.append(line) print(linhas) template = get_template(template_name) html = template.render({ 'title': title, 'header': header, 'linhas': linhas, }) result = io.BytesIO() pdf = pisaDocument( io.BytesIO(html.encode("UTF-8")), dest=result, link_callback=lambda uri, rel: os.path.join( settings.MEDIA_ROOT, uri.replace(settings.MEDIA_URL, ""))) if not pdf.err: return HttpResponse(result.getvalue(), content_type='application/pdf') return HttpResponse('Erro na geração do relatório<pre>%s</pre>' % cgi.escape(html))
def test_label_for_field(self): """ Tests for label_for_field """ self.assertEqual( label_for_field("title", Article), "title" ) self.assertEqual( label_for_field("hist", Article), "History" ) self.assertEqual( label_for_field("hist", Article, return_attr=True), ("History", None) ) self.assertEqual( label_for_field("__str__", Article), "article" ) with self.assertRaisesMessage(AttributeError, "Unable to lookup 'unknown' on Article"): label_for_field("unknown", Article) def test_callable(obj): return "nothing" self.assertEqual( label_for_field(test_callable, Article), "Test callable" ) self.assertEqual( label_for_field(test_callable, Article, return_attr=True), ("Test callable", test_callable) ) self.assertEqual( label_for_field("test_from_model", Article), "Test from model" ) self.assertEqual( label_for_field("test_from_model", Article, return_attr=True), ("Test from model", Article.test_from_model) ) self.assertEqual( label_for_field("test_from_model_with_override", Article), "not What you Expect" ) self.assertEqual( label_for_field(lambda x: "nothing", Article), "--" ) self.assertEqual(label_for_field('site_id', Article), 'Site id') class MockModelAdmin: @admin.display(description='not Really the Model') def test_from_model(self, obj): return "nothing" self.assertEqual( label_for_field("test_from_model", Article, model_admin=MockModelAdmin), "not Really the Model" ) self.assertEqual( label_for_field("test_from_model", Article, model_admin=MockModelAdmin, return_attr=True), ("not Really the Model", MockModelAdmin.test_from_model) )
def result_headers(cl): """ Generates the list column headers. """ ordering_field_columns = cl.get_ordering_field_columns() for i, field_name in enumerate(cl.list_display): text, attr = label_for_field( field_name, cl.model, model_admin=cl.model_admin, return_attr=True ) if attr: # Potentially not sortable # if the field is the action checkbox: no sorting and special class if field_name == 'action_checkbox': yield { "text": text, "class_attrib": mark_safe(' class="action-checkbox-column"'), "sortable": False, } continue admin_order_field = getattr(attr, "admin_order_field", None) if not admin_order_field: # Not sortable yield { "text": text, "class_attrib": format_html(' class="column-{}"', field_name), "sortable": False, } continue # OK, it is sortable if we got this far th_classes = ['sortable', 'column-{}'.format(field_name)] order_type = '' new_order_type = 'asc' sort_priority = 0 sorted = False # Is it currently being sorted on? if i in ordering_field_columns: sorted = True order_type = ordering_field_columns.get(i).lower() sort_priority = list(ordering_field_columns).index(i) + 1 th_classes.append('sorted %sending' % order_type) new_order_type = {'asc': 'desc', 'desc': 'asc'}[order_type] # build new ordering param o_list_primary = [] # URL for making this field the primary sort o_list_remove = [] # URL for removing this field from sort o_list_toggle = [] # URL for toggling order type for this field make_qs_param = lambda t, n: ('-' if t == 'desc' else '') + str(n) for j, ot in ordering_field_columns.items(): if j == i: # Same column param = make_qs_param(new_order_type, j) # We want clicking on this header to bring the ordering to the # front o_list_primary.insert(0, param) o_list_toggle.append(param) # o_list_remove - omit else: param = make_qs_param(ot, j) o_list_primary.append(param) o_list_toggle.append(param) o_list_remove.append(param) if i not in ordering_field_columns: o_list_primary.insert(0, make_qs_param(new_order_type, i)) yield { "text": text, "sortable": True, "sorted": sorted, "ascending": order_type == "asc", "sort_priority": sort_priority, "url_primary": cl.get_query_string({ORDER_VAR: '.'.join(o_list_primary)}), "url_remove": cl.get_query_string({ORDER_VAR: '.'.join(o_list_remove)}), "url_toggle": cl.get_query_string({ORDER_VAR: '.'.join(o_list_toggle)}), "class_attrib": format_html(' class="{}"', ' '.join(th_classes)) if th_classes else '', }
def get_field_label(self, field_name, field=None): """ Return a label to display for a field """ return label_for_field(field_name, model=self.model)
def get_heading(self, queryset, field): """ Get headings for exported spreadsheet column for the relevant field """ heading_override = self.export_heading_overrides.get(field) if heading_override: return force_str(heading_override) return force_str(label_for_field(field, model=self.model).title())
def result_header(self, field_name, row): ordering_field_columns = self.ordering_field_columns item = ResultHeader(field_name, row) text, attr = label_for_field(field_name, self.model, model_admin=self, return_attr=True ) item.text = text item.attr = attr if attr and not getattr(attr, "admin_order_field", None): return item # OK, it is sortable if we got this far th_classes = ['sortable'] order_type = '' new_order_type = 'desc' sort_priority = 0 sorted = False # Is it currently being sorted on? if field_name in ordering_field_columns: sorted = True order_type = ordering_field_columns.get(field_name).lower() sort_priority = list(ordering_field_columns.keys()).index(field_name) + 1 th_classes.append('sorted %sending' % order_type) new_order_type = {'asc': 'desc', 'desc': 'asc'}[order_type] # build new ordering param o_list_asc = [] # URL for making this field the primary sort o_list_desc = [] # URL for making this field the primary sort o_list_remove = [] # URL for removing this field from sort o_list_toggle = [] # URL for toggling order type for this field make_qs_param = lambda t, n: ('-' if t == 'desc' else '') + str(n) for j, ot in ordering_field_columns.items(): if j == field_name: # Same column param = make_qs_param(new_order_type, j) # We want clicking on this header to bring the ordering to the # front o_list_asc.insert(0, j) o_list_desc.insert(0, '-' + j) o_list_toggle.append(param) # o_list_remove - omit else: param = make_qs_param(ot, j) o_list_asc.append(param) o_list_desc.append(param) o_list_toggle.append(param) o_list_remove.append(param) if field_name not in ordering_field_columns: o_list_asc.insert(0, field_name) o_list_desc.insert(0, '-' + field_name) item.sorted = sorted item.sortable = True item.ascending = (order_type == "asc") item.sort_priority = sort_priority menus = [ ('asc', o_list_asc, 'caret-up', _(u'Sort ASC')), ('desc', o_list_desc, 'caret-down', _(u'Sort DESC')), ] if sorted: row['num_sorted_fields'] = row['num_sorted_fields'] + 1 menus.append((None, o_list_remove, 'times', _(u'Cancel Sort'))) item.btns.append('<a class="toggle" href="%s"><i class="fa fa-%s"></i></a>' % ( self.get_query_string({ORDER_VAR: '.'.join(o_list_toggle)}), 'sort-up' if order_type == "asc" else 'sort-down')) item.menus.extend(['<li%s><a href="%s" class="active"><i class="fa fa-%s"></i> %s</a></li>' % ( (' class="active"' if sorted and order_type == i[ 0] else ''), self.get_query_string({ORDER_VAR: '.'.join(i[1])}), i[2], i[3]) for i in menus]) item.classes.extend(th_classes) return item
def make_to_excel(object_list, fields=None): ''' object_list queryset. fields is a list.eg: fields=['id', 'created', 'creator'] ''' if not object_list: return ''' xlwt设置表格的一些样式 ''' body_style = xlwt.XFStyle() borders = xlwt.Borders() borders.left = 1 borders.right = 1 borders.top = 1 borders.bottom = 1 font = xlwt.Font() font.bold = True pattern = xlwt.Pattern() pattern.pattern = xlwt.Pattern.SOLID_PATTERN pattern.pattern_fore_colour = 22 title_style = xlwt.XFStyle() title_style.borders = borders title_style.font = font title_style.pattern = pattern body_style = xlwt.XFStyle() body_style.borders = borders ''' 开始制作Excel表格 ''' verbose_name = object_list.model._meta.verbose_name wb = xlwt.Workbook(encoding='utf-8') ws = wb.add_sheet('{0}列表'.format(verbose_name)) model = object_list.model fields = fields_for_model(model, fields=fields) # 上面 `fields` 获取某个 model fields 列表. field_names = [] field_verboses = [] for attname, field in fields.items(): if attname not in ['password']: field_names.append(attname) field_verboses.append(label_for_field(attname, model)) for col in range(len(field_verboses)): ws.write(0, col, force_text(field_verboses[col]), title_style) row = 1 for obj in object_list: for index, field_name in enumerate(field_names): field = model._meta.get_field(field_name) value = field.value_from_object(obj) cell_value = display_for_field(value, field, html=False, only_date=False) ws.write(row, index, cell_value, body_style) row += 1 output = BytesIO() wb.save(output) output.seek(0) time = formats.localize( timezone.template_localtime(timezone.datetime.now())) filename = urlquote('{}{}'.format(verbose_name, slugify(time, allow_unicode=True))) # 上面 `filename` 解决导出中文文件名出错的问题 response = HttpResponse(output) # response = StreamingHttpResponse(output) # Stream在这里其实是不起作用了,可以直接HttpResponse response['charset'] = 'utf-8' response['content_type'] = 'application/octet-stream' response['Content-Disposition'] = 'attachment; filename="{}.xls"'.format( filename) return response
def test_label_for_field(self): """ Tests for label_for_field """ self.assertEqual( label_for_field("title", Article), "title" ) self.assertEqual( label_for_field("title2", Article), "another name" ) self.assertEqual( label_for_field("title2", Article, return_attr=True), ("another name", None) ) self.assertEqual( label_for_field("__unicode__", Article), "article" ) self.assertEqual( label_for_field("__str__", Article), str("article") ) self.assertRaises( AttributeError, lambda: label_for_field("unknown", Article) ) def test_callable(obj): return "nothing" self.assertEqual( label_for_field(test_callable, Article), "Test callable" ) self.assertEqual( label_for_field(test_callable, Article, return_attr=True), ("Test callable", test_callable) ) self.assertEqual( label_for_field("test_from_model", Article), "Test from model" ) self.assertEqual( label_for_field("test_from_model", Article, return_attr=True), ("Test from model", Article.test_from_model) ) self.assertEqual( label_for_field("test_from_model_with_override", Article), "not What you Expect" ) self.assertEqual( label_for_field(lambda x: "nothing", Article), "--" ) class MockModelAdmin(object): def test_from_model(self, obj): return "nothing" test_from_model.short_description = "not Really the Model" self.assertEqual( label_for_field("test_from_model", Article, model_admin=MockModelAdmin), "not Really the Model" ) self.assertEqual( label_for_field("test_from_model", Article, model_admin=MockModelAdmin, return_attr=True), ("not Really the Model", MockModelAdmin.test_from_model) )
def test_list_label(self): # See that adding a field to the admin list_display also receives the translated title # This happens by TranslatedFieldDescriptor.short_description self.assertEqual(label_for_field("tr_title", SimpleModel), "Translated Title")
def result_headers(cl): """ Generate the list column headers. """ ordering_field_columns = cl.get_ordering_field_columns() for i, field_name in enumerate(cl.list_display): text, attr = label_for_field(field_name, cl.model, model_admin=cl.model_admin, return_attr=True) if attr: field_name = _coerce_field_name(field_name, i) # Potentially not sortable # if the field is the action checkbox: no sorting and special class if field_name == 'action_checkbox': yield { "text": text, "class_attrib": mark_safe(' class="action-checkbox-column"'), "sortable": False, } continue admin_order_field = getattr(attr, "admin_order_field", None) if not admin_order_field: # Not sortable yield { "text": text, "class_attrib": format_html(' class="column-{}"', field_name), "sortable": False, } continue # OK, it is sortable if we got this far th_classes = ['sortable', 'column-{}'.format(field_name)] order_type = '' new_order_type = 'asc' sort_priority = 0 # Is it currently being sorted on? is_sorted = i in ordering_field_columns if is_sorted: order_type = ordering_field_columns.get(i).lower() sort_priority = list(ordering_field_columns).index(i) + 1 th_classes.append('sorted %sending' % order_type) new_order_type = {'asc': 'desc', 'desc': 'asc'}[order_type] # build new ordering param o_list_primary = [] # URL for making this field the primary sort o_list_remove = [] # URL for removing this field from sort o_list_toggle = [] # URL for toggling order type for this field def make_qs_param(t, n): return ('-' if t == 'desc' else '') + str(n) for j, ot in ordering_field_columns.items(): if j == i: # Same column param = make_qs_param(new_order_type, j) # We want clicking on this header to bring the ordering to the # front o_list_primary.insert(0, param) o_list_toggle.append(param) # o_list_remove - omit else: param = make_qs_param(ot, j) o_list_primary.append(param) o_list_toggle.append(param) o_list_remove.append(param) if i not in ordering_field_columns: o_list_primary.insert(0, make_qs_param(new_order_type, i)) yield { "text": text, "sortable": True, "sorted": is_sorted, "ascending": order_type == "asc", "sort_priority": sort_priority, "url_primary": cl.get_query_string({ORDER_VAR: '.'.join(o_list_primary)}), "url_remove": cl.get_query_string({ORDER_VAR: '.'.join(o_list_remove)}), "url_toggle": cl.get_query_string({ORDER_VAR: '.'.join(o_list_toggle)}), "class_attrib": format_html(' class="{}"', ' '.join(th_classes)) if th_classes else '', }
def test_label_for_field(self): """ Tests for label_for_field """ self.assertEqual( label_for_field("title", Article), "title" ) self.assertEqual( label_for_field("hist", Article), "History" ) self.assertEqual( label_for_field("hist", Article, return_attr=True), ("History", None) ) self.assertEqual( label_for_field("__unicode__", Article), "article" ) self.assertEqual( label_for_field("__str__", Article), str("article") ) with self.assertRaises(AttributeError): label_for_field("unknown", Article) def test_callable(obj): return "nothing" self.assertEqual( label_for_field(test_callable, Article), "Test callable" ) self.assertEqual( label_for_field(test_callable, Article, return_attr=True), ("Test callable", test_callable) ) self.assertEqual( label_for_field("test_from_model", Article), "Test from model" ) self.assertEqual( label_for_field("test_from_model", Article, return_attr=True), ("Test from model", Article.test_from_model) ) self.assertEqual( label_for_field("test_from_model_with_override", Article), "not What you Expect" ) self.assertEqual( label_for_field(lambda x: "nothing", Article), "--" ) class MockModelAdmin(object): def test_from_model(self, obj): return "nothing" test_from_model.short_description = "not Really the Model" self.assertEqual( label_for_field("test_from_model", Article, model_admin=MockModelAdmin), "not Really the Model" ) self.assertEqual( label_for_field("test_from_model", Article, model_admin=MockModelAdmin, return_attr=True), ("not Really the Model", MockModelAdmin.test_from_model) )
def test_list_label(self): # See that adding a field to the admin list_display also receives the translated title # This happens by TranslatedFieldDescriptor.short_description self.assertEqual(label_for_field('tr_title', SimpleModel), "Translated Title")
def result_headers(cl): """ Generates the list column headers. """ for i, field_name in enumerate(cl.list_display): text, attr = label_for_field(field_name, cl.model, model_admin=cl.model_admin, return_attr=True) # OK, it is sortable if we got this far th_classes = ['sortable', 'column-{}'.format(field_name)] order_type = '' new_order_type = 'asc' sort_priority = 0 sorted = False # Is it currently being sorted on? if i in ordering_field_columns: sorted = True order_type = ordering_field_columns.get(i).lower() sort_priority = list(ordering_field_columns).index(i) + 1 th_classes.append('sorted %sending' % order_type) new_order_type = {'asc': 'desc', 'desc': 'asc'}[order_type] # build new ordering param o_list_primary = [] # URL for making this field the primary sort o_list_remove = [] # URL for removing this field from sort o_list_toggle = [] # URL for toggling order type for this field def make_qs_param(t, n): return ('-' if t == 'desc' else '') + str(n) for j, ot in ordering_field_columns.items(): if j == i: # Same column param = make_qs_param(new_order_type, j) # We want clicking on this header to bring the ordering to the # front o_list_primary.insert(0, param) o_list_toggle.append(param) # o_list_remove - omit else: param = make_qs_param(ot, j) o_list_primary.append(param) o_list_toggle.append(param) o_list_remove.append(param) if i not in ordering_field_columns: o_list_primary.insert(0, make_qs_param(new_order_type, i)) yield { "text": text, "sortable": True, "sorted": sorted, "ascending": order_type == "asc", "sort_priority": sort_priority, "url_primary": cl.get_query_string({ORDER_VAR: '.'.join(o_list_primary)}), "url_remove": cl.get_query_string({ORDER_VAR: '.'.join(o_list_remove)}), "url_toggle": cl.get_query_string({ORDER_VAR: '.'.join(o_list_toggle)}), "class_attrib": format_html(' class="{}"', ' '.join(th_classes)) if th_classes else '', }
def make_thead(self): fields = self.get_list_fields ordering = [ o for o in self.get_ordering() if o.rpartition('-')[2] in fields ] switch = {'asc': '', 'desc': '-'} checked_fields = self.user_list_display or self.model_list_display if not checked_fields: checked_fields = fields can_sorted_fields = [f.name for f in self.opts.concrete_fields] for _, field_name in enumerate(fields): checked = field_name in checked_fields sortable = field_name in can_sorted_fields if field_name == 'field-first': yield { "text": mark_safe('''<input id="action-toggle"''' '''name="mode" value="page" type="checkbox">'''), "field": field_name, "class_attrib": mark_safe(' class="no-print field-first"'), "sortable": sortable, } continue if field_name == 'field-second': yield { "text": "#", "field": field_name, "class_attrib": mark_safe(' class="field-second"'), "sortable": sortable, } if field_name == 'field-last': yield { "text": "操作", "field": field_name, "class_attrib": mark_safe(' class="no-print field-last"'), "sortable": sortable, } continue try: text = label_for_field(name=field_name, model=self.model) except Exception: continue if field_name not in can_sorted_fields: # Not sortable yield { "text": text, "checked": checked, "field": field_name, "class_attrib": format_html(' class="col-{}"', field_name), "sortable": sortable, } continue # OK, it is sortable if we got this far is_sorted = field_name in ordering or '-' + field_name in ordering sorted_key = 'asc' if is_sorted and field_name in ordering else 'desc' sorted_value = switch.get(sorted_key) new_ordering = [ o for o in ordering if o != str(sorted_value + field_name) ] remove_link = '.'.join(i for i in new_ordering) new_sorted_key = 'desc' if is_sorted and field_name in ordering else 'asc' new_sorted_value = switch.get(new_sorted_key) new_ordering.insert(0, str(new_sorted_value + field_name)) toggle_link = '.'.join(i for i in new_ordering) toggle_url = self.get_query_string({'order': toggle_link}) remove_url = self.get_query_string({'order': remove_link}) th_classes = ['sortable', 'col-{}'.format(field_name)] yield { "text": text, "checked": checked, "field": field_name, "sortable": sortable, "is_sorted": is_sorted, "sorted_key": sorted_key, "remove_link": "{}".format(remove_url), "toggle_link": "{}".format(toggle_url), "class_attrib": format_html('style="{}" class="{}"', 'min-width: 64px;' if is_sorted else '', ' '.join(th_classes)) if th_classes else '', }