def get_related_objects(self, flatten=False): """ Returns all objects related to the current. """ collector = NestedObjects(using='default') collector.collect([self]) if flatten: return list(utils.flatten(collector.nested())) return collector.nested()
def delete_survey(request, sid): survey = get_object_or_404(Engagement_Survey, id=sid) form = Delete_Eng_Survey_Form(instance=survey) from django.contrib.admin.util import NestedObjects from django.db import DEFAULT_DB_ALIAS collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([survey]) rels = collector.nested() if request.method == 'POST': if 'id' in request.POST and str(survey.id) == request.POST['id']: form = Delete_Eng_Survey_Form(request.POST, instance=survey) if form.is_valid(): survey.delete() messages.add_message(request, messages.SUCCESS, 'Survey and relationships removed.', extra_tags='alert-success') return HttpResponseRedirect(reverse('survey')) add_breadcrumb(title="Delete Survey", top_level=False, request=request) return render(request, 'defectDojo-engagement-survey/delete_survey.html', { 'survey': survey, 'form': form, 'rels': rels, })
def viewmap_delete_page(request, vsid): page = get_object_or_404(Page, pk=vsid) uim = page.uimodel if uim.is_frozen: return render(request, 'mcms/uimodels/frozen.html', dict(uimodel=uim)) collector = NestedObjects(using='default') collector.collect([page]) to_delete = collector.nested() if request.method == 'POST': page.delete() return HttpResponseRedirect(reverse('mcms:uimodels:edit_viewmap', kwargs={'vmid': page.viewmap.id})) opts = page._meta object_name = force_unicode(opts.verbose_name) title = ('Are you sure?') context = { 'title': title, 'object_name': object_name, 'object': page, 'deleted_objects': to_delete, 'opts': opts, 'app_label': opts.app_label, } return TemplateResponse( request, 'mcms/uimodels/delete_confirmation.html', context, current_app='Test')
def get_deleted_objects(obj, user): """ Find all objects related to ``obj`` that should also be deleted. Returns a nested list of strings suitable for display in the template with the ``unordered_list`` filter. Copied and updated from django.contrib.admin.util for front end display. """ using = router.db_for_write(obj.__class__) collector = NestedObjects(using=using) collector.collect([obj]) perms_needed = set() def format_callback(obj): opts = obj._meta if hasattr(obj, "get_absolute_url"): url = obj.get_absolute_url() p = "%s.%s" % (opts.app_label, opts.get_delete_permission()) if not user.has_perm(p): perms_needed.add(opts.verbose_name) # Display a link to the admin page. return mark_safe(u'%s: <a href="%s">%s</a>' % (escape(capfirst(opts.verbose_name)), url, escape(obj))) else: # no link return u"%s: %s" % (capfirst(opts.verbose_name), force_unicode(obj)) to_delete = collector.nested(format_callback) protected = [format_callback(obj) for obj in collector.protected] return to_delete, perms_needed, protected
def delete_user(request, uid): user = get_object_or_404(Dojo_User, id=uid) form = DeleteUserForm(instance=user) from django.contrib.admin.util import NestedObjects from django.db import DEFAULT_DB_ALIAS collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([user]) rels = collector.nested() if user.id == request.user.id: messages.add_message(request, messages.ERROR, 'You may not delete yourself.', extra_tags='alert-danger') return HttpResponseRedirect(reverse('edit_user', args=(user.id,))) if request.method == 'POST': if 'id' in request.POST and str(user.id) == request.POST['id']: form = DeleteUserForm(request.POST, instance=user) if form.is_valid(): user.delete() messages.add_message(request, messages.SUCCESS, 'User and relationships removed.', extra_tags='alert-success') return HttpResponseRedirect(reverse('users')) add_breadcrumb(title="Delete User", top_level=False, request=request) return render(request, 'dojo/delete_user.html', {'to_delete': user, 'form': form, 'rels': rels, })
def get_context_data(self, **kwargs): context = super(EmplacementDelete, self).get_context_data(**kwargs) collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([context['object']]) deleted_elements = collector.nested() context['deleted_elements'] = deleted_in_str(deleted_elements) return context
def delete_engagement(request, eid): engagement = get_object_or_404(Engagement, pk=eid) product = engagement.product form = DeleteEngagementForm(instance=engagement) from django.contrib.admin.util import NestedObjects from django.db import DEFAULT_DB_ALIAS collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([engagement]) rels = collector.nested() if request.method == 'POST': if 'id' in request.POST and str(engagement.id) == request.POST['id']: form = DeleteEngagementForm(request.POST, instance=engagement) if form.is_valid(): engagement.delete() messages.add_message(request, messages.SUCCESS, 'Engagement and relationships removed.', extra_tags='alert-success') return HttpResponseRedirect(reverse('view_product', args=(product.id,))) add_breadcrumb(parent=engagement, title="Delete", top_level=False, request=request) return render(request, 'dojo/delete_engagement.html', {'engagement': engagement, 'form': form, 'rels': rels, })
def deletion_tree(obj): ''' Return a list of all nested objects that will be deleted ''' collector = NestedObjects(using=obj._state.db) collector.collect([obj]) def format_callback(obj): return u'%s: %s' % (force_text(obj._meta.verbose_name), force_text(obj)) return collector.nested(format_callback)
def delete_survey(request, sid): survey = get_object_or_404(Engagement_Survey, id=sid) form = Delete_Eng_Survey_Form(instance=survey) from django.contrib.admin.util import NestedObjects from django.db import DEFAULT_DB_ALIAS collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([survey]) rels = collector.nested() if request.method == 'POST': if 'id' in request.POST and str(survey.id) == request.POST['id']: form = Delete_Eng_Survey_Form(request.POST, instance=survey) if form.is_valid(): survey.delete() messages.add_message(request, messages.SUCCESS, 'Survey and relationships removed.', extra_tags='alert-success') return HttpResponseRedirect(reverse('survey')) add_breadcrumb(title="Delete Survey", top_level=False, request=request) return render(request, 'defectDojo-engagement-survey/delete_survey.html', {'survey': survey, 'form': form, 'rels': rels, })
def get_context_data(self, *args, **kwargs): context = super(DeleteView, self).get_context_data(*args, **kwargs) using = router.db_for_write(self.model) collector = NestedObjects(using=using) collector.collect([self.object]) context["related_objects"] = collector.nested() return context
def ui_model_delete_device(request, umdid): uim_device = UIModelDevice.objects.get(id=umdid) if uim_device.uimodel.is_frozen: return render(request, 'mcms/uimodels/frozen.html', dict(uimodel=uim_device.uimodel)) collector = NestedObjects(using='default') collector.collect([uim_device, ]) to_delete = collector.nested() if request.method == 'POST': # The user has already confirmed the delete. uim_device.delete() return HttpResponseRedirect( reverse('mcms:uimodels:details', kwargs={ 'mid': uim_device.uimodel.id})) opts = uim_device._meta object_name = force_unicode(opts.verbose_name) title = ('Are you sure?') context = { 'title': title, 'object_name': object_name, 'object': uim_device, 'deleted_objects': to_delete, 'opts': opts, 'app_label': opts.app_label, } return TemplateResponse( request, 'mcms/uimodels/delete_confirmation.html', context, current_app='Test')
def delete_user(request, uid): user = get_object_or_404(Dojo_User, id=uid) form = DeleteUserForm(instance=user) from django.contrib.admin.util import NestedObjects from django.db import DEFAULT_DB_ALIAS collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([user]) rels = collector.nested() if user.id == request.user.id: messages.add_message(request, messages.ERROR, 'You may not delete yourself.', extra_tags='alert-danger') return HttpResponseRedirect(reverse('edit_user', args=(user.id, ))) if request.method == 'POST': if 'id' in request.POST and str(user.id) == request.POST['id']: form = DeleteUserForm(request.POST, instance=user) if form.is_valid(): user.delete() messages.add_message(request, messages.SUCCESS, 'User and relationships removed.', extra_tags='alert-success') return HttpResponseRedirect(reverse('users')) add_breadcrumb(title="Delete User", top_level=False, request=request) return render(request, 'dojo/delete_user.html', { 'to_delete': user, 'form': form, 'rels': rels, })
def delete_engagement(request, eid): engagement = get_object_or_404(Engagement, pk=eid) product = engagement.product form = DeleteEngagementForm(instance=engagement) from django.contrib.admin.util import NestedObjects from django.db import DEFAULT_DB_ALIAS collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([engagement]) rels = collector.nested() if request.method == 'POST': if 'id' in request.POST and str(engagement.id) == request.POST['id']: form = DeleteEngagementForm(request.POST, instance=engagement) if form.is_valid(): del engagement.tags engagement.delete() messages.add_message(request, messages.SUCCESS, 'Engagement and relationships removed.', extra_tags='alert-success') return HttpResponseRedirect( reverse('view_product', args=(product.id, ))) add_breadcrumb(parent=engagement, title="Delete", top_level=False, request=request) return render(request, 'dojo/delete_engagement.html', { 'engagement': engagement, 'form': form, 'rels': rels, })
def get_context_data(self, **kwargs): context = super(OrganizationDelete, self).get_context_data(**kwargs) collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([context['object']]) deleted_elements = collector.nested() context['deleted_elements'] = deleted_in_str(deleted_elements) context['title'] = _("Organization") context['model'] = "organization" return context
def list_deleted_objects(obj): model = obj.__class__ def format_callback(item): return u'%s: %s' % (item._meta.verbose_name.capitalize(), force_unicode(item)) collector = NestedObjects(using=router.db_for_write(model)) collector.collect(model.objects.filter(id=obj.id)) to_delete = collector.nested(format_callback) return {'to_delete': to_delete}
def delete_bastard(obj): """ Delete the bastard obj, user or subscriber. Don't delete if cascade will delete a protected object, in this case alert. """ collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([obj]) def candelete(item): if isinstance(item, Iterable): return all([candelete(i) for i in item]) elif type(item) in PROTECTED_CLASSES: print("%s not deleted because has %s" % (obj, item)) return False else: return True if candelete(collector.nested()): print("Deleting %s and %s" % (obj, collector.nested())) obj.delete()
def make_mobile_numbers_unique(users): for user in users: collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([user]) items = collector.nested() for item in items: if isinstance(item, User): continue else: unique_instances = set([str(instance.__class__.__name__) for instance in item]) if len(unique_instances) == 1: pass
def make_mobile_numbers_unique(users): for user in users: collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([user]) items = collector.nested() for item in items: if isinstance(item, User): continue else: unique_instances = set( [str(instance.__class__.__name__) for instance in item]) if len(unique_instances) == 1: pass
class NestedObjectsTests(TestCase): """ Tests for ``NestedObject`` utility collection. """ def setUp(self): self.n = NestedObjects() self.objs = [Count.objects.create(num=i) for i in range(5)] def _check(self, target): self.assertEquals(self.n.nested(lambda obj: obj.num), target) def _add(self, obj, parent=None): # don't bother providing the extra args that NestedObjects ignores self.n.add(None, None, obj, None, parent) def test_unrelated_roots(self): self._add(self.objs[0]) self._add(self.objs[1]) self._add(self.objs[2], self.objs[1]) self._check([0, 1, [2]]) def test_siblings(self): self._add(self.objs[0]) self._add(self.objs[1], self.objs[0]) self._add(self.objs[2], self.objs[0]) self._check([0, [1, 2]]) def test_duplicate_instances(self): self._add(self.objs[0]) self._add(self.objs[1]) dupe = Count.objects.get(num=1) self._add(dupe, self.objs[0]) self._check([0, 1]) def test_non_added_parent(self): self._add(self.objs[0], self.objs[1]) self._check([0]) def test_cyclic(self): self._add(self.objs[0], self.objs[2]) self._add(self.objs[1], self.objs[0]) self._add(self.objs[2], self.objs[1]) self._add(self.objs[0], self.objs[2]) self._check([0, [1, [2]]])
class NestedObjectsTests(TestCase): """ Tests for ``NestedObject`` utility collection. """ def setUp(self): self.n = NestedObjects(using=DEFAULT_DB_ALIAS) self.objs = [Count.objects.create(num=i) for i in range(5)] def _check(self, target): self.assertEqual(self.n.nested(lambda obj: obj.num), target) def _connect(self, i, j): self.objs[i].parent = self.objs[j] self.objs[i].save() def _collect(self, *indices): self.n.collect([self.objs[i] for i in indices]) def test_unrelated_roots(self): self._connect(2, 1) self._collect(0) self._collect(1) self._check([0, 1, [2]]) def test_siblings(self): self._connect(1, 0) self._connect(2, 0) self._collect(0) self._check([0, [1, 2]]) def test_non_added_parent(self): self._connect(0, 1) self._collect(0) self._check([0]) def test_cyclic(self): self._connect(0, 2) self._connect(1, 0) self._connect(2, 1) self._collect(0) self._check([0, [1, [2]]]) def test_queries(self): self._connect(1, 0) self._connect(2, 0) # 1 query to fetch all children of 0 (1 and 2) # 1 query to fetch all children of 1 and 2 (none) # Should not require additional queries to populate the nested graph. self.assertNumQueries(2, self._collect, 0)
def related_objects(obj): """ Return a generator to the objects that would be deleted if we delete "obj" (excluding obj) """ collector = NestedObjects(using=router.db_for_write(obj)) collector.collect([obj]) def flatten(elem): if isinstance(elem, list): return itertools.chain.from_iterable(map(flatten, elem)) elif obj != elem: return (elem,) return () return flatten(collector.nested())
def related_objects(obj): """ Return a generator to the objects that would be deleted if we delete "obj" (excluding obj) """ collector = NestedObjects(using=router.db_for_write(obj)) collector.collect([obj]) def flatten(elem): if isinstance(elem, list): return itertools.chain.from_iterable(map(flatten, elem)) elif obj != elem: return (elem, ) return () return flatten(collector.nested())
def _get_deleted_objects(objs): """ Slightly simplified version of the function used in the standard admin """ if len(objs) == 0: return [] collector = NestedObjects(using=router.db_for_write(objs[0])) collector.collect(objs) def format_callback(obj): return '%s: %s' % (obj.__class__.__name__, unicode(obj)) return collector.nested(format_callback)
def get_deleted_objects(obj): """ Find all objects related to ``objs`` that should also be deleted. ``objs`` should be an iterable of objects. Returns a nested list of strings suitable for display in the template with the ``unordered_list`` filter. """ collector = NestedObjects() obj._collect_sub_objects(collector) to_delete = collector.nested(_format_callback) return to_delete
def get_deleted_objects(objs, opts, user, admin_site, using): collector = NestedObjects(using=using) collector.collect(objs) perms_needed = set() def clean_empty(objects): cleaned = [] for obj in objects: if isinstance(obj, list): cleaned.append(clean_empty(obj)) elif obj != '': cleaned.append(obj) return cleaned if cleaned else '"Hidden objects"' def format_callback(obj): has_admin = admin_site._registry.get(obj.__class__, False) opts = obj._meta if has_admin: if getattr(has_admin, 'deletable_objects_excluded', False): return '' admin_url = reverse('%s:%s_%s_change' % (admin_site.name, opts.app_label, opts.object_name.lower()), None, (quote(obj._get_pk_val()),)) p = '%s.%s' % (opts.app_label, opts.get_delete_permission()) if not user.has_perm(p): perms_needed.add(opts.verbose_name) # Display a link to the admin page. # NOTE: Define as unicode for avoid errors when obj # representation contains non-ascii chars return format_html(u'{0}: <a href="{1}">{2}</a>', capfirst(opts.verbose_name), admin_url, obj) else: # Don't display link to edit, because it either has no # admin or is edited inline. return u'%s: %s' % (capfirst(opts.verbose_name), force_text(obj)) to_delete = collector.nested(format_callback) to_delete = clean_empty(to_delete) protected = [format_callback(obj) for obj in collector.protected] return to_delete, perms_needed, protected
def response(self, request, username, project_slug, member_username): membership = get_object_or_404( Membership.objects.select_related('project', 'member'), project__slug=project_slug, project__author__username=username, member__username=member_username)\ member = membership.member project = membership.project if project.author == member: messages.warning( request, _("Project owner's membership cannot be " "removed.")) return redirect(project.get_members_url()) collector = NestedObjects() membership._collect_sub_objects(collector) form = MembershipDeleteForm(request.POST or None) perms_to_delete = UserObjectPermission.objects.filter( user=member, content_type=ContentType.objects.get_for_model(project), object_pk=project.id) if request.method == 'POST': # Confirm removal if form.is_valid() and project.author != member: msg = _("Membership removed") messages.success(request, msg) membership.delete() perms_to_delete.delete() return redirect(project.get_members_url()) else: msg = _("Couldn't remove membership") messages.error(request, msg) if project.author == member: msg = _("Project's author cannot be removed") messages.error(request, msg) context = { 'project': project, 'membership': membership, 'form': form, 'to_delete': collector.nested(), 'member_perms': perms_to_delete, } return context
def get_deleted_objects(objs): from django.contrib.admin.util import NestedObjects from django.utils.text import capfirst from django.utils.encoding import force_unicode def format_callback(obj): opts = obj._meta # Don't display link to edit, because it either has no # admin or is edited inline. return u'%s: %s' % (capfirst(opts.verbose_name), force_unicode(obj)) collector = NestedObjects(using='default') # or specific database # collector = NestedObjects(using=using) collector.collect(objs) return collector.nested(format_callback)
def collect_backlinks(model_instance): from django.contrib.admin.util import NestedObjects collector = NestedObjects(using='scenario_db') # or specific database collector.collect([model_instance]) dependants = collector.nested() # fun fact: spelling differs between America and Brittain print("Found related models:", dependants) links = {} if len(dependants[1:]): for direct_reference in dependants[1:][0]: # only iterates over the top level if not isinstance(direct_reference, list) and not isinstance(direct_reference, RelationalPoint): # Points are obvious, don't include them name = direct_reference.__class__.__name__ try: # not everything has a name attr links[str(direct_reference)] = '/setup/%s/%i/' % (name, direct_reference.pk) except: links['%s:%i' % (name, direct_reference.pk)] = \ '/setup/%s/%i/' % (name, direct_reference.pk) print(links) return links
def get_deleted_objects(objs, user): """ Find all objects related to ``objs`` that should also be deleted. ``objs`` must be a homogeneous iterable of objects (e.g. a QuerySet). Returns a nested list of strings suitable for display in the template with the ``unordered_list`` filter. Copied and updated from django.contrib.admin.utils for front end display. """ using = router.db_for_write(objs[0].__class__) collector = NestedObjects(using=using) collector.collect(objs) perms_needed = set() def format_callback(obj): opts = obj._meta no_edit_link = '%s: %s' % (capfirst(opts.verbose_name), force_text(obj)) p = '%s.%s' % (opts.app_label, get_permission_codename('delete', opts)) if not user.has_perm(p): perms_needed.add(opts.verbose_name) if hasattr(obj, 'get_absolute_url'): url = obj.get_absolute_url() # Display a link to the admin page. return format_html('{}: <a href="{}">{}</a>', capfirst(opts.verbose_name), url, obj) else: # Don't display link to edit, because it either has no # admin or is edited inline. return no_edit_link to_delete = collector.nested(format_callback) protected = [format_callback(obj) for obj in collector.protected] return to_delete, collector.model_count, perms_needed, protected
def get_deleted_objects(objs, opts, user, admin_site, using): """ Find all objects related to ``objs`` that should also be deleted. ``objs`` must be a homogenous iterable of objects (e.g. a QuerySet). Returns a nested list of strings suitable for display in the template with the ``unordered_list`` filter. """ collector = NestedObjects(using=using) collector.collect(objs) perms_needed = set() def format_callback(obj): has_admin = obj.__class__ in admin_site._registry opts = obj._meta if has_admin: admin_url = reverse('%s_%s_edit' % ( opts.app_label, opts.object_name.lower()), None, (quote(obj._get_pk_val()),)) p = '%s_%s_delete' % (opts.app_label,opts.object_name.lower()) if not user.has_perm(p): perms_needed.add(opts.verbose_name) # Display a link to the admin page. return format_html(u'{0}: <a href="{1}">{2}</a>', capfirst(opts.verbose_name), admin_url, obj) else: # Don't display link to edit, because it either has no # admin or is edited inline. return '%s: %s' % (capfirst(opts.verbose_name), force_text(obj)) to_delete = collector.nested(format_callback) protected = [format_callback(obj) for obj in collector.protected] return to_delete, perms_needed, protected
def reportwhatwillbedeleted(request, report): if not request.user.is_authenticated() or not hasPermission( request.user, 'moderate_reports'): raise PermissionDenied() context = ajaxContext(request) # Get the report report = get_object_or_404(models.Report, pk=report, i_status=models.Report.get_i( 'status', 'Pending')) # Get the reported thing queryset = report.reported_thing_collection.queryset thing = get_object_or_404(queryset, pk=report.reported_thing_id) from django.contrib.admin.util import NestedObjects collector = NestedObjects(using='default') # or specific database collector.collect([thing]) context['report'] = report context['to_delete'] = collector.nested() return render(request, 'ajax/reportwhatwillbedeleted.html', context)
def _collect_deleted_objects(self, obj): result = [] try: # This is for Django up to 1.2 from django.db.models.query_utils import CollectedObjects seen_objs = CollectedObjects() obj._collect_sub_objects(seen_objs) for cls, subobjs in seen_objs.iteritems(): for subobj in subobjs.values(): result.append(subobj) except ImportError: # Django 1.3 solution, those imports needs to be here, because # otherwise they will fail on Django < 1.3. from django.contrib.admin.util import NestedObjects from django.db import router using = router.db_for_write(obj) collector = NestedObjects(using=using) collector.collect([obj]) result = self._flatten(collector.nested()) return result
def get_related_objects( obj, to_update=DEFAULT_TO_UPDATE ): collector = NestedObjects( using=DEFAULT_DB_ALIAS ) collector.collect( obj ) perms_needed = set() def format_callback( o ): opts = o._meta key = '%s_%s' % ( opts.app_label, opts.object_name.lower() ) to_delete = key not in to_update try: admin_url = reverse( 'admin:%s_%s_change' % ( opts.app_label, opts.object_name.lower() ), None, ( o._get_pk_val() ,) ) except: return mark_safe( u'%s%s: %s%s' % ( '<strike>' if to_delete else '', capfirst( opts.verbose_name ), force_unicode( o ), '</strike>' if to_delete else '' ) ) return mark_safe( u'%s%s: <a href="%s">%s</a>%s' % ( '<strike>' if to_delete else '', escape( capfirst( opts.verbose_name ) ), admin_url, escape( o ), '</strike>' if to_delete else '' ) ) return collector.nested(format_callback)
def get_deleted_objects(obj, user): """ Find all objects related to ``obj`` that should also be deleted. Returns a nested list of strings suitable for display in the template with the ``unordered_list`` filter. Copied and updated from django.contrib.admin.util for front end display. """ using = router.db_for_write(obj.__class__) collector = NestedObjects(using=using) collector.collect([obj]) perms_needed = set() def format_callback(obj): opts = obj._meta if hasattr(obj, 'get_absolute_url'): url = obj.get_absolute_url() p = '%s.%s' % (opts.app_label, opts.get_delete_permission()) if not user.has_perm(p): perms_needed.add(opts.verbose_name) # Display a link to the admin page. return mark_safe(u'%s: <a href="%s">%s</a>' % (escape(capfirst(opts.verbose_name)), url, escape(obj))) else: # no link return u'%s: %s' % (capfirst(opts.verbose_name), force_unicode(obj)) to_delete = collector.nested(format_callback) protected = [format_callback(obj) for obj in collector.protected] return to_delete, perms_needed, protected
def get_deleted_objects(objs, opts, user, admin_site, using): """ Find all objects related to ``objs`` that should also be deleted. ``objs`` must be a homogenous iterable of objects (e.g. a QuerySet). Returns a nested list of strings suitable for display in the template with the ``unordered_list`` filter. """ collector = NestedObjects(using=using) collector.collect(objs) perms_needed = set() def format_callback(obj): opts = obj._meta return '%s: %s' % (capfirst(opts.verbose_name), force_text(obj)) to_delete = collector.nested(format_callback) protected = [format_callback(obj) for obj in collector.protected] return to_delete, perms_needed, protected
def response(self, request, username, project_slug, name): team = get_object_or_404( Team.objects.select_related('group', 'project'), project__author__username=username, project__slug=project_slug, group__name=name) group, project = team.group, team.project collector = NestedObjects() team._collect_sub_objects(collector) form = TeamDeleteForm(request.POST or None) perms_to_delete = GroupObjectPermission.objects.filter( group = group, content_type = ContentType.objects.get_for_model(project), object_pk = project.id) if request.method == 'POST': # Confirm removal if form.is_valid(): msg = _("Team removed") messages.success(request, msg) team.delete() perms_to_delete.delete() return redirect(project.get_teams_url()) else: msg = _("Couldn't remove team") messages.error(request, msg) context = { 'project': project, 'team': team, 'form': form, 'to_delete': collector.nested(), 'team_perms': perms_to_delete, } return context
def delete_related_objects(modeladmin, request, queryset): """ Action that deletes related objects for the selected items. This action first displays a confirmation page whichs shows all the deleteable objects, or, if the user has no permission one of the related childs (foreignkeys), a "permission denied" message. Next, it deletes all related objects and redirects back to the change list. """ opts = modeladmin.model._meta app_label = opts.app_label # Check that the user has delete permission for the actual model if not modeladmin.has_delete_permission(request): raise PermissionDenied using = router.db_for_write(modeladmin.model) first_level_related_objects = [] first_level_related_objects_by_type = defaultdict(list) collector = NestedObjects(using=using) collector.collect(queryset) for base_object_or_related_list in collector.nested(): if type(base_object_or_related_list) is not list: # If it's not a list, it's a base object. Skip it. continue for obj in base_object_or_related_list: if type(obj) is list: # A list here contains related objects for the previous # element. We can skip it since delete() on the first # level of related objects will cascade. continue else: first_level_related_objects.append(obj) first_level_related_objects_by_type[type(obj)].append(obj) deletable_objects = [] model_count = defaultdict(int) perms_needed = set() protected = [] # `get_deleted_objects()` fails when passed a heterogeneous list like # `first_level_related_objects`, so embark on this rigmarole to spoon-feed # it only homogeneous lists for homogeneous_list in first_level_related_objects_by_type.values(): # Populate deletable_objects, a data structure of (string # representations of) all related objects that will also be deleted. deletable_objects_, model_count_, perms_needed_, protected_ = get_deleted_objects( homogeneous_list, opts, request.user, modeladmin.admin_site, using) # Combine the results with those from previous homogeneous lists deletable_objects.extend(deletable_objects_) for k, v in model_count_.iteritems(): model_count[k] += v perms_needed.update(perms_needed_) protected.extend(protected_) # The user has already confirmed the deletion. # Do the deletion and return a None to display the change list view again. if request.POST.get('post'): if perms_needed: raise PermissionDenied n = 0 with transaction.atomic(using): for obj in first_level_related_objects: obj_display = force_text(obj) modeladmin.log_deletion(request, obj, obj_display) obj.delete() n += 1 modeladmin.message_user( request, _("Successfully deleted %(count)d related objects.") % { "count": n, "items": model_ngettext(modeladmin.opts, n) }, messages.SUCCESS) # Return None to display the change list page again. return None if len(queryset) == 1: objects_name = force_text(opts.verbose_name) else: objects_name = force_text(opts.verbose_name_plural) if perms_needed or protected: title = _("Cannot delete %(name)s") % {"name": objects_name} else: title = _("Are you sure?") context = dict( modeladmin.admin_site.each_context(request), title=title, objects_name=objects_name, deletable_objects=[deletable_objects], model_count=dict(model_count).items(), queryset=queryset, perms_lacking=perms_needed, protected=protected, opts=opts, action_checkbox_name=helpers.ACTION_CHECKBOX_NAME, ) request.current_app = modeladmin.admin_site.name # Display the confirmation page return TemplateResponse(request, "delete_related_for_selected_confirmation.html", context, current_app=modeladmin.admin_site.name)
def delete_related_objects(modeladmin, request, queryset): """ Action that deletes related objects for the selected items. This action first displays a confirmation page whichs shows all the deleteable objects, or, if the user has no permission one of the related childs (foreignkeys), a "permission denied" message. Next, it deletes all related objects and redirects back to the change list. """ opts = modeladmin.model._meta app_label = opts.app_label # Check that the user has delete permission for the actual model if not modeladmin.has_delete_permission(request): raise PermissionDenied using = router.db_for_write(modeladmin.model) first_level_related_objects = [] collector = NestedObjects(using=using) collector.collect(queryset) for base_object_or_related_list in collector.nested(): if type(base_object_or_related_list) is not list: # If it's not a list, it's a base object. Skip it. continue for obj in base_object_or_related_list: if type(obj) is list: # A list here contains related objects for the previous # element. We can skip it since delete() on the first # level of related objects will cascade. continue else: first_level_related_objects.append(obj) # Populate deletable_objects, a data structure of (string representations # of) all related objects that will also be deleted. deletable_objects, model_count, perms_needed, protected = get_deleted_objects( first_level_related_objects, opts, request.user, modeladmin.admin_site, using ) # The user has already confirmed the deletion. # Do the deletion and return a None to display the change list view again. if request.POST.get('post'): if perms_needed: raise PermissionDenied n = 0 with transaction.atomic(using): for obj in first_level_related_objects: obj_display = force_text(obj) modeladmin.log_deletion(request, obj, obj_display) obj.delete() n += 1 modeladmin.message_user( request, _("Successfully deleted %(count)d related objects.") % { "count": n, "items": model_ngettext(modeladmin.opts, n)}, messages.SUCCESS ) # Return None to display the change list page again. return None if len(queryset) == 1: objects_name = force_text(opts.verbose_name) else: objects_name = force_text(opts.verbose_name_plural) if perms_needed or protected: title = _("Cannot delete %(name)s") % {"name": objects_name} else: title = _("Are you sure?") context = dict( modeladmin.admin_site.each_context(request), title=title, objects_name=objects_name, deletable_objects=[deletable_objects], model_count=dict(model_count).items(), queryset=queryset, perms_lacking=perms_needed, protected=protected, opts=opts, action_checkbox_name=helpers.ACTION_CHECKBOX_NAME, ) request.current_app = modeladmin.admin_site.name # Display the confirmation page return TemplateResponse( request, "delete_related_for_selected_confirmation.html", context, current_app=modeladmin.admin_site.name)
def get_deleted_objects(self, objs, opts, request, using): """ Find all objects related to ``objs`` that should also be deleted. ``objs`` must be a homogenous iterable of objects (e.g. a QuerySet). Returns a nested list of strings suitable for display in the template with the ``unordered_list`` filter. Copied from django.contrib.admin.util.get_deleted_objects and extended to override delete permissions to take the object's uploader into account, by allowing deletion if has_delete_permission() returns True. """ from django.contrib.admin.util import NestedObjects collector = NestedObjects(using=using) collector.collect(objs) perms_needed = set() def format_callback(obj): has_admin = obj.__class__ in self.admin_site._registry opts = obj._meta from django.utils.html import escape from django.utils.safestring import mark_safe from django.utils.text import capfirst from django.core.urlresolvers import reverse if has_admin: from django.contrib.admin.util import quote admin_url = reverse('%s:%s_%s_change' % (self.admin_site.name, opts.app_label, opts.object_name.lower()), None, (quote(obj._get_pk_val()),)) p = '%s.%s' % (opts.app_label, opts.get_delete_permission()) if isinstance(obj, self.model): if not self.has_delete_permission(request, obj): perms_needed.add(opts.verbose_name) elif not request.user.has_perm(p): perms_needed.add(opts.verbose_name) # Display a link to the admin page. return mark_safe(u'%s: <a href="%s">%s</a>' % (escape(capfirst(opts.verbose_name)), admin_url, escape(obj))) else: # Don't display link to edit, because it either has no # admin or is edited inline. from django.utils.encoding import force_unicode return u'%s: %s' % (capfirst(opts.verbose_name), force_unicode(obj)) to_delete = collector.nested(format_callback) protected = [format_callback(obj) for obj in collector.protected] return to_delete, perms_needed, protected
def get_context_data(self, **kwargs): collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([self.object]) kwargs.setdefault('nested_objects', collector.nested()) return super(TreeDeleteView, self).get_context_data(**kwargs)
def get_nested_objects(obj): from django.contrib.admin.util import NestedObjects collector = NestedObjects(using='default') collector.collect([obj]) return collector.nested()
class NestedObjectsTests(TestCase): """ Tests for ``NestedObject`` utility collection. """ def setUp(self): self.n = NestedObjects(using=DEFAULT_DB_ALIAS) self.objs = [Count.objects.create(num=i) for i in range(5)] def _check(self, target): self.assertEqual(self.n.nested(lambda obj: obj.num), target) def _connect(self, i, j): self.objs[i].parent = self.objs[j] self.objs[i].save() def _collect(self, *indices): self.n.collect([self.objs[i] for i in indices]) def test_unrelated_roots(self): self._connect(2, 1) self._collect(0) self._collect(1) self._check([0, 1, [2]]) def test_siblings(self): self._connect(1, 0) self._connect(2, 0) self._collect(0) self._check([0, [1, 2]]) def test_non_added_parent(self): self._connect(0, 1) self._collect(0) self._check([0]) def test_cyclic(self): self._connect(0, 2) self._connect(1, 0) self._connect(2, 1) self._collect(0) self._check([0, [1, [2]]]) def test_queries(self): self._connect(1, 0) self._connect(2, 0) # 1 query to fetch all children of 0 (1 and 2) # 1 query to fetch all children of 1 and 2 (none) # Should not require additional queries to populate the nested graph. self.assertNumQueries(2, self._collect, 0) def test_on_delete_do_nothing(self): """ Check that the nested collector doesn't query for DO_NOTHING objects. """ n = NestedObjects(using=DEFAULT_DB_ALIAS) objs = [Event.objects.create()] EventGuide.objects.create(event=objs[0]) with self.assertNumQueries(2): # One for Location, one for Guest, and no query for EventGuide n.collect(objs)
def have_relations_with(obj): collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([obj]) return len(collector.nested()) > 1
def get_dep_objects(instance, using=DEFAULT_DB_ALIAS): """ Find all objects related to ``objs`` that should also be deleted. ``objs`` must be a homogeneous iterable of objects (e.g. a QuerySet). Returns a nested list of strings suitable for display in the template with the ``unordered_list`` filter. """ collector = NestedObjects(using=using) collector.collect([instance]) def format_callback(obj): no_edit_link = '%s: %s' % (capfirst(force_text(obj._meta.verbose_name)), force_text(obj)) return no_edit_link def format_callback2(obj): no_edit_link = '%s' % (capfirst(force_text(obj._meta.verbose_name))) return no_edit_link #ver_objs = collector.nested(format_callback) objects = collector.nested() # print objects deps = [] try: for x in objects[1]: if type(x) is not list: deps.append(x) except: pass # obteniendo mensaje para eliminar msg_del = '' if deps: objs = [] for p in deps: if not 'relationship' in force_text(p._meta.verbose_name): objs.append( _(u'<br>%(class_name)s: "%(instance)s"') % { 'class_name': capfirst(force_text(p._meta.verbose_name)), 'instance': force_text(p) + ' (' + force_text(p.pk) + ')'} ) params = { 'class_name': capfirst(force_text(instance._meta.verbose_name)), 'instance': force_text(instance), 'related_objects': get_text_list(objs, _('and'))} msg = _("Deleting %(class_name)s %(instance)s would require deleting the following " "protected related objects: %(related_objects)s") msgx = _("Deleting the %(object_name)s '%(escaped_object)s' would require deleting the " "following protected related objects:") #raise ValidationError(force_text(msg), code='deleting_protected', params=params) #raise Exception(msg) # messages.success(self.request, (', ').join(deps)# ) msg_del = force_text(msg % params) msg_delx = msgx % { 'object_name': capfirst(force_text(instance._meta.verbose_name)), 'escaped_object': get_text_list(objs, _('and'))} return deps, msg_del