Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/polymorphic/admin/helpers.py: 40%
47 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1"""
2Rendering utils for admin forms;
4This makes sure that admin fieldsets/layout settings are exported to the template.
5"""
6import json
8from django.contrib.admin.helpers import AdminField, InlineAdminForm, InlineAdminFormSet
9from django.utils.encoding import force_str
10from django.utils.text import capfirst
11from django.utils.translation import gettext
13from polymorphic.formsets import BasePolymorphicModelFormSet
16class PolymorphicInlineAdminForm(InlineAdminForm):
17 """
18 Expose the admin configuration for a form
19 """
21 def polymorphic_ctype_field(self):
22 return AdminField(self.form, "polymorphic_ctype", False)
24 @property
25 def is_empty(self):
26 return "__prefix__" in self.form.prefix
29class PolymorphicInlineAdminFormSet(InlineAdminFormSet):
30 """
31 Internally used class to expose the formset in the template.
32 """
34 def __init__(self, *args, **kwargs):
35 # Assigned later via PolymorphicInlineSupportMixin later.
36 self.request = kwargs.pop("request", None)
37 self.obj = kwargs.pop("obj", None)
38 super().__init__(*args, **kwargs)
40 def __iter__(self):
41 """
42 Output all forms using the proper subtype settings.
43 """
44 for form, original in zip(self.formset.initial_forms, self.formset.get_queryset()):
45 # Output the form
46 model = original.get_real_instance_class()
47 child_inline = self.opts.get_child_inline_instance(model)
48 view_on_site_url = self.opts.get_view_on_site_url(original)
50 yield PolymorphicInlineAdminForm(
51 formset=self.formset,
52 form=form,
53 fieldsets=self.get_child_fieldsets(child_inline),
54 prepopulated_fields=self.get_child_prepopulated_fields(child_inline),
55 original=original,
56 readonly_fields=self.get_child_readonly_fields(child_inline),
57 model_admin=child_inline,
58 view_on_site_url=view_on_site_url,
59 )
61 # Extra rows, and empty prefixed forms.
62 for form in self.formset.extra_forms + self.formset.empty_forms:
63 model = form._meta.model
64 child_inline = self.opts.get_child_inline_instance(model)
65 yield PolymorphicInlineAdminForm(
66 formset=self.formset,
67 form=form,
68 fieldsets=self.get_child_fieldsets(child_inline),
69 prepopulated_fields=self.get_child_prepopulated_fields(child_inline),
70 original=None,
71 readonly_fields=self.get_child_readonly_fields(child_inline),
72 model_admin=child_inline,
73 )
75 def get_child_fieldsets(self, child_inline):
76 return list(child_inline.get_fieldsets(self.request, self.obj) or ())
78 def get_child_readonly_fields(self, child_inline):
79 return list(child_inline.get_readonly_fields(self.request, self.obj))
81 def get_child_prepopulated_fields(self, child_inline):
82 fields = self.prepopulated_fields.copy()
83 fields.update(child_inline.get_prepopulated_fields(self.request, self.obj))
84 return fields
86 def inline_formset_data(self):
87 """
88 A JavaScript data structure for the JavaScript code
89 This overrides the default Django version to add the ``childTypes`` data.
90 """
91 verbose_name = self.opts.verbose_name
92 return json.dumps(
93 {
94 "name": "#%s" % self.formset.prefix,
95 "options": {
96 "prefix": self.formset.prefix,
97 "addText": gettext("Add another %(verbose_name)s")
98 % {"verbose_name": capfirst(verbose_name)},
99 "childTypes": [
100 {
101 "type": model._meta.model_name,
102 "name": force_str(model._meta.verbose_name),
103 }
104 for model in self.formset.child_forms.keys()
105 ],
106 "deleteText": gettext("Remove"),
107 },
108 }
109 )
112class PolymorphicInlineSupportMixin:
113 """
114 A Mixin to add to the regular admin, so it can work with our polymorphic inlines.
116 This mixin needs to be included in the admin that hosts the ``inlines``.
117 It makes sure the generated admin forms have different fieldsets/fields
118 depending on the polymorphic type of the form instance.
120 This is achieved by overwriting :func:`get_inline_formsets` to return
121 an :class:`PolymorphicInlineAdminFormSet` instead of a standard Django
122 :class:`~django.contrib.admin.helpers.InlineAdminFormSet` for the polymorphic formsets.
123 """
125 def get_inline_formsets(self, request, formsets, inline_instances, obj=None, *args, **kwargs):
126 """
127 Overwritten version to produce the proper admin wrapping for the
128 polymorphic inline formset. This fixes the media and form appearance
129 of the inline polymorphic models.
130 """
131 inline_admin_formsets = super().get_inline_formsets(
132 request, formsets, inline_instances, obj=obj
133 )
135 for admin_formset in inline_admin_formsets:
136 if isinstance(admin_formset.formset, BasePolymorphicModelFormSet):
137 # This is a polymorphic formset, which belongs to our inline.
138 # Downcast the admin wrapper that generates the form fields.
139 admin_formset.__class__ = PolymorphicInlineAdminFormSet
140 admin_formset.request = request
141 admin_formset.obj = obj
142 return inline_admin_formsets