|
1 | 1 | from __future__ import unicode_literals
|
2 | 2 |
|
3 | 3 | from collections import OrderedDict
|
| 4 | +from functools import partial, update_wrapper |
4 | 5 |
|
5 |
| -from django.contrib.admin.options import IS_POPUP_VAR, TO_FIELD_VAR |
6 |
| -from django.contrib.admin.utils import unquote, quote |
7 |
| -from django.forms.models import _get_foreign_key |
8 |
| -from django.db import transaction |
9 | 6 | from django.conf.urls import url, include
|
| 7 | +from django.contrib.admin.options import IS_POPUP_VAR, TO_FIELD_VAR |
| 8 | +from django.contrib.admin.utils import unquote, quote, flatten_fieldsets |
10 | 9 | from django.contrib import admin
|
11 | 10 | from django.contrib import messages
|
12 | 11 | from django.contrib.admin.views.main import ChangeList
|
13 | 12 | from django.contrib.admin.actions import delete_selected
|
| 13 | +from django.core.exceptions import FieldError |
| 14 | +from django.db import transaction |
| 15 | +from django.forms.models import _get_foreign_key, modelform_defines_fields, modelform_factory, ALL_FIELDS |
14 | 16 | from django.http import HttpResponseRedirect
|
15 | 17 | from django.shortcuts import get_object_or_404
|
16 | 18 | from django.template.response import SimpleTemplateResponse
|
|
22 | 24 | from django.utils.six.moves.urllib.parse import parse_qsl, urlparse, urlunparse
|
23 | 25 | from django.utils.translation import ugettext as _
|
24 | 26 | from django.views.decorators.csrf import csrf_protect
|
25 |
| -from functools import update_wrapper |
26 | 27 |
|
27 | 28 | try:
|
28 | 29 | from django.urls import Resolver404, get_script_prefix, resolve, reverse
|
@@ -201,22 +202,52 @@ def get_queryset(self, request):
|
201 | 202 | return super(SubAdminMixin, self).get_queryset(request).filter(**lookup_kwargs)
|
202 | 203 |
|
203 | 204 | def get_form(self, request, obj=None, **kwargs):
|
204 |
| - if not MODELADMIN_GET_EXCLUDE_SUPPORT: |
205 |
| - # Workaround for Django < 1.11 not supporting get_exclude in ModelAdmin |
206 |
| - exclude = self.exclude |
207 |
| - self.exclude = list(exclude or []) + self.get_exclude(request, obj) |
208 |
| - form = super(SubAdminMixin, self).get_form(request, obj, **kwargs) |
209 |
| - self.exclude = exclude |
210 |
| - return form |
| 205 | + if MODELADMIN_GET_EXCLUDE_SUPPORT: |
| 206 | + return super(SubAdminMixin, self).get_form(request, obj, **kwargs) |
| 207 | + |
| 208 | + if 'fields' in kwargs: |
| 209 | + fields = kwargs.pop('fields') |
| 210 | + else: |
| 211 | + fields = flatten_fieldsets(self.get_fieldsets(request, obj)) |
| 212 | + excluded = self.get_exclude(request, obj) |
| 213 | + exclude = [] if excluded is None else list(excluded) |
| 214 | + readonly_fields = self.get_readonly_fields(request, obj) |
| 215 | + exclude.extend(readonly_fields) |
| 216 | + |
| 217 | + if excluded is None and hasattr(self.form, '_meta') and self.form._meta.exclude: |
| 218 | + exclude.extend(self.form._meta.exclude) |
| 219 | + |
| 220 | + exclude = exclude or None |
| 221 | + |
| 222 | + new_attrs = OrderedDict( |
| 223 | + (f, None) for f in readonly_fields |
| 224 | + if f in self.form.declared_fields |
| 225 | + ) |
211 | 226 |
|
212 |
| - return super(SubAdminMixin, self).get_form(request, obj, **kwargs) |
| 227 | + form = type(self.form.__name__, (self.form,), new_attrs) |
| 228 | + |
| 229 | + defaults = { |
| 230 | + "form": form, |
| 231 | + "fields": fields, |
| 232 | + "exclude": exclude, |
| 233 | + "formfield_callback": partial(self.formfield_for_dbfield, request=request), |
| 234 | + } |
| 235 | + defaults.update(kwargs) |
| 236 | + |
| 237 | + if defaults['fields'] is None and not modelform_defines_fields(defaults['form']): |
| 238 | + defaults['fields'] = ALL_FIELDS |
213 | 239 |
|
214 |
| - def get_exclude(self, request, obj=None): |
215 | 240 | try:
|
216 |
| - exclude = super(SubAdminMixin, self).get_exclude(request, obj) or [] |
217 |
| - except AttributeError: |
218 |
| - exclude = [] |
| 241 | + return modelform_factory(self.model, **defaults) |
| 242 | + except FieldError as e: |
| 243 | + raise FieldError('%s. Check fields/fieldsets/exclude attributes of class %s.' % (e, self.__class__.__name__)) |
219 | 244 |
|
| 245 | + def get_exclude(self, request, obj=None): |
| 246 | + if MODELADMIN_GET_EXCLUDE_SUPPORT: |
| 247 | + excluded = super(SubAdminMixin, self).get_exclude(request, obj) |
| 248 | + else: |
| 249 | + excluded = self.exclude |
| 250 | + exclude = [] if excluded is None else list(excluded) |
220 | 251 | exclude.extend(request.subadmin.related_instances.keys())
|
221 | 252 | return list(set(exclude))
|
222 | 253 |
|
|
0 commit comments