Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/mptt/templatetags/mptt_admin.py: 18%

111 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1import datetime 

2import warnings 

3 

4from django.conf import settings 

5from django.contrib.admin.templatetags.admin_list import ( 

6 result_headers, 

7 result_hidden_fields, 

8) 

9from django.contrib.admin.templatetags.admin_urls import add_preserved_filters 

10from django.contrib.admin.utils import ( 

11 display_for_field, 

12 display_for_value, 

13 lookup_field, 

14) 

15from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist 

16from django.db import models 

17from django.template import Library 

18from django.urls import NoReverseMatch 

19 

20 

21try: 

22 from django.utils.deprecation import RemovedInDjango20Warning 

23except ImportError: 

24 RemovedInDjango20Warning = RuntimeWarning 

25from django.contrib.admin.templatetags.admin_list import _coerce_field_name 

26from django.utils.encoding import force_str 

27from django.utils.html import format_html 

28from django.utils.safestring import mark_safe 

29from django.utils.translation import get_language_bidi 

30 

31 

32register = Library() 

33 

34 

35MPTT_ADMIN_LEVEL_INDENT = getattr(settings, "MPTT_ADMIN_LEVEL_INDENT", 10) 

36IS_GRAPPELLI_INSTALLED = True if "grappelli" in settings.INSTALLED_APPS else False 

37 

38 

39### 

40# Ripped from contrib.admin's (1.10) items_for_result tag. 

41# The only difference is we're indenting nodes according to their level. 

42def mptt_items_for_result(cl, result, form): 

43 """ 

44 Generates the actual list of data. 

45 """ 

46 

47 def link_in_col(is_first, field_name, cl): 

48 if cl.list_display_links is None: 

49 return False 

50 if is_first and not cl.list_display_links: 

51 return True 

52 return field_name in cl.list_display_links 

53 

54 first = True 

55 pk = cl.lookup_opts.pk.attname 

56 

57 # #### MPTT ADDITION START 

58 # figure out which field to indent 

59 mptt_indent_field = getattr(cl.model_admin, "mptt_indent_field", None) 

60 if not mptt_indent_field: 

61 for field_name in cl.list_display: 

62 try: 

63 f = cl.lookup_opts.get_field(field_name) 

64 except FieldDoesNotExist: 

65 if mptt_indent_field is None and field_name != "action_checkbox": 

66 mptt_indent_field = field_name 

67 else: 

68 # first model field, use this one 

69 mptt_indent_field = field_name 

70 break 

71 

72 # figure out how much to indent 

73 mptt_level_indent = getattr( 

74 cl.model_admin, "mptt_level_indent", MPTT_ADMIN_LEVEL_INDENT 

75 ) 

76 # #### MPTT ADDITION END 

77 

78 for field_index, field_name in enumerate(cl.list_display): 

79 # #### MPTT SUBSTITUTION START 

80 empty_value_display = cl.model_admin.get_empty_value_display() 

81 # #### MPTT SUBSTITUTION END 

82 row_classes = ["field-%s" % _coerce_field_name(field_name, field_index)] 

83 try: 

84 f, attr, value = lookup_field(field_name, result, cl.model_admin) 

85 except ObjectDoesNotExist: 

86 result_repr = empty_value_display 

87 else: 

88 empty_value_display = getattr( 

89 attr, "empty_value_display", empty_value_display 

90 ) 

91 if f is None or f.auto_created: 

92 if field_name == "action_checkbox": 

93 row_classes = ["action-checkbox"] 

94 allow_tags = getattr(attr, "allow_tags", False) 

95 boolean = getattr(attr, "boolean", False) 

96 # #### MPTT SUBSTITUTION START 

97 result_repr = display_for_value(value, empty_value_display, boolean) 

98 # #### MPTT SUBSTITUTION END 

99 if allow_tags: 

100 warnings.warn( 

101 "Deprecated allow_tags attribute used on field {}. " 

102 "Use django.utils.safestring.format_html(), " 

103 "format_html_join(), or mark_safe() instead.".format( 

104 field_name 

105 ), 

106 RemovedInDjango20Warning, 

107 ) 

108 result_repr = mark_safe(result_repr) 

109 if isinstance(value, (datetime.date, datetime.time)): 

110 row_classes.append("nowrap") 

111 else: 

112 # #### MPTT SUBSTITUTION START 

113 is_many_to_one = isinstance(f.remote_field, models.ManyToOneRel) 

114 if is_many_to_one: 

115 # #### MPTT SUBSTITUTION END 

116 field_val = getattr(result, f.name) 

117 if field_val is None: 

118 result_repr = empty_value_display 

