How to draw Count () output in django for FloatField in django 1.8

I am using django 1.8.

I have two models: -

class Query(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL)
    title = models.TextField()
    details = models.TextField()
    pub_date = models.DateTimeField('date published')
    post_score=models.FloatField(default=0.0)
    ....

class Tags(models.Model):
    """docstring for Tags"""
    tagname=models.TextField()
grouppostlist=models.ManyToManyField(Query,through='GroupPostsTag',through_fields=('tag','query'))

# and another model(it stores tags for a query)

class GroupPostsTag(models.Model):
    query=models.ForeignKey('Query')
    tag=models.models.ForeignKey('Tags')

      

Now I want to sort requests based on the sum of the "number of tags" and the request "post_score". I'm looking for something like this: -

tagged_user_posts = Query.objects.filter(Q(tags__id__in=tags_list)).annotate(num_tags=Cast(Count('tags'),models.FloatField())).annotate(post_scores=F('num_tags')+F('post_score')).order_by('-post_scores')

      

Cast is provided in django 1.10. So what alternative can I use?

+3


source to share


2 answers


As I said in my comment, you can just copy the source code of the class Cast

and save it in your projects and use it.

It turns out it wasn't that easy. You will also need to change it Cast.as_sql

as shown in v1.10 . And you don't need to call super

on Func.as_sql

.



Just copy the following code and save it in your project. I tested it and it works.

from django.db.models import Func, fields


class Cast(Func):
    """
    Coerce an expression to a new field type.
    """
    function = 'CAST'
    template = '%(function)s(%(expressions)s AS %(db_type)s)'

    mysql_types = {
        fields.CharField: 'char',
        fields.IntegerField: 'signed integer',
        fields.FloatField: 'signed',
    }

    def __init__(self, expression, output_field):
        super(Cast, self).__init__(expression, output_field=output_field)

    def as_sql(self, compiler, connection, function=None, template=None, arg_joiner=None, **extra_context):
        if 'db_type' not in extra_context:
            extra_context['db_type'] = self._output_field.db_type(connection)
        connection.ops.check_expression_support(self)
        sql_parts = []
        params = []
        for arg in self.source_expressions:
            arg_sql, arg_params = compiler.compile(arg)
            sql_parts.append(arg_sql)
            params.extend(arg_params)
        data = self.extra.copy()
        data.update(**extra_context)
        # Use the first supplied value in this order: the parameter to this
        # method, a value supplied in __init__() **extra (the value in
        # `data`), or the value defined on the class.
        if function is not None:
            data['function'] = function
        else:
            data.setdefault('function', self.function)
        template = template or data.get('template', self.template)
        arg_joiner = arg_joiner or data.get('arg_joiner', self.arg_joiner)
        data['expressions'] = data['field'] = arg_joiner.join(sql_parts)
        return template % data, params


    def as_mysql(self, compiler, connection):
        extra_context = {}
        output_field_class = type(self._output_field)
        if output_field_class in self.mysql_types:
            extra_context['db_type'] = self.mysql_types[output_field_class]
        return self.as_sql(compiler, connection, **extra_context)

    def as_postgresql(self, compiler, connection):
        # CAST would be valid too, but the :: shortcut syntax is more readable.
        return self.as_sql(compiler, connection, template='%(expressions)s::%(db_type)s')

      

+3


source


As you mentioned in the django 1.10 question, you can use the built-in Cast function. For older versions, you can use the Func () expression



from django.db.models import Count, Func, F, ExpressionWrapper, FloatField
tagged_user_posts = Query.objects.filter(Q(tags__id__in=tags_list)).
    annotate(num_tags=Func(Count('tags'), 
                           template='%(function)s(%(expressions)s AS %(type)s)', 
                           function='Cast', 
                           type='float')
    ).
    annotate(post_scores=ExpressionWrapper(F('num_tags')+F('post_score'), output_field=FloatField())).
    order_by('-post_scores')

      

+1


source







All Articles