def _check_fk_name(self, cls, parent_model): try: _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name) except ValueError as e: return [checks.Error(e.args[0], hint=None, obj=cls, id="admin.E202")] else: return []
def _check_relation(self, obj, parent_model): try: _get_foreign_key(parent_model, obj.model, fk_name=obj.fk_name) except ValueError as e: return [checks.Error(e.args[0], hint=None, obj=obj.__class__, id='admin.E202')] else: return []
def _check_relation(self, obj, parent_model): try: _get_foreign_key(parent_model, obj.model, fk_name=obj.fk_name) except ValueError as e: return [checks.Error(e.args[0], obj=obj.__class__, id='admin.E202')] else: return []
def _check_relation(self, cls, parent_model): try: _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name) except ValueError as e: return [checks.Error(e.args[0], hint=None, obj=cls, id='admin.E202')] else: return []
def _check_fk_name(self, cls, parent_model): try: _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name) except ValueError as e: # Check if generic, if not add error. is_generic_inline_admin = any( isinstance(vf, GenericForeignKey) for vf in parent_model._meta.virtual_fields) if is_generic_inline_admin: return [] return [checks.Error(e.args[0], hint=None, obj=cls, id='admin.E202')] else: return []
def validate_inline(cls, parent, parent_model): # model is already verified to exist and be a Model if cls.fk_name: # default value is None f = get_field(cls, cls.model, cls.model._meta, 'fk_name', cls.fk_name) if not isinstance(f, models.ForeignKey): raise ImproperlyConfigured("'%s.fk_name is not an instance of " "models.ForeignKey." % cls.__name__) fk = _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name, can_fail=True) # extra = 3 if not isinstance(getattr(cls, 'extra'), int): raise ImproperlyConfigured("'%s.extra' should be a integer." % cls.__name__) # max_num = None max_num = getattr(cls, 'max_num', None) if max_num is not None and not isinstance(max_num, int): raise ImproperlyConfigured("'%s.max_num' should be an integer or None (default)." % cls.__name__) # formset if hasattr(cls, 'formset') and not issubclass(cls.formset, BaseModelFormSet): raise ImproperlyConfigured("'%s.formset' does not inherit from " "BaseModelFormSet." % cls.__name__) # exclude if hasattr(cls, 'exclude') and cls.exclude: if fk and fk.name in cls.exclude: raise ImproperlyConfigured("%s cannot exclude the field " "'%s' - this is the foreign key to the parent model " "%s." % (cls.__name__, fk.name, parent_model.__name__))
def _check_exclude_of_parent_model(self, cls, parent_model): # Do not perform more specific checks if the base checks result in an # error. errors = super(InlineModelAdminChecks, self)._check_exclude(cls, parent_model) if errors: return [] # Skip if `fk_name` is invalid. if self._check_relation(cls, parent_model): return [] if cls.exclude is None: return [] fk = _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name) if fk.name in cls.exclude: return [ checks.Error( "Cannot exclude the field '%s', because it is the foreign key " "to the parent model '%s.%s'." % (fk.name, parent_model._meta.app_label, parent_model._meta.object_name), hint=None, obj=cls, id='admin.E201', ) ] else: return []
def __init__(self, **kw): #~ self.groups = [] # for later #~ self.totals = [] # for later if self.label is None: self.label = self.__class__.__name__ if self.name is None: self.name = self.__class__.__name__.lower() #~ if self.title is None: #~ self.title = self.build_title() #~ if self.queryset is None: #~ self.queryset = self.get_queryset() if self.model is None: self.model = self.queryset.model if self.form_class is None: self.form_class = modelform_factory(self.model) if self.row_layout_class is None: self.row_layout = layouts.RowLayout(self.model, self.columnNames) else: assert self.columnNames is None self.row_layout = self.row_layout_class(self.model) if self.master: self.fk = _get_foreign_key(self.master, self.model, self.fk_name) self._page_layouts = [ layout(self.model) for layout in self.page_layouts ] for k, v in kw.items(): if not hasattr(self, k): print "[Warning] Ignoring attribute %s" % k setattr(self, k, v)
def _check_exclude_of_parent_model(self, obj, parent_model): # Do not perform more specific checks if the base checks result in an # error. errors = super(InlineModelAdminChecks, self)._check_exclude(obj) if errors: return [] # Skip if `fk_name` is invalid. if self._check_relation(obj, parent_model): return [] if obj.exclude is None: return [] fk = _get_foreign_key(parent_model, obj.model, fk_name=obj.fk_name) if fk.name in obj.exclude: return [ checks.Error( "Cannot exclude the field '%s', because it is the foreign key " "to the parent model '%s.%s'." % ( fk.name, parent_model._meta.app_label, parent_model._meta.object_name ), hint=None, obj=obj.__class__, id='admin.E201', ) ] else: return []
def __init__(self,**kw): #~ self.groups = [] # for later #~ self.totals = [] # for later if self.label is None: self.label = self.__class__.__name__ if self.name is None: self.name = self.__class__.__name__.lower() #~ if self.title is None: #~ self.title = self.build_title() #~ if self.queryset is None: #~ self.queryset = self.get_queryset() if self.model is None: self.model = self.queryset.model if self.form_class is None: self.form_class = modelform_factory(self.model) if self.row_layout_class is None: self.row_layout = layouts.RowLayout(self.model, self.columnNames) else: assert self.columnNames is None self.row_layout = self.row_layout_class(self.model) if self.master: self.fk = _get_foreign_key(self.master, self.model,self.fk_name) self._page_layouts = [ layout(self.model) for layout in self.page_layouts] for k,v in kw.items(): if not hasattr(self,k): print "[Warning] Ignoring attribute %s" % k setattr(self,k,v)
def _get_list_filter(self): list_filter = super(InlineTableView, self)._get_list_filter() fk_name = _get_foreign_key(self.parent_instance.__class__, self.model, fk_name=self.fk_name).name list_filter['filter'] = filter = list_filter.get('filter', {}) if 'filter' in list_filter: filter[fk_name] = self.parent_instance.pk return list_filter
def get_formsets(self, request, obj=None): initial = {} model = self.model opts = model._meta data = getattr(request, request.method).items() # If an object is provided we collect data if obj is not None: initial.update(model_to_dict(obj)) # Make sure to collect parent model data # and provide it to fieldsets in the form of # parent__field from request if its provided. # This data should be more "up-to-date". for k, v in data: if v: try: f = opts.get_field(k) except models.FieldDoesNotExist: continue if isinstance(f, models.ManyToManyField): initial[k] = v.split(",") else: initial[k] = v for formset, inline in zip(super(cls, self).get_formsets(request, obj), self.inline_instances): fk = _get_foreign_key(self.model, inline.model, fk_name=inline.fk_name).name fk_initial = dict(('%s__%s' % (fk, k),v) for k, v in initial.iteritems()) # If we must provide additional data # we must wrap the formset in a subclass # because passing 'initial' key argument is intercepted # and not provided to subclasses by BaseInlineFormSet.__init__ if len(initial): formset = dynamic_formset_factory(formset, fk_initial) yield formset
def _check_exclude_of_parent_model(self, cls, parent_model): # Do not perform more specific checks if the base checks result in an # error. errors = super(InlineModelAdminChecks, self)._check_exclude(cls, parent_model) if errors: return [] # Skip if `fk_name` is invalid. if self._check_fk_name(cls, parent_model): return [] if cls.exclude is None: return [] fk = _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name) if fk.name in cls.exclude: return [ checks.Error( 'Cannot exclude the field "%s", because it is the foreign key ' "to the parent model %s.%s." % (fk.name, parent_model._meta.app_label, parent_model._meta.object_name), hint=None, obj=cls, id="admin.E201", ) ] else: return []
def translatable_inlineformset_factory(language, parent_model, model, form=TranslatableModelForm, formset=BaseInlineFormSet, fk_name=None, fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None): """ Returns an ``InlineFormSet`` for the given kwargs. You must provide ``fk_name`` if ``model`` has more than one ``ForeignKey`` to ``parent_model``. """ from django.forms.models import _get_foreign_key fk = _get_foreign_key(parent_model, model, fk_name=fk_name) # enforce a max_num=1 when the foreign key to the parent model is unique. if fk.unique: max_num = 1 kwargs = { 'form': form, 'formfield_callback': formfield_callback, 'formset': formset, 'extra': extra, 'can_delete': can_delete, 'can_order': can_order, 'fields': fields, 'exclude': exclude, 'max_num': max_num, } FormSet = translatable_modelformset_factory(language, model, **kwargs) FormSet.fk = fk return FormSet
def get_form_exclude(self, request, obj=None): exclude = super(ViaRestModelISCore, self).get_form_exclude(request, obj) if obj: fk = _get_foreign_key(self.via_model, self.model, fk_name=self.fk_name).name exclude = list(exclude) exclude.append(fk) return exclude
def _check_exclude_of_parent_model(self, obj, parent_model): # Do not perform more specific checks if the base checks result in an # error. errors = super()._check_exclude(obj) if errors: return [] # Skip if `fk_name` is invalid. if self._check_relation(obj, parent_model): return [] if obj.exclude is None: return [] fk = _get_foreign_key(parent_model, obj.model, fk_name=obj.fk_name) if fk.name in obj.exclude: return [ checks.Error( "Cannot exclude the field '%s', because it is the foreign key " "to the parent model '%s.%s'." % (fk.name, parent_model._meta.app_label, parent_model._meta.object_name), obj=obj.__class__, id='admin.E201', ) ] else: return []
def translatable_inlineformset_factory(language, parent_model, model, form=TranslatableModelForm, formset=BaseInlineFormSet, fk_name=None, fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, **kwargs): from django.forms.models import _get_foreign_key fk = _get_foreign_key(parent_model, model, fk_name=fk_name) if fk.unique: #pragma: no cover (internal Django behavior) max_num = 1 FormSet = translatable_modelformset_factory( language, model, form=form, formfield_callback=formfield_callback, formset=formset, extra=extra, can_delete=can_delete, can_order=can_order, fields=fields, exclude=exclude, max_num=max_num, **kwargs) FormSet.fk = fk return FormSet
def childformset_factory(parent_model, model, form=ModelForm, formset=BaseChildFormSet, fk_name=None, fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, validate_max=False, formfield_callback=None, widgets=None, min_num=None, validate_min=False): fk = _get_foreign_key(parent_model, model, fk_name=fk_name) # enforce a max_num=1 when the foreign key to the parent model is unique. if fk.unique: max_num = 1 validate_max = True if exclude is None: exclude = [] exclude += [fk.name] kwargs = { 'form': form, 'formfield_callback': formfield_callback, 'formset': formset, 'extra': extra, 'can_delete': can_delete, # if the model supplies a sort_order_field, enable ordering regardless of # the current setting of can_order 'can_order': (can_order or hasattr(model, 'sort_order_field')), 'fields': fields, 'exclude': exclude, 'max_num': max_num, 'validate_max': validate_max, 'widgets': widgets, 'min_num': min_num, 'validate_min': validate_min, } FormSet = transientmodelformset_factory(model, **kwargs) FormSet.fk = fk return FormSet
def check_inline(self, cls, parent_model): " Validate inline class's fk field is not excluded. " fk = _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name, can_fail=True) if hasattr(cls, 'exclude') and cls.exclude: if fk and fk.name in cls.exclude: raise ImproperlyConfigured("%s cannot exclude the field " "'%s' - this is the foreign key to the parent model " "%s.%s." % (cls.__name__, fk.name, parent_model._meta.app_label, parent_model.__name__))
def get_formset(self, request, obj=None): setattr(self.form, '_magic_user', request.user) # magic variable assigned to form setattr(self, '_magic_user', request.user) # magic variable from django.forms.models import _get_foreign_key setattr(self, '_magic_instance', obj) setattr(self, '_magic_fk', _get_foreign_key(self.parent_model, self.model, fk_name=self.fk_name)) self.user = request.user return super(NewmanInlineModelAdmin, self).get_formset(request, obj)
def multiinlineformset_factory(parent_model, model, multiform=MultiForm, app_data_field='app_data', name=None, form_opts={}, formset=BaseInlineFormSet, fk_name=None, **kwargs): fk = _get_foreign_key(parent_model, model, fk_name=fk_name) if fk.unique: kwargs['max_num'] = 1 FormSet = multiformset_factory(model, multiform, app_data_field, name, form_opts, formset=formset, **kwargs) FormSet.fk = fk return FormSet
def post_register(self): from django.db.models.fields.related import RelatedObject from django.forms.models import _get_foreign_key self.fk = _get_foreign_key(self._parent.resource_adaptor, self.model, self.fk_name) if self.rel_name is None: #TODO invert this self.rel_name = RelatedObject(self.fk.rel.to, self.model, self.fk).get_accessor_name() super(InlineModelResource, self).post_register()
def __init__(self, parent_model, parent_admin): self.parent_model = parent_model self.parent_admin = parent_admin if self.fk_name is None: self.fk_name = _get_foreign_key(parent_model, self.model).name super(NestedAdminInitMixin, self).__init__(self.model, parent_admin.admin_site)
def __init__(self, parent_model, parent_admin): self.parent_model = parent_model self.parent_admin = parent_admin if self.fk_name is None: self.fk_name = _get_foreign_key(parent_model, self.model).name super().__init__(self.model, parent_admin.admin_site) self.subadmin_instances = self.get_subadmin_instances()
def validate_compose(cls, parent, parent_model): # model is already verified to exist and be a Model if cls.fk_name: # default value is None f = get_field(cls, cls.model, cls.model._meta, 'fk_name', cls.fk_name) if not isinstance(f, models.ForeignKey): raise ImproperlyConfigured("'%s.fk_name is not an instance of " "models.ForeignKey." % cls.__name__) fk = _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name, can_fail=True)
def get_form_exclude(self, request, obj=None): exclude = super(ViaRESTModelISCore, self).get_form_exclude(request, obj) if obj: fk = _get_foreign_key(self.via_model, self.model, fk_name=self.fk_name).name exclude = list(exclude) exclude.append(fk) return exclude
def _get_all_admin_fields(request): request.data_browser = {"calculated_fields": set(), "fields": set()} def from_fieldsets(admin, all_): auth_user_compat = settings.DATA_BROWSER_AUTH_USER_COMPAT if auth_user_compat and isinstance(admin, UserAdmin): obj = admin.model() # get the change fieldsets, not the add ones else: obj = None for f in flatten_fieldsets(admin.get_fieldsets(request, obj)): # skip calculated fields on inlines if not isinstance(admin, InlineModelAdmin) or hasattr( admin.model, f): yield f def visible(model_admin, request): if model_admin.has_change_permission(request): return True if hasattr(model_admin, "has_view_permission"): return model_admin.has_view_permission(request) else: return False # pragma: no cover Django < 2.1 all_admin_fields = defaultdict(set) model_admins = {} for model, model_admin in site._registry.items(): model_admins[model] = model_admin if visible(model_admin, request): all_admin_fields[model].update(from_fieldsets(model_admin, True)) all_admin_fields[model].update( model_admin.get_list_display(request)) all_admin_fields[model].add(_OPEN_IN_ADMIN) # check the inlines, these are already filtered for access for inline in model_admin.get_inline_instances(request): try: fk_field = _get_foreign_key(model, inline.model, inline.fk_name) except Exception: pass # ignore things like GenericInlineModelAdmin else: if inline.model not in model_admins: # pragma: no branch model_admins[inline.model] = inline all_admin_fields[inline.model].update( from_fieldsets(inline, False)) all_admin_fields[inline.model].add(fk_field.name) # we always have id and never pk for fields in all_admin_fields.values(): fields.add("id") fields.discard("pk") fields.discard("__str__") return model_admins, all_admin_fields
def __init__(self, parent_resource): self.resource_adaptor = self.model self.site = parent_resource.site self.parent_resource = parent_resource from django.db.models.fields.related import RelatedObject from django.forms.models import _get_foreign_key self.fk = _get_foreign_key(self.parent_resource.resource_adaptor, self.model, self.fk_name) if self.rel_name is None: self.rel_name = RelatedObject(self.fk.rel.to, self.model, self.fk).get_accessor_name() self.inline_instances = []
def smartinlineformset_factory(parent_model, model, request, form=ModelForm, formset=BaseInlineFormSet, fk_name=None, fields=None, exclude=None, extra=3, can_order=False, can_delete=True, min_num=None, max_num=None, formfield_callback=None, widgets=None, validate_min=False, validate_max=False, localized_fields=None, labels=None, help_texts=None, error_messages=None, formreadonlyfield_callback=None, readonly_fields=None, readonly=False): fk = _get_foreign_key(parent_model, model, fk_name=fk_name) # enforce a max_num=1 when the foreign key to the parent model is unique. if fk.unique: max_num = 1 kwargs = { 'form': form, 'formfield_callback': formfield_callback, 'formset': formset, 'extra': extra, 'can_delete': can_delete, 'can_order': can_order, 'fields': fields, 'exclude': exclude, 'max_num': max_num, 'min_num': min_num, 'widgets': widgets, 'validate_max': validate_max, 'validate_min': validate_min, 'localized_fields': localized_fields, 'labels': labels, 'help_texts': help_texts, 'error_messages': error_messages, 'formreadonlyfield_callback': formreadonlyfield_callback, 'readonly_fields': readonly_fields, 'readonly': readonly, } FormSet = smartmodelformset_factory(model, request, **kwargs) FormSet.fk = fk return FormSet
def process(self): target = self.cleaned_data["target"] fields = [] for field in self.instance._meta.get_fields(): if self.cleaned_data.get("set_{}".format(field.name)): setattr(target, field.name, getattr(self.instance, field.name)) fields.append("{}".format( getattr(field, "verbose_name", field.name))) if fields: self.modeladmin.message_user( self.request, _("Updated fields of %(node)s: %(fields)s") % { "node": target, "fields": ", ".join(fields) }, ) if self.cleaned_data.get("_set_content"): from django.forms.models import _get_foreign_key # Since 2009. for inline in self.modeladmin.inlines: fk = _get_foreign_key(self.modeladmin.model, inline.model, inline.fk_name, False) # Remove all existing instances inline.model._default_manager.filter(**{ fk.name: target }).delete() for obj in inline.model._default_manager.filter( **{fk.name: self.instance}): obj.pk = None setattr(obj, fk.name, target) obj.save(force_insert=True) self.modeladmin.message_user( self.request, _("Replaced the content of %(target)s with the contents of %(source)s." ) % { "target": target, "source": self.instance }, ) target.save() opts = self.modeladmin.model._meta return redirect( "admin:%s_%s_change" % (opts.app_label, opts.model_name), target.pk)
def get_formset(self, request, obj=None): setattr(self.form, '_magic_user', request.user) # magic variable assigned to form setattr(self, '_magic_user', request.user) # magic variable from django.forms.models import _get_foreign_key setattr(self, '_magic_instance', obj) setattr( self, '_magic_fk', _get_foreign_key(self.parent_model, self.model, fk_name=self.fk_name)) self.user = request.user return super(NewmanInlineModelAdmin, self).get_formset(request, obj)
def get_model_form(base_model=None, base_form=None, inline_models=None, inline_forms=None, inline_options=None, common_options=None, formset=False, **kwargs): """ Permet de construire d'un coup un formulaire de modèle et ses sous-formulaires éventuels Les listes `inline_models`, `inline_forms` et `inline_kwargs` doivent être de même taille et dans le même ordre :param base_model: Modèle de base (obligatoire) :param base_form: Formulaire pour le modèle de base (facultatif) :param inline_models: Sous-modèles à relier (obligatoire) :param inline_forms: Sous-formulaires pour chaque sous-modèle (facultatif) :param inline_options: Paramètres de chaque sous-formulaire (facultatif) :param formset: En faire un ensemble de formulaires ? :param kwargs: Paramètres optionnels utilisés uniquement pour le formulaire principal :return: Formulaire principal et ses sous-formulaires """ from itertools import zip_longest common_options = common_options or {} inline_models, inline_forms, inline_options = inline_models or [], inline_forms or [], inline_options or [] inlines = [] for model, form, options in zip_longest(inline_models, inline_forms, inline_options, fillvalue=None): if not model: continue options = options or {} options.update(common_options) fk = _get_foreign_key(base_model, model) if fk.unique: options['max_num'] = 1 inline = get_model_formset(model, form=form, formset=CommonInlineFormSet, **options) inline.fk = fk inlines.append(inline) if formset: formset = get_model_formset(base_model, form=base_form, **kwargs) formset._inlines = inlines return formset elif not base_form: base_form = modelform_factory(base_model, form=CommonModelForm, **kwargs) base_form._inlines = inlines return base_form
def set_parent_info(self, parent_model=None, fk_name=None): # TODO: should use property on parent_model self.parent_model = parent_model if self.parent_model: if self.is_generic_fk: # Generic FK (GenericRelation) field = get_generic_fk_field(self.model) if field: self.fk_field = field.fk_field self.ct_field = field.ct_field else: # Normal FK fk = _get_foreign_key(self.parent_model, self.model, fk_name) self.fk_name = fk.name
def get_inline_formsets(self, obj, change): "Helper function to generate InlineFormSets for add/change_view." inline_formsets = [] obj = obj if change else None fields = flatten_fieldsets(self.get_fieldsets(self.mode)) for InlineFormSet, inline in self.get_formsets_with_inlines(obj): inline_fk_field = _get_foreign_key(self.model, inline.model, inline.fk_name) if inline_fk_field.remote_field.name not in fields: continue formset_kwargs = inline.get_formset_kwargs( formset_class=InlineFormSet, obj=obj) inline_formsets.append(InlineFormSet(**formset_kwargs)) return inline_formsets
def get_form_class(self, request, instance=None, **kwargs): kwargs.update(self.form_kwargs) if "exclude" in self.formset_kwargs: kwargs['exclude'] = kwargs.get("exclude", []) \ + self.formset_kwargs.get("exclude") try: fk = _get_foreign_key(type(self.instance), self.model) kwargs['exclude'] = kwargs.get("exclude", []) + [fk.name] except: pass return modelform_factory(self.model, form=self.form_class or ModelForm, **kwargs)
def translatable_inlineformset_factory(language, parent_model, model, form=TranslatableModelForm, formset=BaseInlineFormSet, fk_name=None, fields=None, exclude=None, extra=3, can_order=False, can_delete=True, max_num=None, formfield_callback=None, **kwargs): from django.forms.models import _get_foreign_key fk = _get_foreign_key(parent_model, model, fk_name=fk_name) if fk.unique: #pragma: no cover (internal Django behavior) max_num = 1 FormSet = translatable_modelformset_factory(language, model, form=form, formfield_callback=formfield_callback, formset=formset, extra=extra, can_delete=can_delete, can_order=can_order, fields=fields, exclude=exclude, max_num=max_num, **kwargs) FormSet.fk = fk return FormSet
def get_initial_inlines(self): initial_inlines = {} if self.request.GET.get('pk_copy', None) is not None: object_to_copy = get_object_or_404(self.get_queryset(), pk=self.request.GET['pk_copy']) for inline, inline_copy_fields in self.get_inlines_copy_fields( ).items(): fields_to_copy = inline_copy_fields if inline.model._meta.pk.name in fields_to_copy: fields_to_copy.remove(self.model._meta.pk.name) datas = [] fk = _get_foreign_key(self.model, inline.model) for object in inline.model._default_manager.filter( **{fk.name: object_to_copy}): datas.append(model_to_dict(object, fields=fields_to_copy)) initial_inlines.update({inline: datas}) return initial_inlines
def validate_inline(cls, parent, parent_model): # model is already verified to exist and be a Model if cls.fk_name: # default value is None f = get_field(cls, cls.model, cls.model._meta, "fk_name", cls.fk_name) if not isinstance(f, models.ForeignKey): raise ImproperlyConfigured("'%s.fk_name is not an instance of " "models.ForeignKey." % cls.__name__) if not issubclass(cls, EmbeddedDocumentAdmin): fk = _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name, can_fail=True) else: fk = None # extra = 3 if not isinstance(cls.extra, int): raise ImproperlyConfigured("'%s.extra' should be a integer." % cls.__name__) # max_num = None max_num = getattr(cls, "max_num", None) if max_num is not None and not isinstance(max_num, int): raise ImproperlyConfigured( "'%s.max_num' should be an integer or None (default)." % cls.__name__) # formset if hasattr(cls, "formset") and not issubclass(cls.formset, BaseDocumentFormSet): raise ImproperlyConfigured("'%s.formset' does not inherit from " "BaseDocumentFormSet." % cls.__name__) # exclude if hasattr(cls, "exclude") and cls.exclude: if fk and fk.name in cls.exclude: raise ImproperlyConfigured( "%s cannot exclude the field " "'%s' - this is the foreign key to the parent model " "%s." % (cls.__name__, fk.name, parent_model.__name__)) if hasattr(cls, "readonly_fields"): check_readonly_fields(cls, cls.document, cls.document._meta)
def duplicate_page(original_page, page_changes=None): ''' Takes a page and duplicates it as a child of the original's parent page. Expects to be passed the original page and an optional function ''' from .admin import page_admin original_content = original_page.content with update_index(): page = deepcopy(original_page) page.pk = None if callable(page_changes): page = page_changes(page, original_page) page.save() content = deepcopy(original_content) content.pk = None content.page = page content.save() # This doesn't copy m2m relations on the copied inline for content_cls, admin_cls in page_admin.content_inlines: if not isinstance(content, content_cls): continue model_cls = admin_cls.model fk = _get_foreign_key(Page, model_cls, fk_name=admin_cls.fk_name) related_items = model_cls.objects.filter(**{ fk.name: original_page.pk }).distinct().all() for item in related_items: new_object = deepcopy(item) new_object.pk = None setattr(new_object, fk.name, page) new_object = overlay_obj(new_object, item, exclude=[fk.name, 'pk', 'id'], commit=True) new_object.save() return page
def subform_factory(summary, items, included_fields=None): # TODO: fk_name may be necessary excludes = [] try: fk = _get_foreign_key(summary.instance.__class__, items.rel_model, fk_name=None) excludes.append(fk.name) except Exception: pass # The following feature has been removed, in favour of explicit field selection # If this is an intermediate model, exclude the other foreign key field # if items.end_model is not None: # efk = _get_foreign_key(items.end_model, items.rel_model, fk_name=None) # excludes.append(efk.name) class Meta: model = items.rel_model exclude = excludes fields = included_fields return type("%sModelForm" % items.rel_model.__name__, (ModelForm,), {"Meta": Meta})
def contenttype_inlineformset_factory(parent_model, model, admin_site, formfield_callback, extra=3, can_order=False, can_delete=True, max_num=0): fk = _get_foreign_key(parent_model, model) Meta = type('Meta', (MenuItemForm.Meta,), {'model': model}) class_name = model.__name__ + 'Form' form_class_attrs = { 'admin_site': admin_site, 'Meta': Meta, 'formfield_callback': formfield_callback } form = ModelFormMetaclass(class_name, (MenuItemForm,), form_class_attrs) FormSet = formset_factory(form, BaseInlineFormSet, extra=extra, max_num=max_num, can_order=can_order, can_delete=can_delete) FormSet.model = model FormSet.fk = fk return FormSet
def form(self, parent, name, *args, **kwargs): form = self._get_or_load_from_module(self.form_name) fk = _get_foreign_key(self.model, parent._meta.model, name) Form = modelform_factory( self.model, form=form, fields=self.fields, exclude=self.exclude, formfield_callback=self.formfield_callback, widgets=self.widgets, localized_fields=self.localized_fields, labels=self.labels, help_texts=self.help_texts, error_messages=self.error_messages, ) Form.fk = fk form_widget = Form(*args, **kwargs) return form_widget
def subform_factory(summary, items, included_fields=None): # TODO: fk_name may be necessary excludes = [] try: fk = _get_foreign_key(summary.instance.__class__, items.rel_model, fk_name=None) excludes.append(fk.name) except Exception: pass # The following feature has been removed, in favour of explicit field selection # If this is an intermediate model, exclude the other foreign key field #if items.end_model is not None: # efk = _get_foreign_key(items.end_model, items.rel_model, fk_name=None) # excludes.append(efk.name) class Meta: model = items.rel_model exclude = excludes fields = included_fields return type('%sModelForm' % items.rel_model.__name__, (ModelForm, ), {'Meta': Meta})
def get_formsets_with_inlines(self, request, obj=None): # Make sure to pass request data to fieldsets # so they can use it to define choices initial = {} model = self.model opts = model._meta data = getattr(request, request.method).items() # If an object is provided we collect data if obj is not None: initial.update(model_to_dict(obj)) # Make sure to collect parent model data # and provide it to fieldsets in the form of # parent__field from request if its provided. # This data should be more "up-to-date". for k, v in data: if v: try: f = opts.get_field(k) except models.FieldDoesNotExist: continue if isinstance(f, models.ManyToManyField): initial[k] = v.split(",") else: initial[k] = v for formset, inline in self._get_formsets_with_inlines( request, obj): fk = _get_foreign_key(self.model, inline.model, fk_name=inline.fk_name).name fk_initial = dict( ('%s__%s' % (fk, k), v) for k, v in initial.items()) # If we must provide additional data # we must wrap the formset in a subclass # because passing 'initial' key argument is intercepted # and not provided to subclasses by BaseInlineFormSet.__init__ if len(initial): formset = dynamic_formset_factory(formset, fk_initial) yield formset, inline
def validate_inline(cls, parent, parent_model): # model is already verified to exist and be a Model if cls.fk_name: # default value is None f = get_field(cls, cls.model, cls.model._meta, "fk_name", cls.fk_name) if not isinstance(f, models.ForeignKey): raise ImproperlyConfigured("'%s.fk_name is not an instance of " "models.ForeignKey." % cls.__name__) if not issubclass(cls, EmbeddedDocumentAdmin): fk = _get_foreign_key(parent_model, cls.model, fk_name=cls.fk_name, can_fail=True) else: fk = None # extra = 3 if not isinstance(cls.extra, int): raise ImproperlyConfigured("'%s.extra' should be a integer." % cls.__name__) # max_num = None max_num = getattr(cls, "max_num", None) if max_num is not None and not isinstance(max_num, int): raise ImproperlyConfigured("'%s.max_num' should be an integer or None (default)." % cls.__name__) # formset if hasattr(cls, "formset") and not issubclass(cls.formset, BaseDocumentFormSet): raise ImproperlyConfigured("'%s.formset' does not inherit from " "BaseDocumentFormSet." % cls.__name__) # exclude if hasattr(cls, "exclude") and cls.exclude: if fk and fk.name in cls.exclude: raise ImproperlyConfigured( "%s cannot exclude the field " "'%s' - this is the foreign key to the parent model " "%s." % (cls.__name__, fk.name, parent_model.__name__) ) if hasattr(cls, "readonly_fields"): check_readonly_fields(cls, cls.document, cls.document._meta)
def inlineformset_factory(parent_model, model, extra=3, max_num=None, fk_name=None, formset=BaseInlineFormSet, **kwargs): """ Returns an ``InlineFormSet`` for the given kwargs. You must provide ``fk_name`` if ``model`` has more than one ``ForeignKey`` to ``parent_model``. """ # enforce a max_num=1 when the foreign key to the parent model is unique. fk = _get_foreign_key(parent_model, model, fk_name=fk_name) if fk.unique: max_num = 1 FormSet = modelformset_factory(model, formset=formset, max_num=max_num, extra=extra, **kwargs) FormSet.fk = fk return FormSet
def _get_list_filter(self): fk_name = _get_foreign_key(self.parent_instance.__class__, self.model, fk_name=self.fk_name).name return {'filter': {fk_name: self.parent_instance.pk}}
def _get_all_admin_fields(request): request.data_browser = {"calculated_fields": set(), "fields": set()} def from_fieldsets(admin, all_): auth_user_compat = settings.DATA_BROWSER_AUTH_USER_COMPAT if auth_user_compat and isinstance(admin, UserAdmin): obj = admin.model() # get the change fieldsets, not the add ones else: obj = None fields = admin.get_fieldsets(request, obj) for f in flatten_fieldsets(fields): # skip calculated fields on inlines if not isinstance(admin, InlineModelAdmin) or hasattr( admin.model, f): yield f def visible(model_admin, request): attrs = ["get_fieldsets", "model", "get_queryset"] if not all(hasattr(model_admin, a) for a in attrs): debug_log( f"{type(model_admin)} instance does not look like a ModelAdmin or InlineModelAdmin" ) return False if getattr(model_admin, "ddb_ignore", False): return False if model_admin.has_change_permission(request): return True if hasattr(model_admin, "has_view_permission"): return model_admin.has_view_permission(request) else: return False # pragma: no cover Django < 2.1 all_admin_fields = defaultdict(set) hidden_fields = defaultdict(set) model_admins = {} for model, model_admin in site._registry.items(): model_admins[model] = model_admin if visible(model_admin, request): all_admin_fields[model].update(from_fieldsets(model_admin, True)) all_admin_fields[model].update( model_admin.get_list_display(request)) all_admin_fields[model].update( getattr(model_admin, "ddb_extra_fields", [])) all_admin_fields[model].add(open_in_admin) hidden_fields[model].update( getattr(model_admin, "ddb_hide_fields", [])) # check the inlines, these are already filtered for access for inline in model_admin.get_inline_instances(request): if visible(inline, request): try: fk_field = _get_foreign_key(model, inline.model, inline.fk_name) except Exception as e: debug_log( e) # ignore things like GenericInlineModelAdmin else: if inline.model not in model_admins: # pragma: no branch model_admins[inline.model] = inline all_admin_fields[inline.model].update( from_fieldsets(inline, False)) all_admin_fields[inline.model].update( getattr(inline, "ddb_extra_fields", [])) all_admin_fields[inline.model].add(fk_field.name) hidden_fields[inline.model].update( getattr(inline, "ddb_hide_fields", [])) for model, model_admin in model_admins.items(): if isinstance(model_admin, AdminMixin): all_admin_fields[model].update(model_admin._ddb_annotations()) # we always have id and never pk for fields in all_admin_fields.values(): fields.add("id") fields.discard("pk") fields.discard("__str__") # throw away the hidden ones for model, fields in hidden_fields.items(): for f in fields: all_admin_fields[model].discard(f) return model_admins, all_admin_fields
def get_related_field(self): return _get_foreign_key( parent_model=self.parent_backend.model, model=self.backend.model)
# -*- coding: utf-8 -*-
def _get_all_admin_fields(request): assert hasattr(request, "data_browser"), request def from_fieldsets(admin, include_calculated): auth_user_compat = settings.DATA_BROWSER_AUTH_USER_COMPAT if auth_user_compat and isinstance(admin, UserAdmin): obj = admin.model() # get the change fieldsets, not the add ones else: obj = None fields = admin.get_fieldsets(request, obj) for f in flatten_fieldsets(fields): # skip calculated fields unless include_calculated given if include_calculated or _model_has_field(admin.model, f): yield f def visible(model_admin, request): has_attrs = all( hasattr(model_admin, a) for a in ["get_fieldsets", "model", "get_queryset"]) if not has_attrs or not issubclass(model_admin.model, models.Model): debug_log( f"{type(model_admin)} instance does not look like a ModelAdmin or" " InlineModelAdmin") return False if _get_option(model_admin, "ignore", request): return False return model_admin.has_view_permission(request) all_model_fields = defaultdict(set) hidden_model_fields = defaultdict(set) def get_common(admin, model): all_model_fields[model].update( from_fieldsets(admin, include_calculated=False)) all_model_fields[model].update( _get_option(admin, "extra_fields", request)) hidden_model_fields[model].update( _get_option(admin, "hide_fields", request)) model_admins = {} for model, model_admin in site._registry.items(): if visible(model_admin, request): model_admins[model] = model_admin all_model_fields[model].update( model_admin.get_list_display(request)) all_model_fields[model].add(open_in_admin) get_common(model_admin, model) # check the inlines, these are already filtered for access for inline in model_admin.get_inline_instances(request): if visible(inline, request): try: fk_field = _get_foreign_key(model, inline.model, inline.fk_name) except Exception as e: debug_log( e) # ignore things like GenericInlineModelAdmin else: if inline.model not in model_admins: # pragma: no branch model_admins[inline.model] = inline all_model_fields[inline.model].add(fk_field.name) get_common(inline, inline.model) for model, model_admin in model_admins.items(): # add in the backside of related fields's for field_name in set( all_model_fields[model]): # copy because we might modify if _model_has_field(model, field_name): field = model._meta.get_field(field_name) if (field.is_relation and field.related_model in all_model_fields and not field.remote_field.hidden): all_model_fields[field.related_model].add( field.remote_field.name) # and the calculated fields all_model_fields[model].update( from_fieldsets(model_admin, include_calculated=True)) # and any annotations that weren't mentioned in field_sets etc if isinstance(model_admin, AdminMixin): all_model_fields[model].update(model_admin._ddb_annotations()) # we always have the actual pk field and never have the "pk" proxy for model, fields in all_model_fields.items(): fields.add(model._meta.pk.name) fields.discard("pk") fields.discard("__str__") # throw away the hidden ones for model, fields in hidden_model_fields.items(): for f in fields: all_model_fields[model].discard(f) return model_admins, all_model_fields