Пример #1
0
    def test_select_field(self):

        obj_type = ContentType.objects.get_for_model(Site)

        # Create a custom field
        cf = CustomField(type=CF_TYPE_SELECT, name='my_field', required=False)
        cf.save()
        cf.obj_type = [obj_type]
        cf.save()

        # Create some choices for the field
        CustomFieldChoice.objects.bulk_create([
            CustomFieldChoice(field=cf, value='Option A'),
            CustomFieldChoice(field=cf, value='Option B'),
            CustomFieldChoice(field=cf, value='Option C'),
        ])

        # Assign a value to the first Site
        site = Site.objects.first()
        cfv = CustomFieldValue(field=cf, obj_type=obj_type, obj_id=site.id)
        cfv.value = cf.choices.first()
        cfv.save()

        # Retrieve the stored value
        cfv = CustomFieldValue.objects.filter(obj_type=obj_type, obj_id=site.pk).first()
        self.assertEqual(str(cfv.value), 'Option A')

        # Delete the stored value
        cfv.value = None
        cfv.save()
        self.assertEqual(CustomFieldValue.objects.filter(obj_type=obj_type, obj_id=site.pk).count(), 0)

        # Delete the custom field
        cf.delete()
Пример #2
0
    def test_get_obj_with_custom_fields(self):

        CUSTOM_FIELD_VALUES = [
            (self.cf_text, 'Test string'),
            (self.cf_integer, 1234),
            (self.cf_boolean, True),
            (self.cf_date, date(2016, 6, 23)),
            (self.cf_url, 'http://example.com/'),
            (self.cf_select, self.cf_select_choice1.pk),
        ]
        for field, value in CUSTOM_FIELD_VALUES:
            cfv = CustomFieldValue(field=field, obj=self.site)
            cfv.value = value
            cfv.save()

        url = reverse('dcim-api:site-detail', kwargs={'pk': self.site.pk})
        response = self.client.get(url, **self.header)

        self.assertEqual(response.data['name'], self.site.name)
        self.assertEqual(response.data['custom_fields'].get('magic_word'),
                         CUSTOM_FIELD_VALUES[0][1])
        self.assertEqual(response.data['custom_fields'].get('magic_number'),
                         CUSTOM_FIELD_VALUES[1][1])
        self.assertEqual(response.data['custom_fields'].get('is_magic'),
                         CUSTOM_FIELD_VALUES[2][1])
        self.assertEqual(response.data['custom_fields'].get('magic_date'),
                         CUSTOM_FIELD_VALUES[3][1])
        self.assertEqual(response.data['custom_fields'].get('magic_url'),
                         CUSTOM_FIELD_VALUES[4][1])
        self.assertEqual(response.data['custom_fields'].get('magic_choice'), {
            'value': self.cf_select_choice1.pk,
            'label': 'Foo'
        })
Пример #3
0
    def test_select_field(self):

        obj_type = ContentType.objects.get_for_model(Site)

        # Create a custom field
        cf = CustomField(type=CustomFieldTypeChoices.TYPE_SELECT, name='my_field', required=False)
        cf.save()
        cf.obj_type.set([obj_type])
        cf.save()

        # Create some choices for the field
        CustomFieldChoice.objects.bulk_create([
            CustomFieldChoice(field=cf, value='Option A'),
            CustomFieldChoice(field=cf, value='Option B'),
            CustomFieldChoice(field=cf, value='Option C'),
        ])

        # Assign a value to the first Site
        site = Site.objects.first()
        cfv = CustomFieldValue(field=cf, obj_type=obj_type, obj_id=site.id)
        cfv.value = cf.choices.first()
        cfv.save()

        # Retrieve the stored value
        cfv = CustomFieldValue.objects.filter(obj_type=obj_type, obj_id=site.pk).first()
        self.assertEqual(str(cfv.value), 'Option A')

        # Delete the stored value
        cfv.value = None
        cfv.save()
        self.assertEqual(CustomFieldValue.objects.filter(obj_type=obj_type, obj_id=site.pk).count(), 0)

        # Delete the custom field
        cf.delete()
