Created
April 12, 2020 06:04
-
-
Save jacoduplessis/90410280bcfb58a57dc018d913a14f66 to your computer and use it in GitHub Desktop.
MPTT admin to move multiple nodes at once
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PlaceAdmin(MPTTModelAdmin): | |
def get_model_info(self): | |
app_label = self.model._meta.app_label | |
return app_label, self.model._meta.model_name | |
def get_move_form_class(self): | |
class MoveSelectTargetForm(forms.Form): | |
target = forms.ModelChoiceField(self.model.objects.all()) | |
position = TreeNodePositionField() | |
object_ids = forms.CharField(max_length=1000) | |
return MoveSelectTargetForm | |
def move_selected_objects(self, request, queryset): | |
selected = queryset.values_list('pk', flat=True) | |
info = self.get_model_info() | |
url = reverse(f'admin:%s_%s_move_select_target' % info) | |
return HttpResponseRedirect('%s?ids=%s' % ( | |
url, | |
','.join(str(pk) for pk in selected), | |
)) | |
actions = [ | |
'move_selected_objects', | |
] | |
def move_select_target(self, request): | |
form = self.get_move_form_class()() | |
form.initial['object_ids'] = request.GET.get('ids') | |
info = self.get_model_info() | |
action = reverse(f'admin:%s_%s_move_process' % info) | |
selection_ids = request.GET.get('ids').split(',') | |
selection = self.model.objects.filter(id__in=selection_ids) | |
context = { | |
**self.admin_site.each_context(request), | |
'form': form, | |
'action': action, | |
'selection': selection, | |
'opts': self.model._meta, | |
} | |
return TemplateResponse(request, 'mptt_move/move_select_target.html', context) | |
def move_process(self, request): | |
url = reverse('admin:%s_%s_changelist' % self.get_model_info(), | |
current_app=self.admin_site.name) | |
response = HttpResponseRedirect(url) | |
form = self.get_move_form_class()(request.POST) | |
if not form.is_valid(): | |
# need something proper here | |
self.message_user(request, 'Invalid submission') | |
return response | |
else: | |
ids = form.cleaned_data['object_ids'].split(',') | |
for obj in self.model.objects.filter(id__in=ids): | |
payload = { | |
'target': form.cleaned_data['target'], | |
'position': form.cleaned_data['position'] | |
} | |
move_form = MoveNodeForm(obj, payload) | |
if not move_form.is_valid(): | |
self.message_user(request, f'Invalid move operation: {form.errors}', level=messages.ERROR) | |
continue | |
else: | |
with transaction.atomic(): | |
move_form.save() | |
with transaction.atomic(): | |
self.model.objects.rebuild() | |
self.message_user(request, 'Move instruction processed, tree rebuilt.') | |
return response | |
def get_urls(self): | |
urls = super().get_urls() | |
info = self.get_model_info() | |
my_urls = [ | |
path('move-select-target/', | |
self.admin_site.admin_view(self.move_select_target), | |
name='%s_%s_move_select_target' % info), | |
path('move-process/', | |
self.admin_site.admin_view(self.move_process), | |
name='%s_%s_move_process' % info), | |
] | |
return my_urls + urls |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment