示例#1
0
文件: fields.py 项目: yxl201908/ralph
        def _get_inheritance_filters_for_single_instance(self):
            """
            Return queryset filter for CustomFieldValue with inheritance for
            single instance.

            Final format of queryset will look similar to:
            (Q(content_type_id=X) & Q(object_id=Y)) | (Q(content_type_id=A) & Q(object_id=B)) | ...  # noqa
            """
            inheritance_filters = [
                # custom field of instance
                models.Q(
                    **{self.content_type_field_name: self.content_type.id}) &
                # object id of instance
                models.Q(**{self.object_id_field_name: self.instance.id})
            ]
            # for each related field (foreign key), add it's content_type
            # and object_id to queryset filter
            for field_path in self.instance.custom_fields_inheritance:
                content_type = _get_content_type_from_field_path(
                    self.instance, field_path)
                value = getattr_dunder(self.instance, field_path)
                # filter only if related field has some value
                if value:
                    inheritance_filters.append(
                        models.Q(
                            **{self.content_type_field_name: content_type.id})
                        & models.Q(**{self.object_id_field_name: value.pk}))
            return reduce(operator.or_, inheritance_filters)
示例#2
0
    def prepare(self, model, *args, **kwargs):
        queryset = BaseObjectsSupport.objects.select_related(
            'support',
            'baseobject__asset__property_of',
            'baseobject__service_env__service'
        ).prefetch_related(
            # AttachmentItem is attached to BaseObject (by content type),
            # so we need to prefetch attachments through base object of support
            'support__baseobject_ptr__attachments__attachment',
            'support__baseobjectssupport_set',
        )
        headers = []
        select_related = []
        if model._meta.object_name == 'DataCenterAsset':
            headers = self.dc_headers
            select_related = self.dc_select_related
            queryset = queryset.filter(
                baseobject__content_type=ContentType.objects.get_for_model(
                    DataCenterAsset
                )
            )
        elif model._meta.object_name == 'BackOfficeAsset':
            headers = self.bo_headers
            select_related = self.bo_select_related
            queryset = queryset.filter(
                baseobject__content_type=ContentType.objects.get_for_model(
                    BackOfficeAsset
                )
            )

        yield headers + self.extra_headers
        for bos in queryset.select_related(*select_related):
            row = [str(getattr_dunder(bos, column)) for column in headers]
            row += self.get_extra_columns(bos)
            yield row
示例#3
0
文件: table.py 项目: yxl201908/ralph
    def get_field_value(self, item, field):
        """
        Returns the value for the given field name.

        Looking in:
            If the field is type Choices returns choice name
            else returns the value of row

        :param item: row from dict
        :param field: field name
        """
        value = None
        if hasattr(self, field):
            value = getattr(self, field)(item)
        else:
            value = getattr_dunder(item, field)
            try:
                choice_class = get_field_by_relation_path(
                    item._meta.model, field
                ).choices
            except FieldDoesNotExist:
                choice_class = None
            if (
                use_choices and choice_class and
                isinstance(choice_class, Choices)
            ):
                value = choice_class.name_from_id(value)
        return value
示例#4
0
    def report_failure(self, item):
        item_dict = model_to_dict(item)
        url = settings.MY_EQUIPMENT_REPORT_FAILURE_URL
        if url:
            placeholders = [
                k[1] for k in Formatter().parse(url) if k[1] is not None
            ]
            item_dict.update({
                k: getattr_dunder(item, k) for k in placeholders
            })
            if self.request and 'username' not in item_dict:
                item_dict['username'] = self.request.user.username

            def escape_param(p):
                """
                Escape URL param and replace quotation by unicode inches sign
                """
                return quote(str(p).replace('"', '\u2033'))
            return '<a href="{}" target="_blank">{}</a><br />'.format(
                url.format(
                    **{k: escape_param(v) for (k, v) in item_dict.items()}
                ),
                _('Report failure')
            )
        return ''
示例#5
0
    def test_getattr_dunder(self):
        """getattr_dunder works recursively"""
        class A():
            pass

        a = A()
        a.b = A()
        a.b.name = 'spam'
        self.assertEqual(getattr_dunder(a, 'b__name'), 'spam')