Пример #4
0
    def test_get_obj_with_custom_fields(self):

        CUSTOM_FIELD_VALUES = [
            (self.cf_text, 'Test string'),
            (self.cf_integer, 1234),
            (self.cf_boolean, True),
            (self.cf_date, date(2016, 6, 23)),
            (self.cf_url, 'http://example.com/'),
            (self.cf_select, self.cf_select_choice1.pk),
        ]
        for field, value in CUSTOM_FIELD_VALUES:
            cfv = CustomFieldValue(field=field, obj=self.site)
            cfv.value = value
            cfv.save()

        url = reverse('dcim-api:site-detail', kwargs={'pk': self.site.pk})
        response = self.client.get(url, **self.header)

        self.assertEqual(response.data['name'], self.site.name)
        self.assertEqual(response.data['custom_fields'].get('magic_word'), CUSTOM_FIELD_VALUES[0][1])
        self.assertEqual(response.data['custom_fields'].get('magic_number'), CUSTOM_FIELD_VALUES[1][1])
        self.assertEqual(response.data['custom_fields'].get('is_magic'), CUSTOM_FIELD_VALUES[2][1])
        self.assertEqual(response.data['custom_fields'].get('magic_date'), CUSTOM_FIELD_VALUES[3][1])
        self.assertEqual(response.data['custom_fields'].get('magic_url'), CUSTOM_FIELD_VALUES[4][1])
        self.assertEqual(response.data['custom_fields'].get('magic_choice'), {
            'value': self.cf_select_choice1.pk, 'label': 'Foo'
        })
Пример #5
0
    def save_coords(self, request):
        results = {}
        if settings.PLUGINS_CONFIG["netbox_topology_views"][
                "allow_coordinates_saving"]:
            try:
                cfCoords = CustomField.objects.get(name='coordinates')
            except CustomField.DoesNotExist:
                results["status"] = "coords custom field not created"
                return Response(status=500)

            obj_type = ContentType.objects.get_for_model(Device)

            device_id = None
            x_coord = None
            y_coord = None
            if "node_id" in request.data:
                if request.data["node_id"]:
                    device_id = request.data["node_id"]
            if "x" in request.data:
                if request.data["x"]:
                    x_coord = request.data["x"]
            if "y" in request.data:
                if request.data["y"]:
                    y_coord = request.data["y"]

            actual_device = Device.objects.get(id=device_id)
            try:
                cfvCoords = CustomFieldValue.objects.get(
                    obj_type=obj_type,
                    obj_id=actual_device.pk,
                    field__name='coordinates')
                cfvCoords.value = "%s;%s" % (x_coord, y_coord)
                cfvCoords.save()
                results["status"] = "coords set"
            except CustomFieldValue.DoesNotExist:
                cfvCoords = CustomFieldValue(field=cfCoords,
                                             obj_type=obj_type,
                                             obj_id=actual_device.id)
                cfvCoords.value = "%s;%s" % (x_coord, y_coord)
                cfvCoords.save()
                results["status"] = "coords set for first time"

            return Response(results)
        else:
            results["status"] = "not allowed to save coords"
            return Response(results, status=500)
Пример #6
0
    def test_simple_fields(self):

        DATA = (
            {'field_type': CF_TYPE_TEXT, 'field_value': 'Foobar!', 'empty_value': ''},
            {'field_type': CF_TYPE_INTEGER, 'field_value': 0, 'empty_value': None},
            {'field_type': CF_TYPE_INTEGER, 'field_value': 42, 'empty_value': None},
            {'field_type': CF_TYPE_BOOLEAN, 'field_value': True, 'empty_value': None},
            {'field_type': CF_TYPE_BOOLEAN, 'field_value': False, 'empty_value': None},
            {'field_type': CF_TYPE_DATE, 'field_value': date(
                2016, 6, 23), 'empty_value': None},
            {'field_type': CF_TYPE_URL,
                'field_value': 'http://example.com/', 'empty_value': ''},
        )

        obj_type = ContentType.objects.get_for_model(Site)

        for data in DATA:

            # Create a custom field
            cf = CustomField(type=data['field_type'],
                             name='my_field', required=False)
            cf.save()
            cf.obj_type = [obj_type]
            cf.save()

            # Assign a value to the first Site
            site = Site.objects.first()
            cfv = CustomFieldValue(field=cf, obj_type=obj_type, obj_id=site.id)
            cfv.value = data['field_value']
            cfv.save()

            # Retrieve the stored value
            cfv = CustomFieldValue.objects.filter(
                obj_type=obj_type, obj_id=site.pk).first()
            self.assertEqual(cfv.value, data['field_value'])

            # Delete the stored value
            cfv.value = data['empty_value']
            cfv.save()
            self.assertEqual(CustomFieldValue.objects.filter(
                obj_type=obj_type, obj_id=site.pk).count(), 0)

            # Delete the custom field
            cf.delete()
Пример #7
0
    def test_simple_fields(self):

        DATA = (
            {'field_type': CF_TYPE_TEXT, 'field_value': 'Foobar!', 'empty_value': ''},
            {'field_type': CF_TYPE_INTEGER, 'field_value': 0, 'empty_value': None},
            {'field_type': CF_TYPE_INTEGER, 'field_value': 42, 'empty_value': None},
            {'field_type': CF_TYPE_BOOLEAN, 'field_value': True, 'empty_value': None},
            {'field_type': CF_TYPE_BOOLEAN, 'field_value': False, 'empty_value': None},
            {'field_type': CF_TYPE_DATE, 'field_value': date(2016, 6, 23), 'empty_value': None},
            {'field_type': CF_TYPE_URL, 'field_value': 'http://example.com/', 'empty_value': ''},
        )

        obj_type = ContentType.objects.get_for_model(Site)

        for data in DATA:

            # Create a custom field
            cf = CustomField(type=data['field_type'], name='my_field', required=False)
            cf.save()
            cf.obj_type = [obj_type]
            cf.save()

            # Assign a value to the first Site
            site = Site.objects.first()
            cfv = CustomFieldValue(field=cf, obj_type=obj_type, obj_id=site.id)
            cfv.value = data['field_value']
            cfv.save()

            # Retrieve the stored value
            cfv = CustomFieldValue.objects.filter(obj_type=obj_type, obj_id=site.pk).first()
            self.assertEqual(cfv.value, data['field_value'])

            # Delete the stored value
            cfv.value = data['empty_value']
            cfv.save()
            self.assertEqual(CustomFieldValue.objects.filter(obj_type=obj_type, obj_id=site.pk).count(), 0)

            # Delete the custom field
            cf.delete()
Пример #8
0
    def post(self, request, **kwargs):
        logger = logging.getLogger('netbox.views.BulkEditView')
        model = self.queryset.model

        # If we are editing *all* objects in the queryset, replace the PK list with all matched objects.
        if request.POST.get('_all') and self.filterset is not None:
            pk_list = [
                obj.pk for obj in self.filterset(request.GET,
                                                 model.objects.only('pk')).qs
            ]
        else:
            pk_list = request.POST.getlist('pk')

        if '_apply' in request.POST:
            form = self.form(model, request.POST)

            if form.is_valid():
                logger.debug("Form validation was successful")
                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 + ['pk']
                ]
                nullified_fields = request.POST.getlist('_nullify')

                try:

                    with transaction.atomic():

                        updated_count = 0
                        for obj in model.objects.filter(
                                pk__in=form.cleaned_data['pk']):

                            # Update standard fields. If a field is listed in _nullify, delete its value.
                            for name in standard_fields:

                                try:
                                    model_field = model._meta.get_field(name)
                                except FieldDoesNotExist:
                                    # This form field is used to modify a field rather than set its value directly
                                    model_field = None

                                # Handle nullification
                                if name in form.nullable_fields and name in nullified_fields:
                                    if isinstance(model_field,
                                                  ManyToManyField):
                                        getattr(obj, name).set([])
                                    else:
                                        setattr(
                                            obj, name,
                                            None if model_field.null else '')

                                # ManyToManyFields
                                elif isinstance(model_field, ManyToManyField):
                                    getattr(obj,
                                            name).set(form.cleaned_data[name])

                                # Normal fields
                                elif form.cleaned_data[name] not in (None, ''):
                                    setattr(obj, name, form.cleaned_data[name])

                            obj.full_clean()
                            obj.save()
                            logger.debug(f"Saved {obj} (PK: {obj.pk})")

                            # Update custom fields
                            obj_type = ContentType.objects.get_for_model(model)
                            for name in custom_fields:
                                field = form.fields[name].model
                                if name in form.nullable_fields and name in nullified_fields:
                                    CustomFieldValue.objects.filter(
                                        field=field,
                                        obj_type=obj_type,
                                        obj_id=obj.pk).delete()
                                elif form.cleaned_data[name] not in [None, '']:
                                    try:
                                        cfv = CustomFieldValue.objects.get(
                                            field=field,
                                            obj_type=obj_type,
                                            obj_id=obj.pk)
                                    except CustomFieldValue.DoesNotExist:
                                        cfv = CustomFieldValue(
                                            field=field,
                                            obj_type=obj_type,
                                            obj_id=obj.pk)
                                    cfv.value = form.cleaned_data[name]
                                    cfv.save()
                            logger.debug(
                                f"Saved custom fields for {obj} (PK: {obj.pk})"
                            )

                            # Add/remove tags
                            if form.cleaned_data.get('add_tags', None):
                                obj.tags.add(*form.cleaned_data['add_tags'])
                            if form.cleaned_data.get('remove_tags', None):
                                obj.tags.remove(
                                    *form.cleaned_data['remove_tags'])

                            updated_count += 1

                    if updated_count:
                        msg = 'Updated {} {}'.format(
                            updated_count, model._meta.verbose_name_plural)
                        logger.info(msg)
                        messages.success(self.request, msg)

                    return redirect(self.get_return_url(request))

                except ValidationError as e:
                    messages.error(self.request,
                                   "{} failed validation: {}".format(obj, e))

            else:
                logger.debug("Form validation failed")

        else:
            # Include the PK list as initial data for the form
            initial_data = {'pk': pk_list}

            # Check for other contextual data needed for the form. We avoid passing all of request.GET because the
            # filter values will conflict with the bulk edit form fields.
            # TODO: Find a better way to accomplish this
            if 'device' in request.GET:
                initial_data['device'] = request.GET.get('device')
            elif 'device_type' in request.GET:
                initial_data['device_type'] = request.GET.get('device_type')

            form = self.form(model, initial=initial_data)

        # Retrieve objects being edited
        table = self.table(self.queryset.filter(pk__in=pk_list),
                           orderable=False)
        if not table.rows:
            messages.warning(
                request,
                "No {} were selected.".format(model._meta.verbose_name_plural))
            return redirect(self.get_return_url(request))

        return render(
            request, self.template_name, {
                'form': form,
                'table': table,
                'obj_type_plural': model._meta.verbose_name_plural,
                'return_url': self.get_return_url(request),
            })
