Django 动态模型字段

2023-12-20

我正在研究一个多租户应用程序中,一些用户可以定义自己的数据字段(通过管理员)以收集表单中的附加数据并报告数据。后一点使得 JSONField 不是一个很好的选择,所以我有以下解决方案:

class CustomDataField(models.Model):
    """
    Abstract specification for arbitrary data fields.
    Not used for holding data itself, but metadata about the fields.
    """
    site = models.ForeignKey(Site, default=settings.SITE_ID)
    name = models.CharField(max_length=64)

    class Meta:
        abstract = True

class CustomDataValue(models.Model):
    """
    Abstract specification for arbitrary data.
    """
    value = models.CharField(max_length=1024)

    class Meta:
        abstract = True

请注意 CustomDataField 如何具有到站点的外键 - 每个站点将具有一组不同的自定义数据字段,但使用相同的数据库。 那么各个具体数据字段可以定义为:

class UserCustomDataField(CustomDataField):
    pass

class UserCustomDataValue(CustomDataValue):
    custom_field = models.ForeignKey(UserCustomDataField)
    user = models.ForeignKey(User, related_name='custom_data')

    class Meta:
        unique_together=(('user','custom_field'),)

这导致以下用途:

custom_field = UserCustomDataField.objects.create(name='zodiac', site=my_site) #probably created in the admin
user = User.objects.create(username='foo')
user_sign = UserCustomDataValue(custom_field=custom_field, user=user, data='Libra')
user.custom_data.add(user_sign) #actually, what does this even do?

但这感觉非常笨重,特别是需要手动创建相关数据并将其与具体模型关联起来。有更好的方法吗?

已被预先丢弃的选项:

  • 自定义 SQL 来即时修改表。部分原因是这无法扩展,部分原因是它太过于黑客行为。
  • 无模式解决方案,例如 NoSQL。我没有反对他们,但他们仍然不合适。最终这个数据is键入,并且可以使用第三方报告应用程序。
  • JSONField,如上所述,因为它不能很好地处理查询。

