Django JSONField的自动转换(django自定义模型字段)

这篇具有很好参考价值的文章主要介绍了Django JSONField的自动转换(django自定义模型字段)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Django JSONField的自动转换(django自定义模型字段)

背景

Django v3.1的主要更新之一便是完善了对JSON数据存储的支持,新增models.JSONField和forms.JSONField,可在所有受支持的数据库后端上使用。

通过models.JSONField可指定此字段为存储类型为JSON格式。null=True表示此字段可以为空。

from django.db import models
 
class Hello(models.Model):
    name = models.CharField(max_length=200)
    data = models.JSONField(null=True)
 
    def __str__(self):
        return self.name

思路

如果您想实现JSONField的自动转换,可以使用Django REST framework的JSONField,或者自定义一个字段类并覆盖from_db_value()和get_prep_value()方法来实现这个功能。

DRF的JSONField更简单,但使用上相对复杂一些。自定义字段类的方法更轻量,但需要我们自己完成一定的编码工作。

这里推荐使用自定义字段类的方法!

使用DRF的JSONField

要使用DRF的JSONField,主要是在Serializer中导入并应用于需要自动转换JSON的字段,然后在视图进行序列化和反序列化,JSONField会自动完成与之相关的所有转换工作。

【不推荐】django自定义模型字段 @models.register_field()

@models.register_field()是一个模型注册装饰器。使用它可以注册自定义字段,使其可以像内置字段一样在模型中使用。

例如,使用了这个装饰器的JSONField可以在模型中像此使用:

class Product(models.Model):
    info = models.JSONField()  

而不用导入字段类:

from .fields import JSONField

class Product(models.Model):
    info = JSONField()

总结:这样的话,就不用单独导入字段类了(我们只需要在django启动入口的位置,如apps.py中 导入JSONField。目的是为了使用@models.register_field装饰器注册这个字段,使其在Django知道并可以在任何模型中像内置字段一样使用)。如果不使用这个装饰器,我们必须导入字段类后才能在模型中使用它。

另外,即使使用了@models.register_field装饰器,我们也可以直接导入JSONField字段类并在模型中使用。

举例:apps.py导入了,在具体的模型类中又单独引入了这个JSONField,用的是哪个?
在这种情况下,Django会使用您在模型中直接导入的JSONField字段类。
也就是说,apps.py中的导入会被忽略,模型中导入的字段类会生效并在模型中实际使用。

这是因为:

  1. Django会根据实际使用解析哪个字段类,而不是根据哪个被导入了。
  2. 如果同一个字段类被 imports 了两次,Python也只会使用最后一个导入的那个

使用@models.register_field()带来的好处是:

  1. 使自定义字段的使用看起来像内置字段,较为简洁直接,易于理解。
  2. 不用导入自定义字段类,模型可以独立定义,解耦了字段的导入依赖。
  3. 自动处理字段的参数,无需在模型中传递,使用起来像内置字段。
  4. 方便第三方库的集成,可直接在模型中使用第三方提供的自定义字段。

另外,需要注意的一点是,您使用了@models.register_field装饰器,将JSONField注册为了一个可以像内建字段一样使用的模型字段。
但是,Django在首次运行时需要导入这个字段类,才知道JSONField代表什么字段。
所以,您需要在首次使用JSONField的模型对应的apps.py中导入这个字段类。

经过测试Django-4.2.1,里没有register_field装饰器。

因此总结起来,直接定义自定义模型字段类,使用时单独引入即可,这样也不污染环境(不用在不用入口apps.py导一次,IDE还报灰色),即用即可,感觉更清晰。

【推荐】自定义一个字段类并覆盖from_db_value()和get_prep_value()方法

直接使用JSONField不会自动转换,是因为:

  • JSONField只是一个简单的继承自TextField的字段
  • 它本身并未实现from_db_value()和get_prep_value()方法
  • 所以当我们访问instance.JSONField时,得到的仅是JSON编码后的字符串,而非Python对象
  • 它也不会在保存实例时自动将Python对象重新转换为JSON字符串