示例#6
0
文件: models.py 项目: yuchunyun/ralph
 def clean(self):
     bo_asset = getattr_dunder(
         self.base_object, 'asset__backofficeasset'
     )
     if (
         bo_asset and self.licence and
         self.licence.region_id != bo_asset.region_id
     ):
         raise ValidationError(
             _('Asset region is in a different region than licence.')
         )
示例#7
0
    def prepare(self, model, *args, **kwargs):
        queryset = model.objects.prefetch_related('tags')
        headers = self.bo_headers
        select_related = self.bo_select_related
        if model._meta.object_name == 'DataCenterAsset':
            headers = self.dc_headers
            select_related = self.dc_select_related

        yield headers + self.extra_headers
        for asset in queryset.select_related(*select_related):
            row = [str(getattr_dunder(asset, column)) for column in headers]
            row += self.get_extra_columns(asset)
            yield row
示例#8
0
文件: admin.py 项目: helopng/ralph
    def create_report_link(self, url, url_title, item):
        item_dict = model_to_dict(item)
        if url:
            placeholders = [
                k[1] for k in Formatter().parse(url) if k[1] is not None
            ]
            item_dict.update(
                {k: getattr_dunder(item, k)
                 for k in placeholders})
            if self.request and 'username' not in item_dict:
                item_dict['username'] = self.request.user.username

            def escape_param(p):
                """
                Escape URL param and replace quotation by unicode inches sign
                """
                return quote_plus(quotation_to_inches(str(p)))

            return '<a href="{}" target="_blank">{}</a><br />'.format(
                url.format(
                    **{k: escape_param(v)
                       for (k, v) in item_dict.items()}), _(url_title))
        return ''
示例#9
0
    def prepare(self, model, *args, **kwargs):
        queryset = Licence.objects.select_related('region', 'software')
        asset_related = [None]
        if model._meta.object_name == 'BackOfficeAsset':
            queryset = queryset.filter(
                software__asset_type__in=(
                    ObjectModelType.back_office, ObjectModelType.all
                )
            )
            asset_related = [
                'base_object__asset', 'base_object__asset__backofficeasset',
                'base_object__asset__backofficeasset__user',
                'base_object__asset__backofficeasset__owner',
                'base_object__asset__backofficeasset__region'
            ]
        if model._meta.object_name == 'DataCenterAsset':
            queryset = queryset.filter(
                software__asset_type=ObjectModelType.data_center
            )
            asset_related = [
                'base_object__asset',
                'base_object__asset__backofficeasset'
            ]

        fill_empty_assets = [''] * len(self.licences_asset_headers)
        fill_empty_licences = [''] * len(self.licences_users_headers)

        headers = self.licences_headers + self.licences_asset_headers + \
            self.licences_users_headers + ['single_cost']
        yield headers

        queryset = queryset.select_related(
            'software'
        ).prefetch_related(
            Prefetch(
                'licenceuser_set',
                queryset=LicenceUser.objects.select_related('user')
            ),
            Prefetch(
                'baseobjectlicence_set',
                queryset=BaseObjectLicence.objects.select_related(
                    *asset_related
                )
            )
        )

        for licence in queryset:
            row = [
                smart_str(getattr_dunder(licence, column))
                for column in self.licences_headers
            ]
            base_row = row

            row = row + fill_empty_assets + fill_empty_licences + ['']
            yield row
            if licence.number_bought > 0 and licence.price:
                single_licence_cost = str(
                    licence.price.amount / licence.number_bought
                )
            else:
                single_licence_cost = ''

            for asset in licence.baseobjectlicence_set.all():
                row = [
                    smart_str(
                        getattr_dunder(asset.base_object, column),
                    ) for column in self.licences_asset_headers
                ]
                yield base_row + row + fill_empty_licences + [
                    single_licence_cost
                ]
            for user in licence.licenceuser_set.all():
                row = [
                    smart_str(getattr_dunder(user, column))
                    for column in self.licences_users_headers
                ]
                yield base_row + fill_empty_assets + row + [
                    single_licence_cost
                ]
