当前位置: 首页 > article >正文

Django一分钟:在Django中怎么存储树形结构的数据,DRF校验递归嵌套模型的替代方案

引言

在开发过程中我们可能需要这样的树形结构:

[
    {
        "data": {"name": "牛奶"},
        "children": [
            {"data": {"name": "蒙牛"}, },
            {"data": {"name": "伊利"}, }
        ]
    },
    {
        "data": {"name": "面包"},
        "children": [
            {"data": {"name": "黑面包"}, },
            {"data": {"name": "白面包"}, }
        ]
    }
]

这种需求很常见,比如:分层的用户组、产品组件表等等,你都会用到树形结构,为这样的需求在django中自己从头创建模型并实现一系列的API是一个相当大的工作,好在我们有很多现成的库可以使用。

如果你在想:Django能不能做到某件事情;来这个网站看看是个好习惯。

一、创建和使用模型

本文中我们用到的库是django-treebeard

pip install django-treebeard

django-treebeard提供了三种实现方式:邻接表、嵌套集、路径树(MPTT)。下面我们使用路径树来演示,创建模型如下:

class Category(MP_Node):
    name = models.CharField(max_length=30)
    node_order_by = ['name']

    def __str__(self):
        return 'Category: {}'.format(self.name)

路径树会为你额外创建三个字段来辅助定义结构分别是pathdepthnumchild,它的插入和更新等维护比较繁重,但查询速度相当快。本文中我们不具体讨论实现原理,只是做简单使用演示,并为你可能遇到的问题提供思路,想详细了解其所有API阅读其文档。

定义好模型之后,模型中的一些方法可以辅助我们完成序列化和反序列化,快速的在数据库中保存和拉取数据:

>>> data =[
    {
        # tree1
        "data": {"name": "牛奶"},
        "children": [
            {"data": {"name": "蒙牛"}, },
            {"data": {"name": "伊利"}, }
        ]
    },
    {
        # tree2
        "data": {"name": "面包"},
        "children": [
            {"data": {"name": "黑面包"}, },
            {"data": {"name": "白面包"}, }
        ]
    }
]
>>> Category.load_bulk(data)
>>> Category.dump_bulk()
# [{'data': {'name': '牛奶'}, 'id': 1, 'children': [{'data': {'name': '伊利'}, 'id': 3}, {'data': {'name': '蒙牛'}, 'id': 2}]}, {'data': {'name': '面包'}, 'id': 4, 'children': [{'data': {'name': '白面包'}, 'id': 6}, {'data': {'name': '黑面包'}, 'id': 5}]}]

二、数据校验

假如你使用django rest framework为这样的递归嵌套的模型创建序列化器非常的困难,我推荐的解决方法是使用pydantic,如果你学习过FastAPI框架你应该对它不陌生。pydantic无法从django模型中自动生成模型,你需要自己定义:

from pydantic import BaseModel

class CategoryNodelModel(BaseModel):
    name: str

class CategoryTreeModel(BaseModel):
    data: CategoryNodelModel
    children: list['CategoryTreeModel'] | None = None

使用方法:

# 假设用户输入
>>> data = [
    {
        # tree1
        "data": {"name": "牛奶"},
        "children": [
            {"data": {"name": "蒙牛"}, },
            {"data": {"name": "伊利"}, }
        ]
    },
    {
        # tree2
        "data": {"name": "面包"},
        "children": [
            {"data": {"name": "黑面包"}, },
            {"data": {"name": "白面包"}, }
        ]
    }
]
# 测试用户输入的结构是否正确
>>> [CategoryTreeModel(**tree) for tree in data]
# 保存到数据库
>>> Category.load_bulk(data)

下面是测试代码,包含对一些api的简单演示:

from rest_framework.test import APITestCase
from api.models import Category
from api.views import CategoryS, CategoryNodelModel, CategoryTreeModel


class TestCategory(APITestCase):

    def setUp(self):
        # 用户输入
        data = [
            {
                # tree1
                "data": {"name": "牛奶"},
                "children": [
                    {"data": {"name": "蒙牛"}, },
                    {"data": {"name": "伊利"}, }
                ]
            },
            {
                # tree2
                "data": {"name": "面包"},
                "children": [
                    {"data": {"name": "黑面包"}, },
                    {"data": {"name": "白面包"}, }
                ]
            }
        ]
        # 测试用户输入的结构是否正确
        [CategoryTreeModel(**tree) for tree in data]
        Category.load_bulk(data)

    def test_get_all(self):
        print(Category.dump_bulk())

    def test_get_tree(self):
        milk = Category.objects.filter(name='牛奶').first()
        if milk:
            print(Category.dump_bulk(milk))

    def test_delete(self):
        milk = Category.objects.filter(name='面包').first()
        milk.delete()
        print(Category.dump_bulk())

总结

对于在django中使用树、图等复杂结构之类需求,可以去尝试寻找现成的库;对于复杂数据的校验可以尝试使用pydantic。选择合适的工具会为我们节省很多时间。


http://www.kler.cn/news/333458.html

相关文章:

  • Python 工具库每日推荐 【BeautifulSoup】
  • wordpress函数has_tag()函数与get_the_tags()有什么区别?
  • 使用PL/SQL Deverloper过程遇见的问题
  • RTSP协议讲解
  • 简单线性回归分析-基于R语言
  • 算法笔记(十)——队列+宽搜
  • 基于muduo库函数实现protobuf协议的通信
  • LabVIEW提高开发效率技巧----调度器设计模式
  • 堆排序算法的原理与应用
  • 【第三版 系统集成项目管理工程师】第15章 组织保障
  • Command | Ubuntu 个别实用命令记录(新建用户、查看网速等)
  • spring揭秘24-springmvc02-5个重要组件
  • 计算机毕业设计 助农产品采购平台的设计与实现 Java实战项目 附源码+文档+视频讲解
  • 【vs code(cursor) ssh连不上服务器(2)】但是 Terminal 可以连上,问题解决 ✅
  • 常用排序算法(下)
  • 增删改查sql
  • Kafka 消费者状态及高水位(High Watermark)详解
  • MySQL数据库用户权限控制的实现方法
  • 关于OJ平台的一个代码小问题 ——
  • 从0到1:培训机构排课小程序开发笔记一