覆盖模型字段的from_db_value()和get_prep_value()方法可以实现「自动转换」的效果。

  • from_db_value()方法用于数据库读取值时将值转换为Python对象
  • get_prep_value()方法用于数据库保存值前将Python对象转换为值
    通过覆盖这两个方法,我们可以实现自定义的转换逻辑,从而达到自动转换的效果。

实力demo

import json
from django.core import serializers
from django.core.exceptions import ValidationError
from django.db import models


class JSONField(models.TextField):
    description = 'JSON Encoded Data'

    def from_json(self, value):
        try:
            return json.loads(value)
        except ValueError:
            raise ValidationError('Invalid JSON')

    def to_json(self, value):

        return json.dumps(value, cls=serializers.json.DjangoJSONEncoder)

    def from_db_value(self, value, *args):
        if value == '':
            return None
        return self.from_json(value)

    def get_db_prep_save(self, value, *args, **kwargs):
        if isinstance(value, str):
            return value
        if value == "":
            return None
        return self.to_json(value)

    def save(self, *args, **kwargs):
        if self.value == '':
            self.value = None
        if self.value is None:
            self.value = json.dumps(None)
        return super().save(*args, **kwargs)
  • 在save()中对None值也进行判断,并转换为JSON null:
  • 在get_db_prep_save()中,使用了self.to_json()将值转换为JSON字符串进行存储。但如果字段值已经是字符串,则无需再次转换。 这个很重要,平时我们有时间业务代码,已经json.dumps了一次,变成了字符串。如果这里不判断,直接再json.dumps一次,到时候解析的时候发现解析出来还是字符串!

python使用模型使用 TextField字段,pg使用jsonb格式问题

jsonb对数据的检查是在 PostgreSQL 端完成的。
也就是说,即使你使用 Django 的 TextField 字段,数据实际上是以 JSONB 的格式存储在数据库中的。
PostgreSQL 在接受数据时,会对 JSON 数据进行检查:

  • 检查数据是否符合 JSON 语法
  • 检查数据类型是否合法(数值、字符串、对象、数组)
  • 检查数组元素是否一致
    只有通过检查的 JSON 数据才会被存储为 JSONB 格式。
    反之,如果 JSON 存在语法错误或类型错误,则存储时会报错。

总结:

  • JSONB 对 JSON 数据的检查是在数据库(PostgreSQL)端完成的
  • 即使 Django 模型使用的是 TextField 字段,但真正存储的是 JSONB 格式
  • JSONB 检查了JSON 语法和类型,可以过滤无效 JSON
  • 而 Django 只能检查字符串格式是否合法

使用TextField来对应一个PostgreSQL的JSONB字段,取数据会存在以下问题:
通过TextField来获取数据,实际上是把JSONB的字符串格式取出来。只能拿到JSON的原始字符串
获取到JSON字符串后,还需要调用.loads()来解析JSON。

使用TextField对应JSONB字段的问题在于:文章来源地址https://www.toymoban.com/news/detail-475517.html

  • 只能读取JSON的字符串,无法访问内置数据
  • 需要额外解析JSON字符串
  • 丢失JSON类型信息
  • 索引支持有限
  • 无法使用JSON相关的函数
    而使用JSONField可以:
  • 直接访问JSON内部数据
  • 保留JSON的类型
  • 支持JSON索引
  • 调用JSON相关的函数
    所以总的来说,使用JSONField对应JSONB字段更加推荐。