Пример #9
0
    def post(self, request, **kwargs):

        model = self.queryset.model

        # Create a mutable copy of the POST data
        post_data = request.POST.copy()

        # If we are editing *all* objects in the queryset, replace the PK list with all matched objects.
        if post_data.get('_all') and self.filterset is not None:
            post_data['pk'] = [
                obj.pk for obj in self.filterset(request.GET,
                                                 model.objects.only('pk')).qs
            ]

        if '_apply' in request.POST:
            form = self.form(model, request.POST)
            if form.is_valid():

                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 + ['pk']
                ]
                nullified_fields = request.POST.getlist('_nullify')

                try:

                    with transaction.atomic():

                        updated_count = 0
                        for obj in model.objects.filter(
                                pk__in=form.cleaned_data['pk']):

                            # Update standard fields. If a field is listed in _nullify, delete its value.
                            for name in standard_fields:

                                try:
                                    model_field = model._meta.get_field(name)
                                except FieldDoesNotExist:
                                    # This form field is used to modify a field rather than set its value directly
                                    model_field = None

                                # Handle nullification
                                if name in form.nullable_fields and name in nullified_fields:
                                    if isinstance(model_field,
                                                  ManyToManyField):
                                        getattr(obj, name).set([])
                                    else:
                                        setattr(
                                            obj, name,
                                            None if model_field.null else '')

                                # ManyToManyFields
                                elif isinstance(model_field, ManyToManyField):
                                    getattr(obj,
                                            name).set(form.cleaned_data[name])

                                # Normal fields
                                elif form.cleaned_data[name] not in (None, ''):
                                    setattr(obj, name, form.cleaned_data[name])

                            obj.full_clean()
                            obj.save()

                            # Update custom fields
                            obj_type = ContentType.objects.get_for_model(model)
                            for name in custom_fields:
                                field = form.fields[name].model
                                if name in form.nullable_fields and name in nullified_fields:
                                    CustomFieldValue.objects.filter(
                                        field=field,
                                        obj_type=obj_type,
                                        obj_id=obj.pk).delete()
                                elif form.cleaned_data[name] not in [None, '']:
                                    try:
                                        cfv = CustomFieldValue.objects.get(
                                            field=field,
                                            obj_type=obj_type,
                                            obj_id=obj.pk)
                                    except CustomFieldValue.DoesNotExist:
                                        cfv = CustomFieldValue(
                                            field=field,
                                            obj_type=obj_type,
                                            obj_id=obj.pk)
                                    cfv.value = form.cleaned_data[name]
                                    cfv.save()

                            # Add/remove tags
                            if form.cleaned_data.get('add_tags', None):
                                obj.tags.add(*form.cleaned_data['add_tags'])
                            if form.cleaned_data.get('remove_tags', None):
                                obj.tags.remove(
                                    *form.cleaned_data['remove_tags'])

                            updated_count += 1

                    if updated_count:
                        msg = 'Updated {} {}'.format(
                            updated_count, model._meta.verbose_name_plural)
                        messages.success(self.request, msg)

                    return redirect(self.get_return_url(request))

                except ValidationError as e:
                    messages.error(self.request,
                                   "{} failed validation: {}".format(obj, e))

        else:
            # Pass the PK list as initial data to avoid binding the form
            initial_data = querydict_to_dict(post_data)
            form = self.form(model, initial=initial_data)

        # Retrieve objects being edited
        table = self.table(
            self.queryset.filter(pk__in=post_data.getlist('pk')),
            orderable=False)
        if not table.rows:
            messages.warning(
                request,
                "No {} were selected.".format(model._meta.verbose_name_plural))
            return redirect(self.get_return_url(request))

        return render(
            request, self.template_name, {
                'form': form,
                'table': table,
                'obj_type_plural': model._meta.verbose_name_plural,
                'return_url': self.get_return_url(request),
            })