示例#10
0
文件: fields.py 项目: yxl201908/ralph
        def get_prefetch_queryset(self, instances, queryset=None):
            """
            Prefetch custom fields with inheritance of values for multiple
            instances.

            This implementation is one-big-workaround for Django's handling of
            prefetch_related (especially in
            django.db.models.query:prefetch_one_level)
            """
            if queryset is None:
                queryset = super().get_queryset().select_related(
                    'custom_field')

            queryset._add_hints(instance=instances[0])
            queryset = queryset.using(queryset._db or self._db)
            content_type = ContentType.objects.get_for_model(instances[0])
            # store possible content types of CustomFieldValue
            content_types = set([content_type])
            # store possible values of object id
            objects_ids = set()
            # mapping from instance id to content_type and object id of
            # dependent fields for inheritance
            instances_cfs = defaultdict(set)
            # process every instance (no inheritance here right now)
            for instance in instances:
                objects_ids.add(instance.pk)
                instances_cfs[instance.pk].add((content_type.pk, instance.pk))
            # process each dependent field from `custom_fields_inheritance`
            for field_path in self.instance.custom_fields_inheritance:
                # assume that field is foreign key
                content_type = _get_content_type_from_field_path(
                    self.instance, field_path)
                content_types.add(content_type)
                # for each instance, get value of this dependent field
                for instance in instances:
                    value = getattr_dunder(instance, field_path)
                    if value:
                        objects_ids.add(value.pk)
                        # store mapping from instance to content type and value
                        # of dependent field to know, which CustomFieldValue
                        # assign later to instance
                        instances_cfs[instance.pk].add(
                            (content_type.pk, value.pk))

            # filter by possible content types and objects ids
            # notice that thus this filter is not perfect (filter separately
            # for content types and for objects ids, without correlation
            # between particular content type and value), this simplify
            # (and speedup) query
            # alternative solution is to do something similar to fetching
            # custom fields for single instance: correlate content type with
            # possible values for this single content type, for example:
            # (Q(content_type_id=A) & Q(object_id__in=[B, C, D])) | (Q(content_type_id=X) & Q(object_id__in=[Y, Z])) | ... # noqa
            query = {
                '%s__in' % self.content_type_field_name: content_types,
                '%s__in' % self.object_id_field_name: set(objects_ids)
            }

            qs = list(queryset.filter(**query))

            # this fragment of code (at least similar one) is normally done in
            # Django's `prefetch_one_level`, but it does NOT handle M2M case
            # (that single prefetched object (in this case CustomFieldValue)
            # could be assigned to multiple instances - it works only with
            # many-to-one case)

            # mapping from content_type and object_id to `CustomFieldValue`s
            rel_obj_cache = defaultdict(list)
            for rel_obj in qs:
                rel_obj_cache[(rel_obj.content_type_id,
                               rel_obj.object_id)].append(rel_obj)

            # for each instance reconstruct it's CustomFieldValues
            # using `instances_cfs` mapping (from instance pk to content_type
            # and object_id of possible CustomFieldValue)
            for obj in instances:
                vals = []
                # fetch `CustomFieldsValue`s for this instance - use mapping
                # from instance pk to content type id and object id of it's
                # dependent fields
                for content_type_id, obj_id in instances_cfs[obj.id]:
                    try:
                        vals.extend(rel_obj_cache[(content_type_id, obj_id)])
                    except KeyError:
                        # ignore if there is no CustomFieldValue for such
                        # content_type_id and object_id
                        pass

                vals = [
                    v[1] for v in _prioritize_custom_field_values(
                        vals, self.instance, self.content_type)
                ]

                # store `CustomFieldValue`s of instance in cache
                instance_custom_fields_queryset = obj.custom_fields.all()
                instance_custom_fields_queryset._result_cache = vals
                instance_custom_fields_queryset._prefetch_done = True
                obj._prefetched_objects_cache[
                    self.prefetch_cache_name] = instance_custom_fields_queryset

            # main "hack" for Django - since all querysets are already
            # prefetched, `prefetch_one_level` has nothing to do, thus
            # `rel_obj_attr` and `instance_attr` (second and third item)
            # returns constant value, to not assign it to any object.
            return (
                qs,
                lambda relobj: None,
                lambda obj: -1,
                # most important part of this workaround - return single=True,
                # to force `prefetch_one_level` to just do setattr to instance
                # under returned cache_name (suffixed with '__empty' below)
                True,
                # cache_name is also changed to not assign empty result
                # to `custom_fields` (and overwrite prefetched custom fields
                # assigned above)
                self.prefetch_cache_name + '__empty')