Django外键关联表的相互查询与JSON序列化详解

Leo
Leo
发布时间:2026-10-13 | 5人浏览过
原创

本文详细解析Django中拥有外键关系的两张表如何进行相互查找。通过示例演示如何利用双下划线语法进行正向查询,以及使用_set属性进行反向查询。此外,文章还解决了Python原生json模块无法直接编码datetime等复杂对象的问题,提供了使用Django serializers模块和编写自定义JSONEncoder两种解决方案,确保数据能正确序列化为JSON格式。

Django外键关联表的双向查询

本文主要介绍在Django框架中,当两张表存在外键关联时,如何实现双向的数据查找。文中通过具体的代码示例进行了详细阐述,对读者的学习或实际工作具有参考价值。

核心问题在于:当两张表通过外键建立联系后,如何在一端表中根据另一端表的属性,筛选出满足特定条件的对象集合?

通常情况下,查询表内数据的条件使用的是Python内置数据类型,可以直接通过字段名进行检索。但如果查询条件涉及外键所指向的另一张表的特定列,应当如何执行查询操作?

假设存在两张表:表1为新闻表(News),它是回复表(Reply)中外键字段指向的目标表;表2为回复表(Reply)。

问题1:如何根据表1(新闻表)的某些条件,来查找表2(回复表)中对应的对象集合?


class News(models.Model):
 title = models.CharField(max_length=50);
 summary = models.TextField();
 
 url = models.CharField(max_length=150);
 favorCount = models.IntegerField(default=0);
 favorUsername = models.TextField(default="");
 replyCount = models.IntegerField(default=0);

class Reply(models.Model):
 content = models.TextField();
 user = models.ForeignKey('User');
 newID = models.ForeignKey('News');
 replyTime = models.DateTimeField(auto_now_add=True);
 
 def __unicode__(self):
  return self.content;

例如,面对如下数据结构,我们需要查找所有新闻ID为3的回复记录。

方法一:首先获取外键指向的目标表对象,然后利用“_set”属性来获取目标表中的数据。


obj = models.News.objects.get(id=3)
replys = obj.reply_set.all()

方法二:直接在目标表中,通过双下划线语法指定外键对应表中的字段来进行查找,从而获取符合条件的对象。


models.Reply.objects.filter(newID__id=3)

问题2:如何根据表2(回复表)的某些条件,查找表1(新闻表)中的对象集合?此时,需要将表2的名字小写后加上两个下划线,再跟上查找条件。例如:查找所有回复内容中包含“new”字符串的新闻。

models.News.objects.filter(reply__content__contains='new');

这种语法既可以在filter过滤器中使用,也可以在values方法中使用。在values中使用时,返回的值即为外键对应表中的数据。

Django数据JSON序列化解决方案

2. 在使用Django开发时,不可避免要与前端进行数据交互。由于Python数据类型丰富,例如datetime模块中的datetime类型无法直接被json编码。若需继续以JSON格式进行格式化,可采用以下两种方法解决。

1)使用Django提供的序列化功能。

2)自行编写编码器或默认处理函数。

注意:Python原生json模块仅能编码Python内置的数据类型,如数字、字符串、元组、列表、字典等。在Django处理数据时,常遇到QuerySet类型的数据,需先将其转换为列表再进行json编码,即使用[list(queryset)]。方法一:利用Django核心提供的serializers.serialize方法,通常使用json格式调用serializers.serialize('json', data),可方便地将Django中的各种数据类型编码为JSON格式。

方法二:自行编写编码器或编写默认处理函数。

1) 编写自己的编码器类。


class MyJSONEncoder(json.JSONEncoder):
 def default(self, obj):
  if isinstance(obj, datetime.datetime):
   return (datetime.timedelta(hours=8)+obj).strftime('%Y-%m-%d %H:%M:%S');
  elif isinstance(obj, datetime.date):
   return obj.strftime("%Y-%m-%d")
  else:
   return json.JSONEncoder.default(self, obj)

2) 编写自己的默认处理函数。


def myDumps(obj):
 if isinstance(obj, datetime.datetime):
  return (datetime.timedelta(hours=8)+obj).strftime('%Y-%m-%d %H:%M:%S');
 else:
  return json.dumps(obj);

对上述代码进行测试。


t = datetime.datetime.utcnow();
 a=[1,2,43,56]; 
 print json.dumps(t,default=myDumps);
 print json.dumps(a,default=myDumps);
 a.extend([t,t+datetime.timedelta(hours=8)]);
 print json.dumps(t,default=myDumps);
 print json.dumps(a,cls=MyJSONEncoder);

测试结果如下。


"2016-06-26 09:53:03"
[1, 2, 43, 56]
"2016-06-26 09:53:03"
[1, 2, 43, 56, "2016-06-26 09:53:03", "2016-06-26 17:53:03"]

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表