示例#1
0
    def get_related_attrs_scan_count(cls, attr_names, queryset=None):
        """
    Calculates the total count for a combination of related attributes
    (``attr_names``).
    Results might be optionally limited using ``queryset``.

    Returns a ``len(attr_names)``-dimensional dict, one dimension
    per attribute name. Each leaf is a tuple with the count of the
    particular combination of attributes.

    Example::

      {
        <Tag: thriller>: {
          <Author: Stephen King>: 120
          },
          …
        },
        …
      },

    """
        objects = queryset or cls.objects
        objects = objects.select_related(*attr_names)

        # get a list (of dicts) with all object combinations and their counts
        attr_combinations_values = objects.values(*attr_names).annotate(count=models.Count("pk")).order_by()

        # a list of object lists, needed to determine possible object
        # combinations
        attrs_objects = [set(getattrs(objects, attr_name)) for attr_name in attr_names]

        # needed to lookup counts for certain object combinations
        counts_by_pk = values_to_hierarchical_dict(attr_combinations_values, attr_names)

        # needed to calculate percentiles (that's why it's already float)
        objects_count = float(len(objects))

        # if object combination does not exist, this information is provided:
        default_leaf = 0

        # assemble a complete hierarchical dictionary of possible
        # combinations of attributes, including their count and percentile
        out = HierarchicalOrderedDict()
        for combination in product(*attrs_objects):

            count_dict = counts_by_pk.get_by_path((getattr(o, "pk", None) for o in combination), None)

            if count_dict:
                count = count_dict["count"]
            else:
                count = default_leaf
            out.set_by_path(combination, count)

        return out
示例#2
0
 def lookups(self, request, model_admin):
   """
   Returns a list of tuples. The first element in each
   tuple will appear in the URL query (the PK of the related model).
   The second element is the human-readable name for the option that
   will appear in the right sidebar on the admin page (``str(obj)``).
   """
   scans = model_admin.resource_class._meta.model.objects.only(
     "%s_id" % attr_name, attr_name
   ).distinct(
   ).select_related(
     attr_name
   )
   components = set(getattrs(scans, attr_name))
   return [(getattr(c, "pk", None), str(c)) for c in components]
示例#3
0
    def get_related_attr_scan_intervals(cls, attr_name, queryset=None):
        """
    Creates a series of time deltas between scans, grouped by objects
    found under ``attr_name``. Results might be optionally limited using
    ``queryset``.

    Returns a dict with the related objects as keys and a list of tuples
    as value each. The tuples are filled with the timestamp and the
    ``timedelta`` to the previous scan.

    Example::

      {
        <Tag: thriller>: [
          (datetime(…), timedelta(…)),
          (datetime(…), timedelta(…)),
        ],
        …
      }
    """

        objects = queryset or cls.objects
        objects = objects.only("timestamp", attr_name).select_related(attr_name).order_by("timestamp")

        # initialize with empty lists (avoids cumbersome checks below)
        attr_objects = objects.only(attr_name).distinct()
        all_series = {o: [] for o in getattrs(attr_objects, attr_name)}

        for scan in objects:
            timestamp = scan.timestamp
            attr_object = getattr(scan, attr_name)
            inner_series = all_series.get(attr_object)
            if inner_series:
                last_timestamp = inner_series[-1][0]
                delta = timestamp - last_timestamp
            else:
                delta = timedelta()
            inner_series.append((timestamp, delta))

        return all_series