如何将django中Count()的输出转换为django 1.8中的FloatField

如何将django中Count()的输出转换为django 1.8中的FloatField,django,django-models,django-orm,Django,Django Models,Django Orm,我正在使用django 1.8 我有两种型号: 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.Floa

我正在使用django 1.8

我有两种型号:

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')
现在我想根据“标记数”和查询的“post_分数”之和对查询进行排序。 我在找这样的东西:-

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')

在django 1.10中提供。那么我可以使用什么替代方案呢

正如我在评论中所说,您可以简单地复制
Cast
类的源代码,并将其保存在项目中并使用它

结果不是那么简单。您还需要更改强制转换.as\u sql。而且,无需对
Func.as\u sql
进行
super
调用

只需复制以下代码并将其保存在项目中。我已经测试过了,效果很好

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__()'s **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')

正如您在django 1.10的问题中提到的,您可以使用内置的Cast函数。对于旧版本,您可以使用


您可以将
Cast
定义为

def Cast(what, as_type):
    if isinstance(as_type, Field):
        as_type = as_type.db_type(connection)
    return Func(
        what,
        template='%(function)s(%(expressions)s AS %(type)s)',
        function='Cast',
        type=as_type,
    )

它是开源的。您只需复制并将其保存在项目中的文件中即可。我尝试过这样做,但它给了我一个错误:
TypeError:as\u sql()得到了一个意外的关键字参数“db\u type”
我对源代码进行了一些修改,并在答案中添加了它。希望有帮助。它显示了一个错误
FieldError:表达式包含混合类型。您必须设置output_field
使用ExpressionWrapper包装F对象的总和应该可以解决此问题。现在试试看。
def Cast(what, as_type):
    if isinstance(as_type, Field):
        as_type = as_type.db_type(connection)
    return Func(
        what,
        template='%(function)s(%(expressions)s AS %(type)s)',
        function='Cast',
        type=as_type,
    )