截至目前,有四种可用的方法,其中两种需要特定的存储后端:

  1. Django-eav https://github.com/mvpdev/django-eav(原始包不再维护,但有一些蓬勃发展的分叉 https://github.com/mvpdev/django-eav/network)

    该解决方案基于实体属性值 https://en.wikipedia.org/wiki/Entity-attribute-value_model数据模型,本质上是使用多个表来存储对象的动态属性。该解决方案的重要部分在于:

    • 使用几个纯粹且简单的 Django 模型来表示动态字段,这使得它易于理解并且与数据库无关;
    • 允许您使用以下简单命令有效地将动态属性存储附加/分离到 Django 模型:

      eav.unregister(Encounter)
      eav.register(Patient)
      
    • 与 Django 管理完美集成 https://github.com/mvpdev/django-eav/blob/master/eav/admin.py;

    • 同时自己的实力也确实非常强大。

    缺点:

    • 效率不太高。这更多的是对 EAV 模式本身的批评,它需要手动将数据从列格式合并到模型中的一组键值对。
    • 更难维护。维护数据完整性需要多列唯一键约束,这在某些数据库上可能效率低下。
    • 您需要选择其中一个叉子 https://github.com/mvpdev/django-eav/network,因为官方包不再维护并且没有明确的领导者。

    用法非常简单:

    import eav
    from app.models import Patient, Encounter
    
    eav.register(Encounter)
    eav.register(Patient)
    Attribute.objects.create(name='age', datatype=Attribute.TYPE_INT)
    Attribute.objects.create(name='height', datatype=Attribute.TYPE_FLOAT)
    Attribute.objects.create(name='weight', datatype=Attribute.TYPE_FLOAT)
    Attribute.objects.create(name='city', datatype=Attribute.TYPE_TEXT)
    Attribute.objects.create(name='country', datatype=Attribute.TYPE_TEXT)
    
    self.yes = EnumValue.objects.create(value='yes')
    self.no = EnumValue.objects.create(value='no')
    self.unkown = EnumValue.objects.create(value='unkown')
    ynu = EnumGroup.objects.create(name='Yes / No / Unknown')
    ynu.enums.add(self.yes)
    ynu.enums.add(self.no)
    ynu.enums.add(self.unkown)
    
    Attribute.objects.create(name='fever', datatype=Attribute.TYPE_ENUM,\
                                           enum_group=ynu)
    
    # When you register a model within EAV,
    # you can access all of EAV attributes:
    
    Patient.objects.create(name='Bob', eav__age=12,
                               eav__fever=no, eav__city='New York',
                               eav__country='USA')
    # You can filter queries based on their EAV fields:
    
    query1 = Patient.objects.filter(Q(eav__city__contains='Y'))
    query2 = Q(eav__city__contains='Y') |  Q(eav__fever=no)
    
  2. PostgreSQL 中的 Hstore、JSON 或 JSONB 字段

    PostgreSQL 支持多种更复杂的数据类型。大多数都是通过第三方包支持的,但近年来 Django 已将它们采用到 django.contrib.postgres.fields 中。

    存储字段:

    Django-hstore https://github.com/jordanm/django-hstore原本是第三方包,但是Django 1.8添加了存储字段 https://docs.djangoproject.com/en/1.8/ref/contrib/postgres/fields/#hstorefield作为内置字段类型,以及其他几种 PostgreSQL 支持的字段类型。

    从某种意义上说,这种方法很好,它可以让您两全其美:动态字段和关系数据库。然而,hstore 是性能方面不理想 http://archives.postgresql.org/pgsql-performance/2011-05/msg00263.php,特别是如果您最终要在一个字段中存储数千个项目。它还仅支持值的字符串。

    #app/models.py
    from django.contrib.postgres.fields import HStoreField
    class Something(models.Model):
        name = models.CharField(max_length=32)
        data = models.HStoreField(db_index=True)
    

    在 Django 的 shell 中你可以像这样使用它:

    >>> instance = Something.objects.create(
                     name='something',
                     data={'a': '1', 'b': '2'}
               )
    >>> instance.data['a']
    '1'        
    >>> empty = Something.objects.create(name='empty')
    >>> empty.data
    {}
    >>> empty.data['a'] = '1'
    >>> empty.save()
    >>> Something.objects.get(name='something').data['a']
    '1'
    

    您可以对 hstore 字段发出索引查询:

    # equivalence
    Something.objects.filter(data={'a': '1', 'b': '2'})
    
    # subset by key/value mapping
    Something.objects.filter(data__a='1')
    
    # subset by list of keys
    Something.objects.filter(data__has_keys=['a', 'b'])
    
    # subset by single key
    Something.objects.filter(data__has_key='a')    
    

    JSON字段:

    JSON/JSONB 字段支持任何 JSON 可编码的数据类型,不仅仅是键/值对,而且往往比 Hstore 更快且(对于 JSONB)更紧凑。 多个包实现了 JSON/JSONB 字段,包括Django-pgfields https://django-pgfields.readthedocs.org/en/latest/fields.html,但从 Django 1.9 开始,JSON字段 https://docs.djangoproject.com/en/1.9/ref/contrib/postgres/fields/#jsonfield是一个内置的使用JSONB进行存储的。JSON字段与 HStoreField 类似,对于大型字典可能表现更好。它还支持字符串以外的类型,例如整数、布尔值和嵌套字典。

    #app/models.py
    from django.contrib.postgres.fields import JSONField
    class Something(models.Model):
        name = models.CharField(max_length=32)
        data = JSONField(db_index=True)
    

    在 shell 中创建:

    >>> instance = Something.objects.create(
                     name='something',
                     data={'a': 1, 'b': 2, 'nested': {'c':3}}
               )
    

    索引查询几乎与 HStoreField 相同,只是可以进行嵌套。复杂的索引可能需要手动创建(或脚本化迁移)。

    >>> Something.objects.filter(data__a=1)
    >>> Something.objects.filter(data__nested__c=3)
    >>> Something.objects.filter(data__has_key='a')
    
  3. Django MongoDB http://django-mongodb-engine.readthedocs.org/en/latest/

    或者其他 NoSQL Django 改编版本——使用它们您可以拥有完全动态的模型。

    NoSQL Django 库很棒,但请记住,它们并不是 100% 与 Django 兼容,例如,迁移到Django-nonrel http://www.allbuttonspressed.com/projects/django-nonrel在标准 Django 中,您需要将 ManyToMany 替换为列表字段 https://stackoverflow.com/questions/3877246/django-nonrel-on-google-app-engine-implications-of-using-listfield-for-manytom除其他事项外。

    查看这个 Django MongoDB 示例:

    from djangotoolbox.fields import DictField
    
    class Image(models.Model):
        exif = DictField()
    ...
    
    >>> image = Image.objects.create(exif=get_exif_data(...))
    >>> image.exif
    {u'camera_model' : 'Spamcams 4242', 'exposure_time' : 0.3, ...}
    

    您甚至可以创建嵌入列表 http://django-mongodb.org/topics/embedded-models.html任何 Django 模型:

    class Container(models.Model):
        stuff = ListField(EmbeddedModelField())
    
    class FooModel(models.Model):
        foo = models.IntegerField()
    
    class BarModel(models.Model):
        bar = models.CharField()
    ...
    
    >>> Container.objects.create(
        stuff=[FooModel(foo=42), BarModel(bar='spam')]
    )
    
  4. Django-mutant:基于syncdb和South-hooks的动态模型 https://github.com/charettes/django-mutant

    Django 突变体 https://github.com/charettes/django-mutant实现完全动态的外键和 m2m 字段。并受到令人难以置信但有些黑客解决方案的启发威尔·哈迪 http://dynamic-models.readthedocs.org/en/latest/index.html和迈克尔·霍尔。

    所有这些都是基于 Django South hooks,根据威尔·哈迪 (Will Hardy) 在 DjangoCon 2011 上的演讲 http://blip.tv/djangocon-europe-2011/wednesday-1415-will-hardy-5311186 (看它!)尽管如此,仍然很强大并在生产中经过测试(相关源码 http://dynamic-models.readthedocs.org/en/latest/).

    首先实施这个 https://bitbucket.org/mhall119/dynamo/overview was 迈克尔·霍尔 http://mhall119.com/2011/02/fun-with-django-meta-classes-and-dynamic-models/.

    是的,这就是魔法,通过这些方法你可以实现完全动态的 Django 应用程序、模型和字段与任何关系数据库后端。但代价是什么?大量使用会影响应用程序的稳定性吗?这些都是需要考虑的问题。您需要确保保持适当的lock https://stackoverflow.com/questions/1123200/how-to-lock-a-critical-section-in-django以允许同时进行数据库更改请求。

    如果您使用 Michael Halls lib,您的代码将如下所示:

    from dynamo import models
    
    test_app, created = models.DynamicApp.objects.get_or_create(
                          name='dynamo'
                        )
    test, created = models.DynamicModel.objects.get_or_create(
                      name='Test',
                      verbose_name='Test Model',
                      app=test_app
                   )
    foo, created = models.DynamicModelField.objects.get_or_create(
                      name = 'foo',
                      verbose_name = 'Foo Field',
                      model = test,
                      field_type = 'dynamiccharfield',
                      null = True,
                      blank = True,
                      unique = False,
                      help_text = 'Test field for Foo',
                   )
    bar, created = models.DynamicModelField.objects.get_or_create(
                      name = 'bar',
                      verbose_name = 'Bar Field',
                      model = test,
                      field_type = 'dynamicintegerfield',
                      null = True,
                      blank = True,
                      unique = False,
                      help_text = 'Test field for Bar',
                   )
    
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Django 动态模型字段 的相关文章

  • Python groupby 无法按预期工作[重复]

    这个问题在这里已经有答案了 我正在尝试读取一个 Excel 电子表格 其中包含以下格式的一些列 column1 column1 AccountName column1 SomeOtherFeature column2 blabla colu
  • Python bash 管道

    我想将 python 脚本的输出通过管道传输到 bash 脚本 到目前为止我所做的是尝试使用os popen sys subprocess 并试图给出一个管道的例子 os popen echo P 1 1 591336 4927369 1
  • 为什么我的查询在参数化后会中断?

    我有 2 张桌子 Sales and Product Sales可以将产品存储为Idn or Name 传统设计 和Type列指定实际type与之相关 Product等是连接的子集表into这个表来获取真实的数据 在这个例子中 Produc
  • 如何使用Python中的or-tools解决累积旅行商问题?

    累积旅行商问题 CTSP 的目标是最小化到达客户的时间总和 而不是总旅行时间 这与最小化总旅行时间不同 例如 如果一个人拥有无限的车辆 车辆与位置数量相同 并且目标是最大限度地减少到达位置的总时间 则可以为每个位置发送一辆车 因为这是满足所
  • 创建动态对象

    如何动态创建对象 string columnNames EmpName EmpID PhoneNo List
  • 类型错误:不支持的操作数类型 -:“int”和“list”

    我正在尝试用 python 创建一个程序 它会使用 Zeller 算法告诉你你出生在星期几http en wikipedia org wiki Zeller 27s congruence http en wikipedia org wiki
  • 如何在 Windows 上检查子进程是否被信号杀死

    问题 给定一个在 python 中启动的子进程 其代码类似于 import subprocess p subprocess Popen command stdout subprocess PIPE stderr subprocess PIP
  • Python NameError,变量“未定义”

    它返回的错误是 NameError name lives is not defined 我知道代码并不是尽可能高效 这是我的第一个项目 但是无论我尝试做什么 都会弹出这个错误 我尝试为其创建一个全局变量 但这没有帮助 我真的很感激一些帮助
  • TensorFlow 运算符重载

    有什么区别 tf add x y and x y 在 TensorFlow 中 当您使用以下命令构建图表时 您的计算图表会有什么不同 代替tf add 更一般地说 有 或者其他张量超载的操作 如果至少有一个x or y is a tf Te
  • 匹配字典集。最优雅的解决方案。 Python

    给定两个字典列表 新的和旧的 字典在两个列表中表示相同的对象 我需要找到差异并生成新的字典列表 其中仅包含新字典中的对象和旧字典中的更新属性 例子 list new id 1 name bob desc cool guy id 2 name
  • Django + 后台任务如何初始化

    我有一个基本的 django 项目 用作 Condor 计算集群的前端接口来生成模拟 用户可以从 django 应用程序开始模拟 在 Condor 中 与仿真相关的元数据和仿真状态保存在数据库中 我需要添加一个新功能 某些 模拟完成时发出通
  • 是否有像 python 的 issubclass 这样的东西,如果第一个参数不是类,它将返回 False?

    我想要issubclass 1 str 返回 false 1不是 的子类str 因为它根本不是一个类 所以我收到了 TypeError 有没有一个好的方法来测试这个而不诉诸try except try if issubclass value
  • 在循环中动态添加方法时的范围问题

    我有一个 API 用于分析我的锻炼数据 我抓取的数据 跑卫 http runkeeper com 的网站 我的主类是一个子类pandas DataFrame 它基本上是表格数据的容器 它支持按列名索引 返回列值的数组 我想根据数据中存在的
  • 转置 pandas 数据框

    如何将列表列表转换为 panda 数据框 它不是以列的形式 而是以行的形式 usr bin env python from random import randrange import pandas data randrange 0 100
  • Django Rest Framework 完整性错误捕获

    在 Django Rest Framework 中 我使用了序列化器 视图集和路由器方法 每当我在 django Rest 框架的 API 视图中发布故意错误时 它都会抛出完整性错误 有没有办法尝试捕获错误 例如如果数据中没有错误 则继续保
  • pytest 看不到正在测试的函数的日志

    我有一个像这样的烧瓶应用程序 from flask import Flask import logging app Flask name app route def catch all logging warning I m a warni
  • Python代码检测OS X El Capitan中的暗模式以更改状态栏菜单图标

    我有目标 C 代码来检测暗模式以更改状态栏 NSDistributedNotificationCenter defaultCenter addObserver self selector selector darkModeChanged n
  • 需要帮助编写扭曲的代理

    我想编写一个简单的代理 可以对请求页面正文中的文本进行打乱 我已经阅读了 stackoverflow 上的部分扭曲文档和其他一些类似的问题 但我有点菜鸟 所以我仍然不明白 我现在就是这样 不知道如何访问和修改页面 from twisted
  • 检查数组中是否有 3 个连续值高于某个阈值

    假设我有一个像这样的 np array a 1 3 4 5 60 43 53 4 46 54 56 78 有没有一种快速方法来获取 3 个连续数字都高于某个阈值的所有位置的索引 也就是说 对于某个阈值th 得到所有x其中 a x gt th
  • Django 无法覆盖表单字段小部件

    我需要在表单中生成基于列的复选框 myapp templates forms widgets custom html div class row for group options index in widget optgroups for