到了这里,关于Django JSONField的自动转换(django自定义模型字段)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Django中数据库模型中的DecimalField字段和IntegerField字段有何区别?

    在Django的数据库模型中, DecimalField 和 IntegerField 是两种不同的字段类型,用于存储数字数据。它们的主要区别在于支持的数据范围和精度。 IntegerField 是用于存储整数值的字段类型。它可以存储包含正数、负数和零在内的整数值。 IntegerField 的取值范围是由所使用的数据库系

    2024年02月16日
    浏览(38)
  • 【Django学习】(十)模型序列化器_关联字段序列化

    这篇文章是针对模型类序列化器以及如何关联字段序列化 进行深入讲解的;  在上面的模型序列化类中: 可以继承ModelSerializer类或者ModelSerializer的子类,来创建模型序列化器类; 模型序列化器类中可以重新定义序列化器字段,优先级大于自动生成的同名字段 如果新定义的字

    2024年02月11日
    浏览(50)
  • Django的数据库操作模型的字段参数blank和null有什么区别?什么叫表单验证?

    在Django的数据库操作模型中,字段参数 blank 和 null 用于定义模型字段的验证规则和数据库约束。它们的区别如下: blank :这个参数用于验证表单数据的有效性。当字段的 blank 参数设置为 True 时,表明该字段可以为空值或者不填写任何内容,不会触发验证错误。换句话说,

    2024年02月11日
    浏览(42)
  • 【mybatis-plus实体类复杂对象字段json自动相互转换,以及自定义字段类型解析器】

    引言: mybatis-plus集合对象字段json如何自动进行相互的转换? 怎样在使用mybatis-plus操作数据表的时候自动对实体类属性进行自动解析? 我们平时在做开发的时候,会遇到一个字段保存json串的情况。一般情况下mybatis-plus在做插入/更新之前将对象手动转换成json串,查询要用的时

    2023年04月13日
    浏览(103)
  • Django实现接口自动化平台(十)自定义action names【持续更新中】

    相关文章: Django实现接口自动化平台(九)环境envs序列化器及视图【持续更新中】_做测试的喵酱的博客-CSDN博客 深入理解DRF中的Mixin类_做测试的喵酱的博客-CSDN博客  python中Mixin类的使用_做测试的喵酱的博客-CSDN博客  本章是项目的一个分解,查看本章内容时,要结合整体项

    2024年02月16日
    浏览(69)
  • Django实现接口自动化平台(十二)自定义函数模块DebugTalks 序列化器及视图【持续更新中】

    上一章: Django实现接口自动化平台(十一)项目模块Projects序列化器及视图【持续更新中】_做测试的喵酱的博客-CSDN博客 本章是项目的一个分解,查看本章内容时,要结合整体项目代码来看: python django vue httprunner 实现接口自动化平台(最终版)_python+vue自动化测试平台_做测

    2024年02月16日
    浏览(42)
  • Django项目单字段的区间查询

    在Django项目中会碰到一些需求就是查询某个表中的一些字段从某日到某日的数据,而且是对但字段查询这个时候我们有两两种方法解决 单字段类型是DateTimeField的 查询日期范围的 这个时候在filter.py里面重写DateTimeFromToRangeFilter,为什么要重写呢? 因为我们做区间查询 起始与结

    2024年02月08日
    浏览(39)
  • 在Django的数据库模型的类中,通常还会定义一个名叫Meta的内部类,这个类有什么作用?

    在Django的数据库模型中, Meta 类是一个内部类,用于定义一些与模型相关的元数据(metadata)。它提供了一种在模型类中指定各种选项和配置的方式。 以下是 Meta 类的一些常见用途和作用: 定义模型的数据库表名: 通过 db_table 选项可以指定模型对应的数据库表的名称。例如

    2024年02月12日
    浏览(53)
  • django添加数据库字段进行数据迁移

    1.修改view.py里面的变量 2.在model.py新增字段 3.打开terminal并将环境切到项目所在环境,切换方式为 4.执行命令

    2024年02月09日
    浏览(61)
  • Django admin中展示字段设置外链

    假设有一个爬虫程序,它的主要作用是爬取一些新闻标题和该新闻的访问链接,总的来说数据项就两个: 新闻标题 访问链接(URL) 作为开发者我希望在Django admin页面中展示“访问链接”的字段能够直接点击访问,而不是复制下来再粘贴到浏览器中访问。 鉴于此,我需要给“

    2024年02月12日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包