Пример #10
0
    def post(self, request, **kwargs):

        # Attempt to derive parent object if a parent class has been given
        if self.parent_cls:
            parent_obj = get_object_or_404(self.parent_cls, **kwargs)
        else:
            parent_obj = None

        # Determine URL to redirect users upon modification of objects
        posted_return_url = request.POST.get('return_url')
        if posted_return_url and is_safe_url(url=posted_return_url,
                                             host=request.get_host()):
            return_url = posted_return_url
        elif parent_obj:
            return_url = parent_obj.get_absolute_url()
        else:
            return_url = reverse(self.default_return_url)

        # Are we editing *all* objects in the queryset or just a selected subset?
        if request.POST.get('_all') and self.filter is not None:
            pk_list = [
                obj.pk for obj in self.filter(request.GET,
                                              self.cls.objects.only('pk')).qs
            ]
        else:
            pk_list = [int(pk) for pk in request.POST.getlist('pk')]

        if '_apply' in request.POST:
            form = self.form(self.cls, parent_obj, request.POST)
            if form.is_valid():

                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'
                ]
                nullified_fields = request.POST.getlist('_nullify')

                try:

                    with transaction.atomic():

                        updated_count = 0
                        for obj in self.cls.objects.filter(pk__in=pk_list):

                            # Update standard fields. If a field is listed in _nullify, delete its value.
                            for name in standard_fields:
                                if name in form.nullable_fields and name in nullified_fields:
                                    setattr(
                                        obj, name, '' if isinstance(
                                            form.fields[name], CharField) else
                                        None)
                                elif form.cleaned_data[name] not in (None, ''):
                                    setattr(obj, name, form.cleaned_data[name])
                            obj.full_clean()
                            obj.save()

                            # Update custom fields
                            obj_type = ContentType.objects.get_for_model(
                                self.cls)
                            for name in custom_fields:
                                field = form.fields[name].model
                                if name in form.nullable_fields and name in nullified_fields:
                                    CustomFieldValue.objects.filter(
                                        field=field,
                                        obj_type=obj_type,
                                        obj_id=obj.pk).delete()
                                elif form.cleaned_data[name] not in [None, '']:
                                    try:
                                        cfv = CustomFieldValue.objects.get(
                                            field=field,
                                            obj_type=obj_type,
                                            obj_id=obj.pk)
                                    except CustomFieldValue.DoesNotExist:
                                        cfv = CustomFieldValue(
                                            field=field,
                                            obj_type=obj_type,
                                            obj_id=obj.pk)
                                    cfv.value = form.cleaned_data[name]
                                    cfv.save()

                            updated_count += 1

                    if updated_count:
                        msg = '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(return_url)

                except ValidationError as e:
                    messages.error(self.request,
                                   "{} failed validation: {}".format(obj, e))

        else:
            initial_data = request.POST.copy()
            initial_data['pk'] = pk_list
            form = self.form(self.cls, parent_obj, initial=initial_data)

        # Retrieve objects being edited
        queryset = self.queryset or self.cls.objects.all()
        table = self.table(queryset.filter(pk__in=pk_list), orderable=False)
        if not table.rows:
            messages.warning(
                request, "No {} were selected.".format(
                    self.cls._meta.verbose_name_plural))
            return redirect(return_url)

        return render(
            request, self.template_name, {
                'form': form,
                'table': table,
                'obj_type_plural': self.cls._meta.verbose_name_plural,
                'return_url': return_url,
            })
Пример #11
0
    def setUpTestData(cls):
        content_type = ContentType.objects.get_for_model(Site)

        # Text custom field
        cls.cf_text = CustomField(type=CustomFieldTypeChoices.TYPE_TEXT,
                                  name='text_field',
                                  default='foo')
        cls.cf_text.save()
        cls.cf_text.obj_type.set([content_type])

        # Integer custom field
        cls.cf_integer = CustomField(type=CustomFieldTypeChoices.TYPE_INTEGER,
                                     name='number_field',
                                     default=123)
        cls.cf_integer.save()
        cls.cf_integer.obj_type.set([content_type])

        # Boolean custom field
        cls.cf_boolean = CustomField(type=CustomFieldTypeChoices.TYPE_BOOLEAN,
                                     name='boolean_field',
                                     default=False)
        cls.cf_boolean.save()
        cls.cf_boolean.obj_type.set([content_type])

        # Date custom field
        cls.cf_date = CustomField(type=CustomFieldTypeChoices.TYPE_DATE,
                                  name='date_field',
                                  default='2020-01-01')
        cls.cf_date.save()
        cls.cf_date.obj_type.set([content_type])

        # URL custom field
        cls.cf_url = CustomField(type=CustomFieldTypeChoices.TYPE_URL,
                                 name='url_field',
                                 default='http://example.com/1')
        cls.cf_url.save()
        cls.cf_url.obj_type.set([content_type])

        # Select custom field
        cls.cf_select = CustomField(type=CustomFieldTypeChoices.TYPE_SELECT,
                                    name='choice_field')
        cls.cf_select.save()
        cls.cf_select.obj_type.set([content_type])
        cls.cf_select_choice1 = CustomFieldChoice(field=cls.cf_select,
                                                  value='Foo')
        cls.cf_select_choice1.save()
        cls.cf_select_choice2 = CustomFieldChoice(field=cls.cf_select,
                                                  value='Bar')
        cls.cf_select_choice2.save()
        cls.cf_select_choice3 = CustomFieldChoice(field=cls.cf_select,
                                                  value='Baz')
        cls.cf_select_choice3.save()

        cls.cf_select.default = cls.cf_select_choice1.value
        cls.cf_select.save()

        # Create some sites
        cls.sites = (
            Site(name='Site 1', slug='site-1'),
            Site(name='Site 2', slug='site-2'),
        )
        Site.objects.bulk_create(cls.sites)

        # Assign custom field values for site 2
        site2_cfvs = {
            cls.cf_text: 'bar',
            cls.cf_integer: 456,
            cls.cf_boolean: True,
            cls.cf_date: '2020-01-02',
            cls.cf_url: 'http://example.com/2',
            cls.cf_select: cls.cf_select_choice2.pk,
        }
        for field, value in site2_cfvs.items():
            cfv = CustomFieldValue(field=field, obj=cls.sites[1])
            cfv.value = value
            cfv.save()