119 else: 

120 result_repr = field_val 

121 else: 

122 # #### MPTT SUBSTITUTION START 

123 result_repr = display_for_field(value, f, empty_value_display) 

124 # #### MPTT SUBSTITUTION END 

125 if isinstance( 

126 f, (models.DateField, models.TimeField, models.ForeignKey) 

127 ): 

128 row_classes.append("nowrap") 

129 if force_str(result_repr) == "": 

130 result_repr = mark_safe(" ") 

131 row_class = mark_safe(' class="%s"' % " ".join(row_classes)) 

132 

133 # #### MPTT ADDITION START 

134 if field_name == mptt_indent_field: 

135 level = getattr(result, result._mptt_meta.level_attr) 

136 padding_attr = mark_safe( 

137 ' style="padding-%s:%spx"' 

138 % ( 

139 "right" if get_language_bidi() else "left", 

140 8 + mptt_level_indent * level, 

141 ) 

142 ) 

143 else: 

144 padding_attr = "" 

145 # #### MPTT ADDITION END 

146 

147 # If list_display_links not defined, add the link tag to the first field 

148 if link_in_col(first, field_name, cl): 

149 table_tag = "th" if first else "td" 

150 first = False 

151 

152 # Display link to the result's change_view if the url exists, else 

153 # display just the result's representation. 

154 try: 

155 url = cl.url_for_result(result) 

156 except NoReverseMatch: 

157 link_or_text = result_repr 

158 else: 

159 url = add_preserved_filters( 

160 {"preserved_filters": cl.preserved_filters, "opts": cl.opts}, 

161 url, 

162 ) 

163 # Convert the pk to something that can be used in Javascript. 

164 # Problem cases are long ints (23L) and non-ASCII strings. 

165 if cl.to_field: 

166 attr = str(cl.to_field) 

167 else: 

168 attr = pk 

169 value = result.serializable_value(attr) 

170 if cl.is_popup: 

171 opener = format_html(' data-popup-opener="{}"', value) 

172 else: 

173 opener = "" 

174 link_or_text = format_html( 

175 '<a href="{}"{}>{}</a>', url, opener, result_repr 

176 ) 

177 

178 # #### MPTT SUBSTITUTION START 

179 yield format_html( 

180 "<{}{}{}>{}</{}>", 

181 table_tag, 

182 row_class, 

183 padding_attr, 

184 link_or_text, 

185 table_tag, 

186 ) 

187 # #### MPTT SUBSTITUTION END 

188 else: 

189 # By default the fields come from ModelAdmin.list_editable, but if we pull 

190 # the fields out of the form instead of list_editable custom admins 

191 # can provide fields on a per request basis 

192 if ( 

193 form 

194 and field_name in form.fields 

195 and not ( 

196 field_name == cl.model._meta.pk.name 

197 and form[cl.model._meta.pk.name].is_hidden 

198 ) 

199 ): 

200 bf = form[field_name] 

201 result_repr = mark_safe(force_str(bf.errors) + force_str(bf)) 

202 # #### MPTT SUBSTITUTION START 

203 yield format_html("<td{}{}>{}</td>", row_class, padding_attr, result_repr) 

204 # #### MPTT SUBSTITUTION END 

205 if form and not form[cl.model._meta.pk.name].is_hidden: 

206 yield format_html("<td>{}</td>", force_str(form[cl.model._meta.pk.name])) 

207 

208 

209def mptt_results(cl): 

210 if cl.formset: 

211 for res, form in zip(cl.result_list, cl.formset.forms): 

212 yield list(mptt_items_for_result(cl, res, form)) 

213 else: 

214 for res in cl.result_list: 

215 yield list(mptt_items_for_result(cl, res, None)) 

216 

217 

218def mptt_result_list(cl): 

219 """ 

220 Displays the headers and data list together 

221 """ 

222 return { 

223 "cl": cl, 

224 "result_hidden_fields": list(result_hidden_fields(cl)), 

225 "result_headers": list(result_headers(cl)), 

226 "results": list(mptt_results(cl)), 

227 } 

228 

229 

230# custom template is merely so we can strip out sortable-ness from the column headers 

231# Based on admin/change_list_results.html (1.3.1) 

232if IS_GRAPPELLI_INSTALLED: 232 ↛ 233line 232 didn't jump to line 233, because the condition on line 232 was never true

233 mptt_result_list = register.inclusion_tag( 

234 "admin/grappelli_mptt_change_list_results.html" 

235 )(mptt_result_list) 

236else: 

237 mptt_result_list = register.inclusion_tag("admin/mptt_change_list_results.html")( 

238 mptt_result_list 

239 )