Django + Mongo + Docker 得到 pymongo.errors.ServerSelectionTimeoutError

Django + Mongo + Docker getting pymongo.errors.ServerSelectionTimeoutError

我一直在努力使用 Django、Djongo、Mongo 和 Docker Compose 获得一个简单的应用程序 运行ning。我的设置如下所示:

docker-compose.yml

services:
  mongodb:
    image: mongo:latest
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: mongoadmin
      MONGO_INITDB_DATABASE: django_mongodb_docker
    ports:
      - 27017:27017

  web:
    build: ./src
    restart: always
    command: python src/manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - 8000:8000
    links:
      - mongodb

Docker文件

FROM python:3
ENV PYTHONUNBUFFERED=1
RUN mkdir /code
COPY . /code/
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt

settings.py

DATABASES = {
    'default': {
        'ENGINE': 'djongo',
        'HOST': 'mongodb',
        'PORT': 27017,
        'USER': 'root',
        'PASSWORD': 'mongoadmin',
        'AUTH_SOURCE': 'admin',
        'AUTH_MECHANISM': 'SCRAM-SHA-1',
    }
}

令人恼火的是,我可以使用 pymongo 从我的 Web 容器连接到容器 运行ning mongo。其工作原理如下。

from pymongo import MongoClient

c = MongoClient(
    'mongodb://mongodb:27017',
    username='root',
    password='mongoadmin',
    authSource='admin',
    authMechanism='SCRAM-SHA-1')

print(c.server_info())

问题是,当我从我的 Web 容器中转到 运行 迁移时,出现以下错误。

