Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

helpers.py 5.5KB

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