Пример #12
0
    def post(self, request, **kwargs):

        model = self.queryset.model

        # Attempt to derive parent object if a parent class has been given
        if self.parent_model:
            parent_obj = get_object_or_404(self.parent_model, **kwargs)
        else:
            parent_obj = None

        # Are we editing *all* objects in the queryset or just a selected subset?
        if request.POST.get('_all') and self.filterset is not None:
            pk_list = [obj.pk for obj in self.filterset(request.GET, model.objects.only('pk')).qs]
        else:
            pk_list = [int(pk) for pk in request.POST.getlist('pk')]

        if '_apply' in request.POST:
            form = self.form(model, parent_obj, request.POST)
            if form.is_valid():

                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']
                nullified_fields = request.POST.getlist('_nullify')

                try:

                    with transaction.atomic():

                        updated_count = 0
                        for obj in model.objects.filter(pk__in=pk_list):

                            # Update standard fields. If a field is listed in _nullify, delete its value.
                            for name in standard_fields:
                                if name in form.nullable_fields and name in nullified_fields and isinstance(form.cleaned_data[name], QuerySet):
                                    getattr(obj, name).set([])
                                elif name in form.nullable_fields and name in nullified_fields:
                                    setattr(obj, name, '' if isinstance(form.fields[name], CharField) else None)
                                elif isinstance(form.cleaned_data[name], QuerySet) and form.cleaned_data[name]:
                                    getattr(obj, name).set(form.cleaned_data[name])
                                elif form.cleaned_data[name] not in (None, '') and not isinstance(form.cleaned_data[name], QuerySet):
                                    setattr(obj, name, form.cleaned_data[name])
                            obj.full_clean()
                            obj.save()

                            # Update custom fields
                            obj_type = ContentType.objects.get_for_model(model)
                            for name in custom_fields:
                                field = form.fields[name].model
                                if name in form.nullable_fields and name in nullified_fields:
                                    CustomFieldValue.objects.filter(
                                        field=field, obj_type=obj_type, obj_id=obj.pk
                                    ).delete()
                                elif form.cleaned_data[name] not in [None, '']:
                                    try:
                                        cfv = CustomFieldValue.objects.get(
                                            field=field, obj_type=obj_type, obj_id=obj.pk
                                        )
                                    except CustomFieldValue.DoesNotExist:
                                        cfv = CustomFieldValue(
                                            field=field, obj_type=obj_type, obj_id=obj.pk
                                        )
                                    cfv.value = form.cleaned_data[name]
                                    cfv.save()

                            # Add/remove tags
                            if form.cleaned_data.get('add_tags', None):
                                obj.tags.add(*form.cleaned_data['add_tags'])
                            if form.cleaned_data.get('remove_tags', None):
                                obj.tags.remove(*form.cleaned_data['remove_tags'])

                            updated_count += 1

                    if updated_count:
                        msg = 'Updated {} {}'.format(updated_count, model._meta.verbose_name_plural)
                        messages.success(self.request, msg)

                    return redirect(self.get_return_url(request))

                except ValidationError as e:
                    messages.error(self.request, "{} failed validation: {}".format(obj, e))

        else:
            initial_data = request.POST.copy()
            initial_data['pk'] = pk_list
            form = self.form(model, parent_obj, initial=initial_data)

        # Retrieve objects being edited
        table = self.table(self.queryset.filter(pk__in=pk_list), orderable=False)
        if not table.rows:
            messages.warning(request, "No {} were selected.".format(model._meta.verbose_name_plural))
            return redirect(self.get_return_url(request))

        return render(request, self.template_name, {
            'form': form,
            'table': table,
            'obj_type_plural': model._meta.verbose_name_plural,
            'return_url': self.get_return_url(request),
        })