Traceback (most recent call last):
  File "/code/src/manage.py", line 22, in <module>
    main()
  File "/code/src/manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 395, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python3.9/site-packages/django/core/management/base.py", line 330, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/local/lib/python3.9/site-packages/django/core/management/base.py", line 371, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python3.9/site-packages/django/core/management/base.py", line 85, in wrapped
    res = handle_func(*args, **kwargs)
  File "/usr/local/lib/python3.9/site-packages/django/core/management/commands/migrate.py", line 92, in handle
    executor = MigrationExecutor(connection, self.migration_progress_callback)
  File "/usr/local/lib/python3.9/site-packages/django/db/migrations/executor.py", line 18, in __init__
    self.loader = MigrationLoader(self.connection)
  File "/usr/local/lib/python3.9/site-packages/django/db/migrations/loader.py", line 53, in __init__
    self.build_graph()
  File "/usr/local/lib/python3.9/site-packages/django/db/migrations/loader.py", line 216, in build_graph
    self.applied_migrations = recorder.applied_migrations()
  File "/usr/local/lib/python3.9/site-packages/django/db/migrations/recorder.py", line 77, in applied_migrations
    if self.has_table():
  File "/usr/local/lib/python3.9/site-packages/django/db/migrations/recorder.py", line 56, in has_table
    tables = self.connection.introspection.table_names(cursor)
  File "/usr/local/lib/python3.9/site-packages/django/db/backends/base/introspection.py", line 48, in table_names
    return get_names(cursor)
  File "/usr/local/lib/python3.9/site-packages/django/db/backends/base/introspection.py", line 43, in get_names
    return sorted(ti.name for ti in self.get_table_list(cursor)
  File "/usr/local/lib/python3.9/site-packages/djongo/introspection.py", line 47, in get_table_list
    for c in cursor.db_conn.list_collection_names()
  File "/usr/local/lib/python3.9/site-packages/pymongo/database.py", line 863, in list_collection_names
    for result in self.list_collections(session=session, **kwargs)]
  File "/usr/local/lib/python3.9/site-packages/pymongo/database.py", line 825, in list_collections
    return self.__client._retryable_read(
  File "/usr/local/lib/python3.9/site-packages/pymongo/mongo_client.py", line 1460, in _retryable_read
    server = self._select_server(
  File "/usr/local/lib/python3.9/site-packages/pymongo/mongo_client.py", line 1278, in _select_server
    server = topology.select_server(server_selector)
  File "/usr/local/lib/python3.9/site-packages/pymongo/topology.py", line 241, in select_server
    return random.choice(self.select_servers(selector,
  File "/usr/local/lib/python3.9/site-packages/pymongo/topology.py", line 199, in select_servers
    server_descriptions = self._select_servers_loop(
  File "/usr/local/lib/python3.9/site-packages/pymongo/topology.py", line 215, in _select_servers_loop
    raise ServerSelectionTimeoutError(
pymongo.errors.ServerSelectionTimeoutError: localhost:27017: [Errno 111] Connection refused, Timeout: 30s, Topology Description: <TopologyDescription id: 5f9ecaa5bbdc0433baa13966, topology_type: Single, servers: [<ServerDescription ('localhost', 27017) server_type: Unknown, rtt: None, error=AutoReconnect('localhost:27017: [Errno 111] Connection refused')>]>

此外,我尝试创建一个 Djongo 模型并保存它以查看问题是否是特定于迁移的(本质上只是尝试使用 djongo 与 mongo 建立任何连接)。

models.py

from djongo import models

class Blog(models.Model):
    name = models.CharField(max_length=100)

test.py

b = Blog(name='test')
b.save()

即returns以下错误:

The above exception was the direct cause of the following exception:
web_1      | 
web_1      | Traceback (most recent call last):
web_1      |   File "/usr/local/lib/python3.9/site-packages/djongo/cursor.py", line 51, in execute
web_1      |     self.result = Query(
web_1      |   File "/usr/local/lib/python3.9/site-packages/djongo/sql2mongo/query.py", line 783, in __init__
web_1      |     self._query = self.parse()
web_1      |   File "/usr/local/lib/python3.9/site-packages/djongo/sql2mongo/query.py", line 884, in parse
web_1      |     raise exe from e
web_1      | djongo.exceptions.SQLDecodeError: 
web_1      | 
web_1      |    Keyword: None
web_1      |    Sub SQL: None
web_1      |    FAILED SQL: INSERT INTO "game_blog" ("name") VALUES (%(0)s)
web_1      |    Params: ['test']
web_1      |    Version: 1.3.3
web_1      | 
web_1      | The above exception was the direct cause of the following exception:
web_1      | 
web_1      | Traceback (most recent call last):
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
web_1      |     return self.cursor.execute(sql, params)
web_1      |   File "/usr/local/lib/python3.9/site-packages/djongo/cursor.py", line 59, in execute
web_1      |     raise db_exe from e
web_1      | djongo.database.DatabaseError
web_1      | 
web_1      | The above exception was the direct cause of the following exception:
web_1      | 
web_1      | Traceback (most recent call last):
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
web_1      |     response = get_response(request)
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 179, in _get_response
web_1      |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/views/generic/base.py", line 70, in view
web_1      |     return self.dispatch(request, *args, **kwargs)
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/views/generic/base.py", line 98, in dispatch
web_1      |     return handler(request, *args, **kwargs)
web_1      |   File "/code/src/game/views.py", line 9, in get
web_1      |     b.save(using='mongo')
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/db/models/base.py", line 753, in save
web_1      |     self.save_base(using=using, force_insert=force_insert,
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/db/models/base.py", line 790, in save_base
web_1      |     updated = self._save_table(
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/db/models/base.py", line 895, in _save_table
web_1      |     results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/db/models/base.py", line 933, in _do_insert
web_1      |     return manager._insert(
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method
web_1      |     return getattr(self.get_queryset(), name)(*args, **kwargs)
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 1254, in _insert
web_1      |     return query.get_compiler(using=using).execute_sql(returning_fields)
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1397, in execute_sql
web_1      |     cursor.execute(sql, params)
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 98, in execute
web_1      |     return super().execute(sql, params)
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 66, in execute
web_1      |     return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 75, in _execute_with_wrappers
web_1      |     return executor(sql, params, many, context)
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
web_1      |     return self.cursor.execute(sql, params)
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/db/utils.py", line 90, in __exit__
web_1      |     raise dj_exc_value.with_traceback(traceback) from exc_value
web_1      |   File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
web_1      |     return self.cursor.execute(sql, params)
web_1      |   File "/usr/local/lib/python3.9/site-packages/djongo/cursor.py", line 59, in execute
web_1      |     raise db_exe from e
web_1      | django.db.utils.DatabaseError

如有任何帮助,我们将不胜感激。

我已经尝试像 this 一样编辑我的 mongodb.conf。

根据 this documentsettings.py 应该有一个 CLIENT 部分,其中包含:

A set of key-value pairs that will be passed directly to MongoClient as kwargs while creating a new client connection.

所以请尝试将您的 settings.py 设置为:

DATABASE = {
    'default': {
        'ENGINE': 'djongo',
        'NAME': 'your-database-name',
        'CLIENT': {
            'host': 'mongodb://mongodb:27017',
            'username': 'root',
            'password': 'mongoadmin',
            'authSource': 'admin',
            'authMechanism': 'SCRAM-SHA-1',
        }
    }
}