StreamingHttpResponse:return 数据库连接池/关闭它

StreamingHttpResponse: return database connection to pool / close it

如果您从 Django 视图 StreamingHttpResponse returned,它什么时候 return 有任何数据库连接到池?如果默认情况下它会在 StreamingHttpResponse 完成后执行此操作,是否有办法更早地建立 return 连接?

def my_view(request):
  # Some database queries using the Django ORM
  # ...

  def yield_data():
    # A generator, with no database queries using the Django ORM
    # ...

  return StreamingHttpResponse(
    yield_data(), status=200
  )

如果有所不同,这是将 https://pypi.org/project/django-db-geventpool/ 与 gunicorn 一起使用,任何答案在使用 pytest.mark.django_db 进行测试时也应该有效(我认为在事务中包含测试)

如果您查看文档

https://docs.djangoproject.com/en/3.0/ref/databases/

连接管理

Django opens a connection to the database when it first makes a database query. It keeps this connection open and reuses it in subsequent requests. Django closes the connection once it exceeds the maximum age defined by CONN_MAX_AGE or when it isn’t usable any longer.

In detail, Django automatically opens a connection to the database whenever it needs one and doesn’t have one already — either because this is the first connection, or because the previous connection was closed.

At the beginning of each request, Django closes the connection if it has reached its maximum age. If your database terminates idle connections after some time, you should set CONN_MAX_AGE to a lower value, so that Django doesn’t attempt to use a connection that has been terminated by the database server. (This problem may only affect very low traffic sites.)

At the end of each request, Django closes the connection if it has reached its maximum age or if it is in an unrecoverable error state. If any database errors have occurred while processing the requests, Django checks whether the connection still works, and closes it if it doesn’t. Thus, database errors affect at most one request; if the connection becomes unusable, the next request gets a fresh connection.

此外,如果您在 django 源代码中看到 db/__init__.py

# For backwards compatibility. Prefer connections['default'] instead.
connection = DefaultConnectionProxy()


# Register an event to reset saved queries when a Django request is started.
def reset_queries(**kwargs):
    for conn in connections.all():
        conn.queries_log.clear()


signals.request_started.connect(reset_queries)


# Register an event to reset transaction state and close connections past
# their lifetime.
def close_old_connections(**kwargs):
    for conn in connections.all():
        conn.close_if_unusable_or_obsolete()


signals.request_started.connect(close_old_connections)
signals.request_finished.connect(close_old_connections)

它连接到 request_startedrequest_finished 信号以使用 close_old_connections 关闭旧连接。

所以如果你不愿意等待连接关闭你可以自己调用这个方法。您更新后的代码将如下所示

from django.db import close_old_connections

def my_view(request):
  # Some database queries using the Django ORM
  # ...
  close_old_connections()

  def yield_data():
    # A generator, with no database queries using the Django ORM
    # ...

  return StreamingHttpResponse(
    yield_data(), status=200
  )