【问题标题】:Can I use a database view as a model in Django?我可以在 Django 中使用数据库视图作为模型吗?
【发布时间】:2010-10-05 04:49:22
【问题描述】:

我想使用我在数据库中创建的视图作为我的 django-view 的源。

这可能吗,不使用自定义 sql?

******13/02/09 更新*************

就像许多答案所暗示的那样,您可以在数据库中创建自己的视图,然后通过在 models.py 中定义它在 API 中使用它。

一些警告:

  • manage.py syncdb 将不再工作
  • 视图在其名称的开头需要与所有其他模型(表)相同的内容,例如,如果您的应用程序被称为“事物”,那么您的视图将需要被称为 thing_$viewname

【问题讨论】:

  • 视图不需要与应用同名。只需使用元字段 db_table。例如名为 its_a_View 的视图。类元:db_table = u'its_a_view'

标签: django django-migrations django-syncdb


【解决方案1】:

从 Django 1.1 开始,您可以使用Options.managed

对于旧版本,您可以轻松地为视图定义模型类并像使用其他视图一样使用它。我刚刚使用基于 Sqlite 的应用程序对其进行了测试,它似乎工作正常。如果您的视图的“主键”列未命名为“id”,请确保添加主键字段,如果您的视图未命名为“app_classname”,请在元选项中指定视图的名称。

唯一的问题是“syncdb”命令会引发异常,因为 Django 会尝试创建表。您可以通过在与 models.py 不同的单独 Python 文件中定义“视图模型”来防止这种情况。这样,Django 在检查 models.py 以确定要为应用创建的模型时不会看到它们,因此不会尝试创建表。

【讨论】:

  • 知道它会如何处理调用 save 方法吗?一些 dbms 有可更新的视图。
  • 我不确定。有可能 Django 只是尝试在视图上运行 INSERT 或 UPDATE 查询,但我对 Django 源代码没有太多了解:-)
  • 叹息伙计们,无需反对! 这是对一个古老问题的古老答案。 2009年2月还没有Options.managed,2009年7月29日出现在Django 1.1中...
  • 如果您的答案今天不再合适/准确,我建议您删除答案或将其替换为今天正确的答案。 (如果答案不再准确或今天的最佳解决方案,即使在提出问题时答案是准确的,投反对票也是完全可以理解的。) StackExchange 旨在成为高质量答案的存储库,对未来的读者,而不仅仅是 5 年前正确答案的历史档案。
【解决方案2】:

我们已经在使用 MySQL 的应用程序中非常广泛地完成了这项工作,以解决 Django 的单一数据库限制。我们的应用程序有几个数据库存在于一个 MySQL 实例中。只要我们为“当前”数据库中的每个表创建了视图,我们就可以通过这种方式实现跨数据库模型连接。

就视图的插入/更新而言,在我们的用例中,视图基本上是“从 [db.table] 中选择 *;”。换句话说,我们不做任何复杂的连接或过滤,所以来自 save() 的插入/更新触发器工作得很好。如果您的用例需要如此复杂的连接或广泛的过滤,我怀疑您不会在只读场景中遇到任何问题,但可能会遇到插入/更新问题。我认为 MySQL 中有一些潜在的约束会阻止您更新到跨表、具有复杂过滤器等的视图。

无论如何,如果您使用 MySQL 以外的 RDBMS,您的工作量可能会有所不同,但 Django 并不真正关心它是否位于物理表或视图的顶部。将由 RDBMS 确定它是否真正按您的预期运行。正如之前的评论者所指出的,您可能会将 syncdb 扔出窗外,尽管我们使用 post-syncdb 信号成功解决了这个问题,该信号删除了 Django 创建的物理表并运行我们的“创建视图...”命令。但是,post-syncdb 信号的触发方式有点深奥,所以也请注意。

编辑:当然,“post-syncdb 信号”是指“post-syncdb 监听器”

【讨论】:

    【解决方案3】:

    只是为那些会遇到这个问题的人(来自 Google 或其他任何地方)提供的更新...

    目前 Django 有一个简单的“正确方式”来define model without managing database tables

    Options.managed

    默认为True,这意味着Django 将在syncdb 中创建适当的数据库表,并将它们作为reset 管理命令的一部分删除。也就是说,Django 管理数据库表的生命周期。

    如果False,则不会对该模型执行任何数据库表创建或删除操作。如果模型表示现有表或已通过其他方式创建的数据库视图,这将很有用。这是managedFalse 时的唯一区别。模型处理的所有其他方面与正常情况完全相同。

    【讨论】:

    • 提供一些上下文;此功能在 Django 1.1 以上版本中可用。
    • 请记住,当您尝试删除由 models.ForeignKey 的数据库视图中的对象引用的对象时,您将遇到 TransactionErrors。
    • 如果您使用的是 Django 1.3+,那么您可以使用 ForeignKey.on_delete: user = models.ForeignKey(User, on_delete=models.DO_NOTHING) 避免 TransactionErrors
    【解决方案4】:

    来自Django Official Documentation,您可以这样调用视图:

    #import library
    from django.db import connection
    
    #Create the cursor
    cursor = connection.cursor()
    
    #Write the SQL code
    sql_string = 'SELECT * FROM myview'
    
    #Execute the SQL
    cursor.execute(sql_string)
    result = cursor.fetchall()
    

    希望对你有帮助 ;-)

    【讨论】:

      【解决方案5】:

      我刚刚使用带有 postgres 9.4 和 django 1.8 的视图实现了一个模型。

      我创建了这样的自定义迁移类:

      # -*- coding: utf-8 -*-
      from __future__ import unicode_literals
      
      from django.db import migrations
      
      
      class Migration(migrations.Migration):
      
          dependencies = [
              ('myapp', '0002_previousdependency'),
          ]
      
          sql = """
          create VIEW myapp_myview as
           select your view here
          """
      
          operations = [
              migrations.RunSQL("drop view if exists myapp_myview;"),
              migrations.RunSQL(sql)
          ]
      

      我像往常一样编写模型。它适用于我的目的。

      注意- 当我运行 makemigrations 时,为模型创建了一个新的迁移文件,我手动删除了该文件。

      完全公开-我的视图是只读的,因为我使用的是从 jsonb 数据类型派生的视图并且没有编写 ON UPDATE INSTEAD 规则。

      【讨论】:

      • 如果不想安装sqlparse,可以将RunSQL的参数包装在[]中。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-09
      • 2018-09-12
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 2020-02-08
      • 2016-06-25
      相关资源
      最近更新 更多