Hello,
In my application, I have added an action to a modeladmin class. I want to allow users to select objects in an admin view, put up a form (using default modelform) that will allow me to get data from the user and massage it. Then create bulk entries in the db with mentioned, data.
Currently,
- I have the code to massage the data in a function inside the modeladmin class and it redirects to a view (hoping to send the data to the view).
- I have a form that uses modelform, excluding some fields that don’t apply due to the multiselect nature of the action.
- I have a view that should be displaying the form, receiving the data, and performing the creation of the bulk entries.
- I have a very basic template
- My urls are there but I’m unsure how to make it work.
My Issue:
I am trying to redirect from the modeladmin class (function inside) to the view but the data is a dictionary of bulk data. Clearly I have designed it incorrectly but I’m unsure how to make it right. Should I just be doing all of the work (including submitting the new db entries) right in the modeladmin class? FYI: I originally had the function for the action in the admin.py outside of the modeladmin class but I’m currently grasping at straws so things are getting rearranged.
models.py
class AutoBlock(models.Model):
unimportant info
class Pool(models.Model):
unimportant info
admin.py
class PoolAdmin(ImportExportMixin, admin.ModelAdmin):
list_per_page = 10
list_display = ("id","name", "scheduler", "clusters", 'can_run_check_cluster', 'job_queue_enable')
ordering = ("name",)
list_display_links = ('id',)
list_editable = ("name", "scheduler", 'can_run_check_cluster', 'job_queue_enable')
search_fields = ("name", "scheduler__description")
actions = ['**activate_autoblock_selected_action**']
def **activate_autoblock_selected_action**(self, request, queryset):
clusters_list = Cluster.objects.all()
cluster_list = []
# Get the object ids for the selected objects (pools or schedulers)
object_id_list = []
queryset_type = queryset[0].__class__
for obj in queryset:
object_id_list.append(obj.id)
# Get the list of clusters that have the selected objects associated
for x in clusters_list:
if x not in cluster_list:
obj_id = None
if queryset_type is Scheduler and x.scheduler:
obj_id = x.scheduler.id
elif x.pool:
obj_id = x.pool.id
if obj_id in object_id_list:
cluster_list.append(x)
all_with_details = {}
# Get all the clusters with details into a dictionary
for cluster in cluster_list:
scheduler = cluster.scheduler
all_with_details[cluster.get_cluster_ip()] = {"scheduler_ip": scheduler.ip,
"scheduler_name": scheduler.description}
# Send dictionary of new cluster data and list of existing inactive autoblocks to update
return redirect('add_auto_block_bulk', kwargs=all_with_details)
activate_autoblock_selected_action.short_description = "Activate autoblock on selected objects"
views.py
@require_http_methods(["POST"])
@csrf_exempt
def add_auto_block_bulk(request, **kwargs):
scaleio_build = ""
spark_test = ""
report_link = ""
error = ""
# launch form to get user input
form = AddUpdateAutoblockForm(request.POST)
# Verify form and collect user input
if form.is_valid():
scaleio_build = form.cleaned_data['scaleio_build']
spark_test = form.cleaned_data['spark_test']
report_link = form.cleaned_data['report_link']
error = form.cleaned_data['error']
try:
req_str = request.body.decode('utf-8').replace('\\', '')
body = json.loads(req_str)
# Populate list of new AutoBlock objects including user data and selection data
autoblocks = [AutoBlock(cluster_ip=cluster,
scheduler_name=details["scheduler_name"],
scheduler_ip=details["scheduler_ip"],
scaleio_build=scaleio_build,
spark_test=spark_test,
report_link=report_link,
error=error) for cluster, details in kwargs["items_to_add"].items()]
# create new AutoBlock entries in the database
new_auto_block = AutoBlock.objects.bulk_create(autoblocks)
new_auto_block.save()
add_sucess = True
# update existing inactive AutoBlock table entries to be active
AutoBlock.objects.bulk_update(kwargs["objects_to_update"], ['active'])
return HttpResponse(status=200)
except Exception as e:
if add_sucess:
log_warning_response("Failed to add auto blocks, exp {}".format(str(e)), 400)
else:
log_warning_response("Failed to update auto block, exp {}".format(str(e)), 400)
return HttpResponse(str(e), status=400)
else:
form = AddUpdateAutoblockForm()
return render(request, 'form_post_template.html', {'form': form})
forms.py - this excludes any fields that can’t apply to a bulk operation and sets dummy data for fields that require input. The dummy data will be replaced for each entry that is to be added to the db during the massaging of the data.
class AddUpdateAutoblockForm(ModelForm):
class Meta:
model = AutoBlock
exclude = ['scheduler_ip', 'scheduler_name', 'cluster_ip', 'active']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['cluster_ip'] = "1.1.1.1"
self.fields['active'] = True
form_post_template.html
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
urls.py
urlpatterns = [
path(r'add_auto_block_bulk/', views.add_auto_block_bulk),