随机推荐

  • ftp_get 不适用于大文件

    这是我的代码 con ftp connect ftpserver com ftp login con username password ftp pasv con true ftp set option con FTP TIMEOUT SE
  • create-react-app 不会生成 public 和 src 文件夹,因此无法启动

    我已经安装 CRA 一个多月了 并且一直在使用它 没有任何问题 但是今天我创建了一个新的 React 应用程序 它构建了文件夹和目录 但它不生成 src 和公共文件夹 它只是生成节点 module 文件夹 因此当我运行 npm start
  • Cordova/phonegap 活动生命周期

    我正在cordova应用程序中为android开发一个地图插件 让我们暂时忘记已经有不止一个了 并认为这是一个学术问题 的文档MapView states http developer android com reference com g
  • PhoneGap/Cordova iOS:捕获有持续时间限制的视频(即 30 秒)

    我想将视频捕捉时间限制为 30 秒 截至目前 PhoneGap 文档说明了 iOS 实现的以下内容 不支持持续时间参数 无法以编程方式限制录制长度 我确实找到了这篇文章 它似乎给出了纯粹客观的 C 实现的解决方案 iPhone 5秒视频拍摄
  • os_signpost 在模拟器上有效,但在设备上运行时无效

    我想使用仪器跟踪时间的函数之一中有以下代码行 当我从仪器在模拟器上运行该应用程序时 使用 os signpost 测量的时间确实显示出来 我可以准确地测量我需要的东西 Then I switch to device same code Ho
  • R - 分割数据框并保存到不同的文件

    我有一个数据框 其中包含多个地点的每月温度数据 gt df4 1 36 location variable cut month year freq 1 Adamantina temperature 10 Jan 1981 21 0 646
  • 如何消除 SSIS 作业中的“未使用的输出列”警告?

    我正在尝试消除 SSIS 进度日志中的一些虚假警告 我收到一堆关于使用原始 SQL 完成工作的任务中未使用列的警告 我有一个数据流 负责在加载新数据之前将数据归档到临时表中 数据流如下所示 OLEDB Source task read st
  • Xcode 是否隐式将 plist 转换为二进制格式?

    Xcode 在构建过程中是否会隐式地将项目中的 plist 转换为二进制文件 我不认为它隐式地这样做 但很难确定 有一个名为 Property List Output Encoding 又名 PLIST FILE OUTPUT FORMAT
  • 如何修复SSL证书验证失败

    我在本地使用 PHPMailer Apache 和 PHP 当我测试我的 SSL 配置和我的 cacerts 时 我得到 default cert file C Program Files Common Files SSL cert pem
  • 在VB.NET中使用Moq的VerifySet

    我有一个功能可以更新 ASP NET 会员资格提供程序中的用户
  • Python Kivy:如何在单击按钮时调用函数?

    我对使用 kivy 库还很陌生 我有一个 app py 文件和一个 app kv 文件 我的问题是我无法在按下按钮时调用函数 app py import kivy from kivy app import App from kivy uix
  • 如何在 wpf 中使用 WindowChrome 而不使用 Windows Aero 玻璃效果,黑色边框

    我正在尝试使用 WindowChrome 类自定义窗口边框 没有 Windows Aero 玻璃效果 正如预期的那样 我最终得到了一个黑人寄宿生 但我最终也没有标题按钮 从微软我了解到我可以通过将窗口样式设置为 null 来使用标准窗口来克
  • DQL 查询返回:预期 StateFieldPathExpression 或 SingleValuedAssociationField

    我有以下 DQL 查询 public function findByIdJoinedToCodeExample pageId query this gt getEntityManager gt createQuery SELECT c FR
  • 将 super 与 class_eval 一起使用

    我有一个应用程序 其中包含用于添加客户端自定义的核心类模块 我发现 class eval 是重写核心类中方法的好方法 但有时我想避免重写整个方法 而只是遵循原始方法 例如 如果我有一个名为account balance 最好在我的模块 即包
  • 在 ASP.NET 中将 HTML 内容写入 Word 文档时出现问题

    我正在尝试将 HTML 页面内容导出到 Word 我的Html显示页面是 你最喜欢的颜色是什么 NA 列出前三名的学校 一名国家级 两个开发人员 三个PS 以及一个用于点击事件的按钮 按钮单击事件将打开 MS Word 并将页面内容粘贴到
  • 简单的 UIView drawRect 没有被调用

    我不明白这里出了什么问题 我有一个非常简单的 UIViewController 和一个非常简单的 viewDidLoad 方法 void viewDidLoad NSLog making game view GameView v GameV
  • Python-获取目录中所有文件和子文件夹的相对路径

    我正在寻找一种获取特定文件夹内文件和 子 文件夹的相对路径的好方法 对于我目前使用的方法os walk 它正在工作 但对我来说似乎并不 Pythonic myFolder myfolder fileSet set yes I need a
  • 手动设置Session过期时间-CodeIgniter

    如何在 codeigniter 中动态设置会话过期时间 例如 如果用户登录并具有以下角色 admin 过期时间应该比没有权限的用户登录时要长admin role Thanks 您可以通过在配置文件中增加此变量来更新会话过期时间 config
  • 我应该对不透明对象使用整数 ID 还是指针?

    我正在一些图形 API DirectX9 和 DirectX11 之上编写一个抽象层 我想听听您的意见 传统上 我会为每个我想要抽象的概念创建一个基类 因此 在典型的 OO 方式中 我将拥有一个 Shader 类和 2 个子类 DX9Sha
  • Django 动态模型字段

    我正在研究一个多租户应用程序中 一些用户可以定义自己的数据字段 通过管理员 以收集表单中的附加数据并报告数据 后一点使得 JSONField 不是一个很好的选择 所以我有以下解决方案 class CustomDataField models