mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Added bulk editing capability for custom fields
This commit is contained in:
@ -66,15 +66,6 @@ class ProviderBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
template_name = 'circuits/provider_bulk_edit.html'
|
||||
default_redirect_url = 'circuits:provider_list'
|
||||
|
||||
def update_objects(self, pk_list, form):
|
||||
|
||||
fields_to_update = {}
|
||||
for field in ['asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments']:
|
||||
if form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
|
||||
return self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
||||
|
||||
|
||||
class ProviderBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'circuits.delete_provider'
|
||||
@ -159,19 +150,6 @@ class CircuitBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
template_name = 'circuits/circuit_bulk_edit.html'
|
||||
default_redirect_url = 'circuits:circuit_list'
|
||||
|
||||
def update_objects(self, pk_list, form):
|
||||
|
||||
fields_to_update = {}
|
||||
if form.cleaned_data['tenant'] == 0:
|
||||
fields_to_update['tenant'] = None
|
||||
elif form.cleaned_data['tenant']:
|
||||
fields_to_update['tenant'] = form.cleaned_data['tenant']
|
||||
for field in ['type', 'provider', 'port_speed', 'commit_rate', 'comments']:
|
||||
if form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
|
||||
return self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
||||
|
||||
|
||||
class CircuitBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'circuits.delete_circuit'
|
||||
|
@ -3,7 +3,7 @@ import re
|
||||
from django import forms
|
||||
from django.db.models import Count, Q
|
||||
|
||||
from extras.forms import CustomFieldForm
|
||||
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm
|
||||
from ipam.models import IPAddress
|
||||
from tenancy.forms import bulkedit_tenant_choices
|
||||
from tenancy.models import Tenant
|
||||
@ -112,7 +112,7 @@ class SiteImportForm(BulkImportForm, BootstrapMixin):
|
||||
csv = CSVDataField(csv_form=SiteFromCSVForm)
|
||||
|
||||
|
||||
class SiteBulkEditForm(forms.Form, BootstrapMixin):
|
||||
class SiteBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
||||
pk = forms.ModelMultipleChoiceField(queryset=Site.objects.all(), widget=forms.MultipleHiddenInput)
|
||||
tenant = forms.TypedChoiceField(choices=bulkedit_tenant_choices, coerce=int, required=False, label='Tenant')
|
||||
|
||||
|
@ -122,16 +122,6 @@ class SiteBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
template_name = 'dcim/site_bulk_edit.html'
|
||||
default_redirect_url = 'dcim:site_list'
|
||||
|
||||
def update_objects(self, pk_list, form):
|
||||
|
||||
fields_to_update = {}
|
||||
if form.cleaned_data['tenant'] == 0:
|
||||
fields_to_update['tenant'] = None
|
||||
elif form.cleaned_data['tenant']:
|
||||
fields_to_update['tenant'] = form.cleaned_data['tenant']
|
||||
|
||||
return self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
||||
|
||||
|
||||
#
|
||||
# Rack groups
|
||||
@ -248,20 +238,6 @@ class RackBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
template_name = 'dcim/rack_bulk_edit.html'
|
||||
default_redirect_url = 'dcim:rack_list'
|
||||
|
||||
def update_objects(self, pk_list, form):
|
||||
|
||||
fields_to_update = {}
|
||||
for field in ['group', 'tenant', 'role']:
|
||||
if form.cleaned_data[field] == 0:
|
||||
fields_to_update[field] = None
|
||||
elif form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
for field in ['site', 'type', 'width', 'u_height', 'comments']:
|
||||
if form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
|
||||
return self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
||||
|
||||
|
||||
class RackBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'dcim.delete_rack'
|
||||
@ -372,15 +348,6 @@ class DeviceTypeBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
template_name = 'dcim/devicetype_bulk_edit.html'
|
||||
default_redirect_url = 'dcim:devicetype_list'
|
||||
|
||||
def update_objects(self, pk_list, form):
|
||||
|
||||
fields_to_update = {}
|
||||
for field in ['manufacturer', 'u_height']:
|
||||
if form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
|
||||
return self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
||||
|
||||
|
||||
class DeviceTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'dcim.delete_devicetype'
|
||||
@ -682,23 +649,6 @@ class DeviceBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
template_name = 'dcim/device_bulk_edit.html'
|
||||
default_redirect_url = 'dcim:device_list'
|
||||
|
||||
def update_objects(self, pk_list, form):
|
||||
|
||||
fields_to_update = {}
|
||||
for field in ['tenant', 'platform']:
|
||||
if form.cleaned_data[field] == 0:
|
||||
fields_to_update[field] = None
|
||||
elif form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
if form.cleaned_data['status']:
|
||||
status = form.cleaned_data['status']
|
||||
fields_to_update['status'] = True if status == 'True' else False
|
||||
for field in ['tenant', 'device_type', 'device_role', 'serial']:
|
||||
if form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
|
||||
return self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
||||
|
||||
|
||||
class DeviceBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'dcim.delete_device'
|
||||
|
@ -4,19 +4,12 @@ from django.contrib.contenttypes.models import ContentType
|
||||
from .models import CF_TYPE_BOOLEAN, CF_TYPE_DATE, CF_TYPE_INTEGER, CF_TYPE_SELECT, CustomField, CustomFieldValue
|
||||
|
||||
|
||||
class CustomFieldForm(forms.ModelForm):
|
||||
custom_fields = []
|
||||
def get_custom_fields_for_model(content_type, bulk_editing=False):
|
||||
"""Retrieve all CustomFields applicable to the given ContentType"""
|
||||
field_dict = {}
|
||||
custom_fields = CustomField.objects.filter(obj_type=content_type)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super(CustomFieldForm, self).__init__(*args, **kwargs)
|
||||
|
||||
obj_type = ContentType.objects.get_for_model(self._meta.model)
|
||||
|
||||
# Find all CustomFields for this model
|
||||
custom_fields = CustomField.objects.filter(obj_type=obj_type)
|
||||
for cf in custom_fields:
|
||||
|
||||
field_name = 'cf_{}'.format(str(cf.name))
|
||||
|
||||
# Integer
|
||||
@ -25,10 +18,12 @@ class CustomFieldForm(forms.ModelForm):
|
||||
|
||||
# Boolean
|
||||
elif cf.type == CF_TYPE_BOOLEAN:
|
||||
if cf.required:
|
||||
field = forms.BooleanField(required=False, initial=bool(cf.default))
|
||||
else:
|
||||
field = forms.NullBooleanField(required=False, initial=bool(cf.default))
|
||||
choices = (
|
||||
(None, '---------'),
|
||||
(True, 'True'),
|
||||
(False, 'False'),
|
||||
)
|
||||
field = forms.NullBooleanField(required=cf.required, widget=forms.Select(choices=choices))
|
||||
|
||||
# Date
|
||||
elif cf.type == CF_TYPE_DATE:
|
||||
@ -36,6 +31,13 @@ class CustomFieldForm(forms.ModelForm):
|
||||
|
||||
# Select
|
||||
elif cf.type == CF_TYPE_SELECT:
|
||||
choices = [(cfc.pk, cfc) for cfc in cf.choices.all()]
|
||||
if not cf.required:
|
||||
choices = [(0, 'None')] + choices
|
||||
if bulk_editing:
|
||||
choices = [(None, '---------')] + choices
|
||||
field = forms.TypedChoiceField(choices=choices, coerce=int, required=cf.required)
|
||||
else:
|
||||
field = forms.ModelChoiceField(queryset=cf.choices.all(), required=cf.required)
|
||||
|
||||
# Text
|
||||
@ -45,35 +47,45 @@ class CustomFieldForm(forms.ModelForm):
|
||||
field.model = cf
|
||||
field.label = cf.label if cf.label else cf.name.capitalize()
|
||||
field.help_text = cf.description
|
||||
self.fields[field_name] = field
|
||||
self.custom_fields.append(field_name)
|
||||
|
||||
field_dict[field_name] = field
|
||||
|
||||
return field_dict
|
||||
|
||||
|
||||
class CustomFieldForm(forms.ModelForm):
|
||||
custom_fields = []
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
self.obj_type = ContentType.objects.get_for_model(self._meta.model)
|
||||
|
||||
super(CustomFieldForm, self).__init__(*args, **kwargs)
|
||||
|
||||
# Add all applicable CustomFields to the form
|
||||
for name, field in get_custom_fields_for_model(self.obj_type).items():
|
||||
self.fields[name] = field
|
||||
self.custom_fields.append(name)
|
||||
|
||||
# If editing an existing object, initialize values for all custom fields
|
||||
if self.instance.pk:
|
||||
existing_values = CustomFieldValue.objects.filter(obj_type=obj_type, obj_id=self.instance.pk)\
|
||||
existing_values = CustomFieldValue.objects.filter(obj_type=self.obj_type, obj_id=self.instance.pk)\
|
||||
.select_related('field')
|
||||
for cfv in existing_values:
|
||||
self.initial['cf_{}'.format(str(cfv.field.name))] = cfv.value
|
||||
|
||||
def _save_custom_fields(self):
|
||||
|
||||
if self.instance.pk:
|
||||
obj_type = ContentType.objects.get_for_model(self.instance)
|
||||
|
||||
for field_name in self.custom_fields:
|
||||
|
||||
try:
|
||||
cfv = CustomFieldValue.objects.get(field=self.fields[field_name].model, obj_type=obj_type,
|
||||
cfv = CustomFieldValue.objects.get(field=self.fields[field_name].model, obj_type=self.obj_type,
|
||||
obj_id=self.instance.pk)
|
||||
except CustomFieldValue.DoesNotExist:
|
||||
cfv = CustomFieldValue(
|
||||
field=self.fields[field_name].model,
|
||||
obj_type=obj_type,
|
||||
obj_type=self.obj_type,
|
||||
obj_id=self.instance.pk
|
||||
)
|
||||
if cfv.pk and self.cleaned_data[field_name] is None:
|
||||
cfv.delete()
|
||||
elif self.cleaned_data[field_name] is not None:
|
||||
cfv.value = self.cleaned_data[field_name]
|
||||
cfv.save()
|
||||
|
||||
@ -87,3 +99,19 @@ class CustomFieldForm(forms.ModelForm):
|
||||
self.save_custom_fields = self._save_custom_fields
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
class CustomFieldBulkEditForm(forms.Form):
|
||||
custom_fields = []
|
||||
|
||||
def __init__(self, model, *args, **kwargs):
|
||||
|
||||
self.obj_type = ContentType.objects.get_for_model(model)
|
||||
|
||||
super(CustomFieldBulkEditForm, self).__init__(*args, **kwargs)
|
||||
|
||||
# Add all applicable CustomFields to the form
|
||||
for name, field in get_custom_fields_for_model(self.obj_type, bulk_editing=True).items():
|
||||
field.required = False
|
||||
self.fields[name] = field
|
||||
self.custom_fields.append(name)
|
||||
|
@ -131,14 +131,22 @@ class CustomFieldValue(models.Model):
|
||||
if self.field.type == CF_TYPE_INTEGER:
|
||||
self.val_int = value
|
||||
elif self.field.type == CF_TYPE_BOOLEAN:
|
||||
self.val_int = bool(value) if value else None
|
||||
self.val_int = int(bool(value)) if value is not None else None
|
||||
elif self.field.type == CF_TYPE_DATE:
|
||||
self.val_date = value
|
||||
elif self.field.type == CF_TYPE_SELECT:
|
||||
self.val_int = value.id
|
||||
# Could be ModelChoiceField or TypedChoiceField
|
||||
self.val_int = value.id if hasattr(value, 'id') else value
|
||||
else:
|
||||
self.val_char = value
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if (self.field.type == CF_TYPE_TEXT and self.value == '') or self.value is None:
|
||||
if self.pk:
|
||||
self.delete()
|
||||
else:
|
||||
super(CustomFieldValue, self).save(*args, **kwargs)
|
||||
|
||||
|
||||
class CustomFieldChoice(models.Model):
|
||||
field = models.ForeignKey('CustomField', related_name='choices', limit_choices_to={'type': CF_TYPE_SELECT},
|
||||
|
@ -136,19 +136,6 @@ class VRFBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
template_name = 'ipam/vrf_bulk_edit.html'
|
||||
default_redirect_url = 'ipam:vrf_list'
|
||||
|
||||
def update_objects(self, pk_list, form):
|
||||
|
||||
fields_to_update = {}
|
||||
if form.cleaned_data['tenant'] == 0:
|
||||
fields_to_update['tenant'] = None
|
||||
elif form.cleaned_data['tenant']:
|
||||
fields_to_update['tenant'] = form.cleaned_data['tenant']
|
||||
for field in ['description']:
|
||||
if form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
|
||||
return self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
||||
|
||||
|
||||
class VRFBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'ipam.delete_vrf'
|
||||
@ -261,15 +248,6 @@ class AggregateBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
template_name = 'ipam/aggregate_bulk_edit.html'
|
||||
default_redirect_url = 'ipam:aggregate_list'
|
||||
|
||||
def update_objects(self, pk_list, form):
|
||||
|
||||
fields_to_update = {}
|
||||
for field in ['rir', 'date_added', 'description']:
|
||||
if form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
|
||||
return self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
||||
|
||||
|
||||
class AggregateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'ipam.delete_aggregate'
|
||||
@ -401,20 +379,6 @@ class PrefixBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
template_name = 'ipam/prefix_bulk_edit.html'
|
||||
default_redirect_url = 'ipam:prefix_list'
|
||||
|
||||
def update_objects(self, pk_list, form):
|
||||
|
||||
fields_to_update = {}
|
||||
for field in ['vrf', 'tenant']:
|
||||
if form.cleaned_data[field] == 0:
|
||||
fields_to_update[field] = None
|
||||
elif form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
for field in ['site', 'status', 'role', 'description']:
|
||||
if form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
|
||||
return self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
||||
|
||||
|
||||
class PrefixBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'ipam.delete_prefix'
|
||||
@ -527,20 +491,6 @@ class IPAddressBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
template_name = 'ipam/ipaddress_bulk_edit.html'
|
||||
default_redirect_url = 'ipam:ipaddress_list'
|
||||
|
||||
def update_objects(self, pk_list, form):
|
||||
|
||||
fields_to_update = {}
|
||||
for field in ['vrf', 'tenant']:
|
||||
if form.cleaned_data[field] == 0:
|
||||
fields_to_update[field] = None
|
||||
elif form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
for field in ['description']:
|
||||
if form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
|
||||
return self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
||||
|
||||
|
||||
class IPAddressBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'ipam.delete_ipaddress'
|
||||
@ -629,19 +579,6 @@ class VLANBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
template_name = 'ipam/vlan_bulk_edit.html'
|
||||
default_redirect_url = 'ipam:vlan_list'
|
||||
|
||||
def update_objects(self, pk_list, form):
|
||||
|
||||
fields_to_update = {}
|
||||
if form.cleaned_data['tenant'] == 0:
|
||||
fields_to_update['tenant'] = None
|
||||
elif form.cleaned_data['tenant']:
|
||||
fields_to_update['tenant'] = form.cleaned_data['tenant']
|
||||
for field in ['site', 'group', 'status', 'role', 'description']:
|
||||
if form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
|
||||
return self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
||||
|
||||
|
||||
class VLANBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'ipam.delete_vlan'
|
||||
|
@ -205,15 +205,6 @@ class SecretBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
template_name = 'secrets/secret_bulk_edit.html'
|
||||
default_redirect_url = 'secrets:secret_list'
|
||||
|
||||
def update_objects(self, pk_list, form):
|
||||
|
||||
fields_to_update = {}
|
||||
for field in ['role', 'name']:
|
||||
if form.cleaned_data[field]:
|
||||
fields_to_update[field] = form.cleaned_data[field]
|
||||
|
||||
return self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
||||
|
||||
|
||||
class SecretBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'secrets.delete_secret'
|
||||
|
@ -6,7 +6,7 @@
|
||||
{% block select_objects_table %}
|
||||
{% for site in selected_objects %}
|
||||
<tr>
|
||||
<td><a href="{% url 'dcim:site' slug=site.slug %}">{{ site.slug }}</a></td>
|
||||
<td><a href="{% url 'dcim:site' slug=site.slug %}">{{ site }}</a></td>
|
||||
<td>{{ site.tenant }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -8,7 +8,7 @@
|
||||
<tr>
|
||||
<td>{{ field }}</td>
|
||||
<td>
|
||||
{% if value %}
|
||||
{% if value != None %}
|
||||
{{ value }}
|
||||
{% elif field.required %}
|
||||
<span class="text-warning">Not defined</span>
|
||||
|
@ -107,16 +107,6 @@ class TenantBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||
template_name = 'tenancy/tenant_bulk_edit.html'
|
||||
default_redirect_url = 'tenancy:tenant_list'
|
||||
|
||||
def update_objects(self, pk_list, form):
|
||||
|
||||
fields_to_update = {}
|
||||
if form.cleaned_data['group'] == 0:
|
||||
fields_to_update['group'] = None
|
||||
elif form.cleaned_data['group']:
|
||||
fields_to_update['group'] = form.cleaned_data['group']
|
||||
|
||||
return self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
||||
|
||||
|
||||
class TenantBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||
permission_required = 'tenancy.delete_tenant'
|
||||
|
@ -7,7 +7,7 @@ from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import transaction, IntegrityError
|
||||
from django.db.models import ProtectedError
|
||||
from django.forms import ModelMultipleChoiceField, MultipleHiddenInput
|
||||
from django.forms import ModelMultipleChoiceField, MultipleHiddenInput, TypedChoiceField
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.template import TemplateSyntaxError
|
||||
@ -15,8 +15,8 @@ from django.utils.decorators import method_decorator
|
||||
from django.utils.http import is_safe_url
|
||||
from django.views.generic import View
|
||||
|
||||
from extras.forms import CustomFieldForm
|
||||
from extras.models import ExportTemplate, UserAction
|
||||
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm
|
||||
from extras.models import CustomField, CustomFieldValue, ExportTemplate, UserAction
|
||||
|
||||
from .error_handlers import handle_protectederror
|
||||
from .forms import ConfirmationForm
|
||||
@ -282,15 +282,31 @@ class BulkEditView(View):
|
||||
pk_list = request.POST.getlist('pk')
|
||||
|
||||
if '_apply' in request.POST:
|
||||
if hasattr(self.form, 'custom_fields'):
|
||||
form = self.form(self.cls, request.POST)
|
||||
else:
|
||||
form = self.form(request.POST)
|
||||
if form.is_valid():
|
||||
updated_count = self.update_objects(pk_list, form)
|
||||
|
||||
custom_fields = form.custom_fields if hasattr(form, 'custom_fields') else []
|
||||
standard_fields = [field for field in form.fields if field not in custom_fields and field != 'pk']
|
||||
|
||||
# Update objects
|
||||
updated_count = self.update_objects(pk_list, form, standard_fields)
|
||||
|
||||
# Update custom fields for objects
|
||||
if custom_fields:
|
||||
self.update_custom_fields(pk_list, form, custom_fields)
|
||||
|
||||
if updated_count:
|
||||
msg = u'Updated {} {}'.format(updated_count, self.cls._meta.verbose_name_plural)
|
||||
messages.success(self.request, msg)
|
||||
UserAction.objects.log_bulk_edit(request.user, ContentType.objects.get_for_model(self.cls), msg)
|
||||
return redirect(redirect_url)
|
||||
|
||||
else:
|
||||
if hasattr(self.form, 'custom_fields'):
|
||||
form = self.form(self.cls, initial={'pk': pk_list})
|
||||
else:
|
||||
form = self.form(initial={'pk': pk_list})
|
||||
|
||||
@ -305,11 +321,29 @@ class BulkEditView(View):
|
||||
'cancel_url': redirect_url,
|
||||
})
|
||||
|
||||
def update_objects(self, obj_list, form):
|
||||
"""
|
||||
This method provides the update logic (must be overridden by subclasses).
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
def update_objects(self, pk_list, form, fields):
|
||||
fields_to_update = {}
|
||||
|
||||
for name in fields:
|
||||
if isinstance(form.fields[name], TypedChoiceField) and form.cleaned_data[name] == 0:
|
||||
fields_to_update[name] = None
|
||||
elif form.cleaned_data[name]:
|
||||
fields_to_update[name] = form.cleaned_data[name]
|
||||
|
||||
return self.cls.objects.filter(pk__in=pk_list).update(**fields_to_update)
|
||||
|
||||
def update_custom_fields(self, pk_list, form, fields):
|
||||
obj_type = ContentType.objects.get_for_model(self.cls)
|
||||
|
||||
for name in fields:
|
||||
if form.cleaned_data[name] not in [None, u'']:
|
||||
for pk in pk_list:
|
||||
try:
|
||||
cfv = CustomFieldValue.objects.get(field=form.fields[name].model, obj_type=obj_type, obj_id=pk)
|
||||
except CustomFieldValue.DoesNotExist:
|
||||
cfv = CustomFieldValue(field=form.fields[name].model, obj_type=obj_type, obj_id=pk)
|
||||
cfv.value = form.cleaned_data[name]
|
||||
cfv.save()
|
||||
|
||||
|
||||
class BulkDeleteView(View):
|
||||
|
Reference in New Issue
Block a user