Пример #13
0
    def post(self, request, **kwargs):

        # Attempt to derive parent object if a parent class has been given
        if self.parent_cls:
            parent_obj = get_object_or_404(self.parent_cls, **kwargs)
        else:
            parent_obj = None

        # Determine URL to redirect users upon modification of objects
        posted_return_url = request.POST.get('return_url')
        if posted_return_url and is_safe_url(url=posted_return_url, host=request.get_host()):
            return_url = posted_return_url
        elif parent_obj:
            return_url = parent_obj.get_absolute_url()
        else:
            return_url = reverse(self.default_return_url)

        # Are we editing *all* objects in the queryset or just a selected subset?
        if request.POST.get('_all') and self.filter is not None:
            pk_list = [obj.pk for obj in self.filter(request.GET, self.cls.objects.only('pk')).qs]
        else:
            pk_list = [int(pk) for pk in request.POST.getlist('pk')]

        if '_apply' in request.POST:
            form = self.form(self.cls, parent_obj, request.POST)
            if form.is_valid():

                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']
                nullified_fields = request.POST.getlist('_nullify')

                try:

                    with transaction.atomic():

                        updated_count = 0
                        for obj in self.cls.objects.filter(pk__in=pk_list):

                            # Update standard fields. If a field is listed in _nullify, delete its value.
                            for name in standard_fields:
                                if name in form.nullable_fields and name in nullified_fields:
                                    setattr(obj, name, '' if isinstance(form.fields[name], CharField) else None)
                                elif form.cleaned_data[name] not in (None, ''):
                                    setattr(obj, name, form.cleaned_data[name])
                            obj.full_clean()
                            obj.save()

                            # Update custom fields
                            obj_type = ContentType.objects.get_for_model(self.cls)
                            for name in custom_fields:
                                field = form.fields[name].model
                                if name in form.nullable_fields and name in nullified_fields:
                                    CustomFieldValue.objects.filter(
                                        field=field, obj_type=obj_type, obj_id=obj.pk
                                    ).delete()
                                elif form.cleaned_data[name] not in [None, '']:
                                    try:
                                        cfv = CustomFieldValue.objects.get(
                                            field=field, obj_type=obj_type, obj_id=obj.pk
                                        )
                                    except CustomFieldValue.DoesNotExist:
                                        cfv = CustomFieldValue(
                                            field=field, obj_type=obj_type, obj_id=obj.pk
                                        )
                                    cfv.value = form.cleaned_data[name]
                                    cfv.save()

                            updated_count += 1

                    if updated_count:
                        msg = '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(return_url)

                except ValidationError as e:
                    messages.error(self.request, "{} failed validation: {}".format(obj, e))

        else:
            initial_data = request.POST.copy()
            initial_data['pk'] = pk_list
            form = self.form(self.cls, parent_obj, initial=initial_data)

        # Retrieve objects being edited
        queryset = self.queryset or self.cls.objects.all()
        table = self.table(queryset.filter(pk__in=pk_list), orderable=False)
        if not table.rows:
            messages.warning(request, "No {} were selected.".format(self.cls._meta.verbose_name_plural))
            return redirect(return_url)

        return render(request, self.template_name, {
            'form': form,
            'table': table,
            'obj_type_plural': self.cls._meta.verbose_name_plural,
            'return_url': return_url,
        })