场景
在设计表结构时,难免需要建立一些外键关联。例如这样两个模型:
from django.db import models class Person(models.Model): username = models.CharField(max_length=100) birthdate = models.DateField() class Book(models.Model): name = models.CharField(max_length=100) author = models.ForeignKey(Person, on_delete=models.CASCADE)
表 Book 的字段 author 是表 Person 的外键,我们试用 Django 原生的 Serializer 模块来对 Book 实例序列化:
from django.core import serializers book_json = serializers.serialize("json", Book.objects.get(pk=1))
JSON 序列化结果如下:
{ "pk": 1, "model": "store.book", "fields": { "name": "Mostly Harmless", "author": 42 } }
这个 "author": 42 对用户来说相当于未知,我们需要的是 Person 表中主键为 42 的用户姓名,即 username 的值。
解决方案
在 Django 官方文档的「序列化」一节中提到了用 models.Manager 处理的方案;在搜索解决方案过程中,也接触到 Django-REST-Framework(DRF) ,了解到 DRF 中的 Serializer 模块也能解决这类问题。那我们不妨对比一下两种解决方案。
方案一:models.Manager
根据文档,要返回自然主键,我们需要定义一个模型管理器,创建一个 get_by_natural_key 方法,如下:
from django.db import models
from django.db import models class PersonManager(models.Manager): def get_by_natural_key(self, username): return self.get(username=username) class Person(models.Model): username = models.CharField(max_length=100) birthdate = models.DateField() objects = PersonManager()
然后再次序列化 Book 实例:
from django.core import serializers book_json = serializers.serialize("json", Book.objects.get(pk=1), use_natural_foreign_keys=True)
得到新的结果如下:
{
"pk": 1,
"model": "store.book",
"fields": {
"name": "Mostly Harmless",
"author": ["DouglasAdams"]
}
}
如果需要对其他应用的数据模型做修改,例如使用了 django.auth.User(默认认证后端)作为 Book 的外键,要想不修改 User 模型又使用新的模型管理器,可以使用代理模式完成:
from django.db import models class NewManager(models.Manager): # ... pass class MyPerson(Person): objects = NewManager() class Meta: proxy = True
总的来说,这个方案可以完美解决我所遇到的问题,代码量稍微大一些,但是也更灵活。
方案二:DRF 的 Serializer
下面我们试试用 Django-REST-Framework 的序列化模块:
from rest_framework import serializers from .models import Book class BookSerializer(serializers.ModelSerializer): author_name = serializers.CharField(source='author.username') class Meta: model = Book fields = '__all__'
这段代码表示,在序列化 Book 实例时,添加一个新的属性 author_name,该值的来源为 source 参数定义的外键 author 实例的自然主键 username。
然后是执行序列化的过程:
queryset = Book.objects.get(pk=1) BookSerializer(instance=queryset)
序列化结果:
{
"id": 1,
"name": "Mostly Harmless",
"author": 42,
"author_name": "DouglasAdams"
}
当然,序列化一批 Book 实例也是可以的:
queryset = Book.objects.all() BookSerializer(instance=queryset, many=True)
序列化结果:
[
{
"id": 1,
"name": "Mostly Harmless",
"author": 42,
"author_name": "DouglasAdams"
},
{
"id": 2,
"name": "Harry Potter",
"author": 2,
"author_name": "JKRowling"
}
]
可以看到,使用 DRF 的序列化模块返回自然主键,不仅代码清晰改动少,而且效果也很不错,序列化数据少了一个层级,对前端也是十分友好的。
方案三:手动修改序列化后的外键
当然,还有一种最傻也是最容易想到的办法,就是在序列化后,手动修改 JSON 串中对应的外键值为自然主键值。
这种做法可以得到和方案一一样的效果,但是遇到查询结果为列表时我们需要遍历替换。同时试想一下,如果我们在每个视图中都这么处理,那代码会变得十分糟糕。不建议使用该方案。
总结
对比两种序列化方案,我个人更偏向于 DRF 优雅的处理方式。当然,除了序列化,DRF 还有很多功能,例如分页等,强烈建议学习学习。
当然,可能不存在最好的最好的技术方案,遇到这类问题选择最合适自己的就好。也可能还有更多的方法可以解决标题的问题,也欢迎留言探讨!
参考
- docs.djangoproject.com/zh-hans/2.2…
- docs.djangoproject.com/en/2.2/topi…
- www.django-rest-framework.org/api-guide/f…
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
- 第五街的士高《印度激情版》3CD [WAV+CUE][2.4G]
- 三国志8重制版哪个武将智力高 三国志8重制版智力武将排行一览
- 三国志8重制版哪个武将好 三国志8重制版武将排行一览
- 三国志8重制版武将图像怎么保存 三国志8重制版武将图像设置方法
- 何方.1990-我不是那种人【林杰唱片】【WAV+CUE】
- 张惠妹.1999-妹力新世纪2CD【丰华】【WAV+CUE】
- 邓丽欣.2006-FANTASY【金牌大风】【WAV+CUE】
- 饭制《黑神话》蜘蛛四妹手办
- 《燕云十六声》回应跑路:年内公测版本完成95%
- 网友发现国内版《双城之战》第二季有删减:亲亲环节没了!
- 邓丽君2024-《漫步人生路》头版限量编号MQA-UHQCD[WAV+CUE]
- SergeProkofievplaysProkofiev[Dutton][FLAC+CUE]
- 永恒英文金曲精选4《TheBestOfEverlastingFavouritesVol.4》[WAV+CUE]
- 群星《国风超有戏 第9期》[320K/MP3][13.63MB]
- 群星《国风超有戏 第9期》[FLAC/分轨][72.56MB]