def get_queryset(self):
        # custom price order filter based on regular and discount price (if exists)
        qs = super().get_queryset()

        qs = qs.annotate(order_price=Case(
            When(discount_price__isnull=False,
                 then=functions.Cast("discount_price", models.FloatField())),
            default=functions.Cast("price", models.FloatField()),
        ))
        return qs
Example #2
0
def non_rf_indicator_queryset(program_id):
    """
    A QS of indicators to create the indicator plan from
    """
    return models.Indicator.objects.filter(
        program_id=program_id).select_related().with_logframe_sorting(
        ).order_by(
            'old_level_pk',
            'logsort_type',
            functions.Cast('logsort_a', IntegerField()),
            functions.Cast('logsort_b', IntegerField()),
            functions.Cast('logsort_c', IntegerField()),
        )
Example #3
0
 def get_queryset(self, request):
     return super().get_queryset(request).annotate(_name=functions.Concat(
         models.F('cellar'),
         models.Value(' '),
         functions.LPad(
             functions.Cast(models.F('number'),
                            output_field=models.CharField(
                                max_length=2)), 2, models.Value('0')),
         output_field=models.CharField(max_length=5)))
Example #4
0
def ranking_algorithm():
    # Based on Hacker News' post rank formula
    time_diff = functions.Cast(functions.Now() - F('created_time'),
                               fields.DurationField())
    hours = dtime.duration_to_hours(duration=time_diff)
    rank = ExpressionWrapper(
        (F('upvote') - F('devote') + 1) / ((hours + 2)**1.8),
        output_field=fields.FloatField())
    return hours, rank
 def get_data(self):
     time_query = self.time_range(self.now)
     tracks = Track.objects.filter(time_query.query, sport=self.sport)
     summary = tracks.values(
         time_query.time_aggregate).annotate(distance=functions.Cast(
             Sum(time_query.stat_query) / 1000, IntegerField()))
     x, y = time_query.fill_data(summary, time_query.time_aggregate,
                                 "distance")
     return [go.Bar(x=x, y=y, name=self.name)]
Example #6
0
def _ensure_resources(jwp_model, resource_queryset):
    """
    Given a model from mediaplatform_jwp and a queryset of CachedResource object corresponding to
    that model, make sure that objects of the appropriate model exist for each CachedResource
    object and that their updated timestamps are correct.

    Returns a list of all JWP resource keys for resources which were updated/created.
    """

    jwp_queryset = jwp_model.objects.all()

    # A query which returns all the cached video resources which do not correspond to an existing
    # JWP video.
    new_resources = (resource_queryset.exclude(
        key__in=jwp_queryset.values_list('key', flat=True)))

    # Start creating a list of all JWP video object which were touched in this update
    updated_jwp_keys = [v.key for v in new_resources.only('key')]

    # Bulk insert objects for all new resources.
    jwp_queryset.bulk_create([
        jwp_model(key=resource.key,
                  updated=resource.data.get('updated', 0),
                  resource=resource) for resource in new_resources
    ])

    # A subquery which returns the corresponding CachedResource's updated timestamp for a JWP
    # Video. We cannot simply use "data__updated" here because Django by design
    # (https://code.djangoproject.com/ticket/14104) does not support joined fields with update()
    # but the checks incorrectly interpret "data__updated" as a join and not a transform. Until
    # Django is fixed, we use a horrible workaround using RawSQL.  See
    # https://www.postgresql.org/docs/current/static/functions-json.html for the Postgres JSON
    # operators.
    matching_resource_updated = models.Subquery(
        resource_queryset.filter(key=models.OuterRef('key')).values_list(
            functions.Cast(expressions.RawSQL("data ->> 'updated'", []),
                           models.BigIntegerField()))[:1])

    # Add to our list of updated JWP videos
    updated_jwp_keys.extend([
        v.key for v in jwp_queryset.filter(
            updated__lt=matching_resource_updated).only('key')
    ])

    # For all objects whose corresponding CachedResource's updated field is later than the object's
    # updated field, update the object.
    (jwp_queryset.annotate(resource_updated=matching_resource_updated).filter(
        updated__lt=models.F('resource_updated')).update(
            updated=models.F('resource_updated')))

    return updated_jwp_keys
