【问题标题】:Specifying Readonly access for Django.db connection object为 Django.db 连接对象指定只读访问权限
【发布时间】:2017-02-09 04:27:15
【问题描述】:

我有一系列集成级别的测试,它们在我的 Django 项目中作为管理命令运行。这些测试正在验证从外部来源摄取到我的数据库中的大量天气数据的完整性。因为我有如此大量的数据,所以我真的必须针对我的生产数据库进行测试才能使测试有意义。我想弄清楚的是如何定义特定于该命令或连接对象的只读数据库连接。我还应该补充一点,这些测试不能通过 ORM,所以我需要执行原始 SQL。

我的测试结构是这样的

class Command(BaseCommand):
    help = 'Runs Integration Tests and Query Tests against Prod Database'

    def handle(self,*args, **options):
        suite = unittest.TestLoader().loadTestsFromTestCase(TestWeatherModel)
        ret = unittest.TextTestRunner().run(suite)
        if(len(ret.failures) != 0):
            sys.exit(1)
        else:
            sys.exit(0)

class TestWeatherModel(unittest.TestCase):
    def testCollectWeatherDataHist(self):
        wm = WeatherManager()
        wm.CollectWeatherData()
        self.assertTrue(wm.weatherData is not None)

WeatherManager.CollectWeatherData() 方法如下所示:

def CollecWeatherData(self):
    cur = connection.cursor()
    cur.execute(<Raw SQL Query>)
    wm.WeatherData = cur.fetchall()
    cur.close()

我想以某种方式证明这一点,以免其他人(或我)稍后出现并意外编写会修改生产数据库的测试。

【问题讨论】:

  • 根据我的经验,这是在数据库端完成的。换句话说,测试应该使用特定于测试的只读用户凭据连接到数据库。您的测试也可能不必访问实时数据库,但这是一个更大的架构问题。
  • 我知道我不应该让这些测试影响生产数据库,我最终会将所有摄取和验证移至暂存数据库,然后同步到生产数据库,但我还没搞定。

标签: python django django-testing django-database django-postgresql


【解决方案1】:

如果你为你的模型添加一个序列化器,你可以专门研究在只读模式下工作的序列化器

class AccountSerializer(serializers.ModelSerializer):
    class Meta:
        model = Account
        fields = ('id', 'account_name', 'users', 'created')
        read_only_fields = ('account_name',)

来自http://www.django-rest-framework.org/api-guide/serializers/#specifying-read-only-fields

【讨论】:

  • 无论如何,在数据库上创建一个只读用户是最好最安全的解决方案
【解决方案2】:

伙计,再一次,在我在这里发布问题之前,我应该更仔细地阅读文档。我可以在设置文件中定义到我的生产数据库的只读连接,然后直接从docs:

如果您使用多个数据库,则可以使用 django.db.connections 来获取特定数据库的连接(和游标)。 django.db.connections 是一个类似字典的对象,允许您使用其别名检索特定连接:

from django.db import connections
cursor = connections['my_db_alias'].cursor()
# Your code here...

【讨论】:

    【解决方案3】:

    您可以通过挂钩到 Django 的 connection_created 信号来实现这一点,并且 然后将事务设为只读。

    以下适用于 PostgreSQL:

    from django.db.backends.signals import connection_created
    
    
    class MyappConfig(AppConfig):
        def ready(self):
            def connection_created_handler(connection, **kwargs):
                with connection.cursor() as cursor:
                    cursor.execute('SET default_transaction_read_only = true;')
            connection_created.connect(connection_created_handler, weak=False)
    

    这对于某些特定的 Django 设置很有用(例如,运行开发 runserver 对生产数据库的代码),您不想 创建一个真正的只读数据库用户。

    【讨论】:

      【解决方案4】:
      DATABASES = {
          'default': {
              'ENGINE': 'django.db.backends.postgresql_psycopg2',
              'NAME': 'mydb',
              'USER': 'myusername',
              'PASSWORD': 'mypassword',
              'HOST': 'myhost',
              'OPTIONS': {
                  'options': '-c default_transaction_read_only=on'
              }
          }
      }
      

      来源:https://nejc.saje.info/django-postgresql-readonly.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-03
        • 1970-01-01
        • 2019-12-24
        • 2017-07-10
        • 2010-10-13
        • 2012-05-29
        • 1970-01-01
        相关资源
        最近更新 更多