Django 按通用外键排序
嘿,这里有个简单的问题。我有两个模型,分别是帖子(Post)和标签(Term),我想给帖子和将来的其他模型添加标签和分类(也就是分类法)。我的帖子模型有以下几个字段:标题(title)、内容(content)、发布时间(published),而我的标签模型是这样定义的:
class Term(models.Model):
taxonomy = models.CharField(max_length=255)
name = models.CharField(max_length=255)
slug = models.SlugField(max_length=50)
接着,我有一个标签关系模型(TermRelation),它把标签和帖子以及其他模型关联起来,像这样:
class TermRelation(models.Model):
term = models.ForeignKey(Term)
object_id = models.PositiveIntegerField()
content_type = models.ForeignKey(ContentType)
content_object = generic.GenericForeignKey()
一切都按预期工作,但我有个问题。我想创建一个特定分类的帖子归档,并按照发布时间对帖子进行排序。这是我想做的:
ctype = ContentType.objects.get_for_model(Post)
relations = TermRelation.objects.filter(content_type__pk=ctype.id)
这样做是可以的,虽然我猜它是按关系的主键(PK)排序的。当我尝试以下操作时:
relations = TermRelation.objects.filter(content_type__pk=ctype.id).order_by('content_object__published')
我收到一个错误,提示在标签关系模型中没有内容对象(content_object)字段。我知道一定有办法解决这个问题。有什么想法吗?
谢谢 ~ K
2 个回答
1
据我所知,这在Django中是做不到的,因为order_by
的参数会被转换成数据库中的列或表,而content_object
在数据库中并不存在。这个原因也是你需要通过对象ID和内容类型来查找内容类型的原因...
2
是的,我之前说的关于简单的SQL查询和连接的确是对的。实际上有几个连接。以下是我用的代码(适用于django >= 1.2的raw()
方法)
data = {
'posts': Post._meta.db_table,
'relations': TermRelation._meta.db_table,
'terms': Term._meta.db_table,
'tag_id': tag.id
}
posts = Post.objects.raw('SELECT %(posts)s.* FROM %(posts)s JOIN %(relations)s ON %(posts)s.id = %(relations)s.object_id JOIN %(terms)s ON %(relations)s.term_id = %(terms)s.id WHERE %(terms)s.id = %(tag_id)s ORDER BY %(posts)s.published DESC' % data)
其实并不难。也许我应该把它封装成一个TermRelation的方法,你觉得怎么样?
更新:我确实把它封装成了一个静态方法,并且让它可以处理不同的内容类型和排序方式。它仍然假设有一个叫做content_type_id的字段,如果有外键指向ContentType,这个字段会默认创建。以下是代码:
@staticmethod
def get_objects_by_term_id(model=None, taxonomy=None, term_id=None, order_by='NULL'):
data = {
'objects': model._meta.db_table,
'content_type': ContentType.objects.get_for_model(model).id,
'relations': TermRelation._meta.db_table,
'terms': Term._meta.db_table,
'term_id': term_id,
'order_by': ' ORDER BY %s ' % order_by
}
return model.objects.raw('SELECT %(objects)s.* FROM %(objects)s JOIN %(relations)s ON %(objects)s.id = %(relations)s.object_id AND %(relations)s.content_type_id = %(content_type)s JOIN %(terms)s ON %(relations)s.term_id = %(terms)s.id WHERE %(terms)s.id = %(term_id)s %(order_by)s' % data)