Example #7
0
    def ordered_media_item_queryset(self):
        """
        A queryset which returns the media items for the play list with the same ordering as
        :py:attr:`.media_items`.

        """
        all_media_items = (MediaItem.objects.filter(
            id__in=self.media_items).annotate(index=expressions.Func(
                models.Value(self.media_items),
                functions.Cast(models.F('id'),
                               output_field=models.TextField()),
                function='array_position')).order_by('index'))

        return all_media_items
Example #8
0
 def cast(self, to_type):
     """
     Coerce an expression to a new value type.
     """
     return functions.Cast(self._name, to_type)
Example #9
0
    def with_end_date(self):
        """
        Returns a :class:`QuerySet` where the :attr:`validity_end` date and the
        :attr:`valid_between` date range have been annotated onto the query.

        The resulting annotations can be queried on like fully materialised
        fields. E.g, it is possible to filter on the `valid_between` field.

        .. code-block:: python

            Model.objects.with_end_date().filter(
                valid_between__contains=date.today(),
            )
        """

        # Models with a single validity date always represent some feature of a
        # "parent model" and are only live for as long as that model is live.
        # The `over_field` is the field on this model that is a foreign key to
        # the "parent model". E.g. for a description it is the described model.
        over_field = self.model._meta.get_field(self.model.validity_over)

        # When we are working out the validity of the next mdoel, only models
        # for the same "parent model" are considered. So this partition selects
        # only the models that match on the same parent fields.
        partition = [
            models.F(f"{over_field.name}__{field}")
            for field in over_field.related_model.identifying_fields
        ]

        # To work out the end date efficiently an SQL window expression is used.
        # The rule for models with only a validity start date is that they are
        # valid up until the next model takes over. So this is the same as
        # ordering the models by their start dates and then takeing the start
        # date of the model that appears after this one.
        window = expressions.Window(
            expression=aggregates.Max("validity_start"),
            partition_by=partition,
            order_by=models.F("validity_start").asc(),
            frame=expressions.RowRange(start=0, end=1),
        )

        # If the value returned by the window expression is the same as the
        # model's own start date, that means there was no future model with a
        # later start date. Hence, this model is at the moment valid for
        # unlimited time. NULLIF returns NULL if the two values match. A day has
        # to be subtracted from the final result because the end date is one day
        # before the next start date.
        end_date_field = functions.Cast(
            functions.NullIf(window, models.F("validity_start")) - timedelta(days=1),
            models.DateField(),
        )

        # To allow the resulting field to be queried, this must be done as part
        # of a Common Table Expression (CTE) because window expressions cannot
        # appear in a WHERE clause.
        #
        # The end date and the start date are combined together into a single
        # DATERANGE field to allow using __contains operators.
        with_dates_added = With(
            self.annotate(
                validity_end=end_date_field,
                valid_between=models.Func(
                    models.F("validity_start"),
                    models.F("validity_end"),
                    expressions.Value("[]"),
                    function="DATERANGE",
                    output_field=TaricDateRangeField(),
                ),
            ),
        )

        return (
            with_dates_added.join(self.model, pk=with_dates_added.col.pk)
            .with_cte(with_dates_added)
            .annotate(
                validity_end=with_dates_added.col.validity_end,
                valid_between=with_dates_added.col.valid_between,
            )
        )
 def get_span_queryset(self, _period_step, start, end):
     qs = self.get_queryset().annotate(
         _date_field=db_functions.Cast(self.date_field, DateField()))
     kwargs = {'_date_field__gte': start, '_date_field__lt': end}
     return qs.filter(**kwargs)