Django Channels Postgres InterfaceError:连接已关闭 [英] Django Channels Postgres InterfaceError: connection already closed

查看:370
本文介绍了Django Channels Postgres InterfaceError:连接已关闭的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我似乎无法在这里解决这个问题。我正在按照文档中的说明 >。我通常会使用Django默认的单元测试,但是由于Channels需要使用pytest,因此我正在使用它,但仍希望保持编写测试的类结构。

I can't seem to wrap my head around the issue here. I'm writing tests for my Channel Consumers following the description in the docs. I'd normally use the Django default unittest but since Channels requires using pytest, I'm using it but will still like to maintain the class structure of writing tests.

I在编写类似于unittest的设置方法时遇到问题,该方法将用于初始化测试属性。我尝试了方法固定装置,使用 autouse = true ,但是它们似乎都不起作用,因为我无法在测试方法中访问实例属性。最后,我只是决定编写 set_up 实例方法,并为每个类手动调用它。这是我到目前为止的内容:

I had issues with writing the setup method similar to unittest which I would use to initialize the test attributes. I tried method fixtures, class fixtures using autouse=true, but none of them seemed to work as I couldn't access the instance attributes in the test methods. Finally I just decided to write the set_up instance method and manually call it for each class. This is what I have so far:

@pytest.mark.django_db
@pytest.mark.asyncio
class TestChatConsumer(object):

    @database_sync_to_async
    def set_up(self):

        self.user = UserFactory()
        self.api_client = APIClientFactory()
        self.token = TokenFactory(user=self.user)

        self.credentials = {
            'AUTHORIZATION': self.token.key,
            ...
        }

        self.credentials_params = '&'.join(['{}={}'.format(k, v) for k, v in self.credentials.items()])
        self.authless_endpoint = '/api/v1/ws/'
        self.endpoint = self.authless_endpoint + '?' + self.credentials_params

    async def test_connect_without_credentials(self):
        await self.set_up()
        communicator = WebsocketCommunicator(application, self.authless_endpoint)
        connected, subprotocol = await communicator.connect()
        assert not connected

    async def test_connect_with_credentials(self):
        await self.set_up()
        communicator = WebsocketCommunicator(application, self.endpoint)
        connected, subprotocol = await communicator.connect()
        assert connected

问题是我不断得到 psycopg2.InterfaceError:当我的使用者尝试使用 connect 方法内的代码访问数据库时,连接已关闭。它使用 database_sync_to_async ,并且在我手动测试它时效果很好。

The issue is that I keep getting psycopg2.InterfaceError: connection already closed when my consumer tries to access the database in it's code inside the connect method. It uses database_sync_to_async and works pretty well when I'm manually testing it.

具体来说,<引发错误的code> connect 方法如下所示:

Specifically, the line in the connect method that raises the error looks like this:

await database_sync_to_async(user.inbox.increment_connections)().

不确定到底是什么问题,因为 database_sync_to_async 应该正确清理旧的连接,以便可以正确地创建新的连接。

Not sure what exactly the issue is as database_sync_to_async should properly clean up old connections so that new ones can be properly created.

任何帮助将不胜感激。

推荐答案

显然我在看错地方。问题在这条线上:

Apparently I was looking at the wrong place. The issue was on this line:

await database_sync_to_async(user.inbox.increment_connections)()

收件箱是相关管理器,因此它会尝试在实际的 database_sync_to_async ,它失败,因为它需要数据库调用。

inbox is a related manager so it tries to fetch it before the actual database_sync_to_async and it fails as it requires a db call.

我尝试了这个 await database_sync_to_async(user).inbox.increment_connections(),但由于它包装了一个方法而不是一个属性,所以它不起作用,所以我最终要做的是使用 prefetch_related 来获取收件箱。这样, user.inbox 不再需要数据库调用,并且可以正常工作

I tried this await database_sync_to_async(user).inbox.increment_connections() and it didn't work since it wraps a method, not an attribute so what I ended up doing was to use prefetch_related to get the inbox during the authentication. In that way user.inbox no longer requires a db call and it works fine

这篇关于Django Channels Postgres InterfaceError:连接已关闭的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