Skip to content
LlamaIndex 文档版本 跟随上游 源快照 32dbf15b 更新于 2026-10-15

本指南要带你把 LlamaIndex 与一个名为 Delphic 的生产就绪 Web 应用起步模板一起使用。文中所有代码示例都可以在 Delphic 仓库里找到

我们要构建什么

下面是 Delphic 开箱即用功能的一段演示:

https://user-images.githubusercontent.com/5049984/233236432-aa4980b6-a510-42f3-887a-81485c9644e6.mp4

架构总览

Delphic 借助 LlamaIndex 这个 Python 库,让用户创建自己的文档集合,随后在一个响应迅速的前端里对这些集合提问。

我们挑选的技术栈兼顾响应速度与健壮性,能够(1)编排复杂的 Python 处理任务,同时提供(2)一个现代、响应式的前端,以及(3)一个可在此基础上继续扩展功能的安全后端。

核心库有:

  1. Django
  2. Django Channels
  3. Django Ninja
  4. Redis
  5. Celery
  6. LlamaIndex
  7. Langchain
  8. React
  9. Docker 与 Docker Compose

得益于这套建立在极其稳定的 Django Web 框架之上的现代技术栈,Delphic 起步应用拥有顺手的开发者体验、内置的认证与用户管理、异步的向量库处理,以及为响应式 UI 提供的基于 WebSocket 的查询连接。此外,前端用 TypeScript 编写,基于 MUI React,以获得响应式的现代界面。

系统要求

Celery 无法在 Windows 上运行。也许可以借助 Windows Subsystem for Linux 部署,但配置它已超出本教程范围。因此,建议只在 Linux 或 OSX 上跟着本教程做。部署应用需要装好 Docker 与 Docker Compose;本地开发还需要 node 版本管理器(nvm)。

Django 后端

项目目录概览

Delphic 应用的后端目录结构遵循常见的 Django 项目惯例。从仓库根目录看,位于 ./delphic 子目录下的主要目录有:

  1. contrib:存放对 Django 内置 contrib 应用的定制或扩展。
  2. indexes:存放与文档索引和 LLM 集成相关的核心功能,其中包括:
  • admin.py:该应用的 Django admin 配置
  • apps.py:应用配置
  • models.py:应用的数据库模型
  • migrations:存放该应用数据库 schema 迁移的目录
  • signals.py:定义应用的各类信号
  • tests.py:应用的单元测试
  1. tasks:存放用 Celery 做异步处理的任务。其中 index_tasks.py 包含创建向量索引的任务。
  2. users:这个目录专用于用户管理,其中包括:
  3. utils:存放应用各处使用的工具模块与函数,例如自定义存储后端、路径助手以及与集合相关的工具。

数据库模型

Delphic 应用有两个核心模型:Document 与 Collection。它们代表应用在「用 LLM 索引并查询文档」时所处理的核心实体。它们定义在 ./delphic/indexes/models.py。

  1. Collection:
  • api_key:指向 API key 的外键,用于把任务关联到发起它的 API key。
  • title:字符字段,给出集合的标题。
  • description:文本字段,给出集合的描述。
  • status:字符字段,保存集合的处理状态,取值来自 CollectionStatus 枚举。
  • created:日期时间字段,记录集合的创建时间。
  • modified:日期时间字段,记录集合的最后修改时间。
  • model:文件字段,保存与集合关联的模型。
  • processing:布尔字段,表示集合当前是否正在处理中。
  1. Document:
  • collection:指向集合的外键,表示文档与集合之间的归属关系。
  • file:文件字段,保存上传的文档文件。
  • description:文本字段,给出该文档的描述。
  • created:日期时间字段,记录文档的创建时间。
  • modified:日期时间字段,记录文档的最后修改时间。

这些模型为「文档集合」以及由它们借助 LlamaIndex 创建的索引打下了扎实的基础。

Django Ninja API

Django Ninja 是一个用 Django 和 Python 3.7+ 类型提示来构建 API 的 Web 框架。它提供了一种简洁、直观且富有表现力的方式来定义 API 端点,并借助 Python 的类型提示自动生成输入校验、序列化与文档。

在 Delphic 仓库里,./config/api/endpoints.py 包含 API 路由以及各端点的逻辑。下面简要说明 endpoints.py 中每个端点的用途:

  1. /heartbeat:一个简单的 GET 端点,用于确认 API 是否在运行。API 可访问时返回 True。这对 Kubernetes 部署很有用——它会主动查询你的容器来确认其存活。

  2. /collections/create:创建新 Collection 的 POST 端点。接受 title、description 以及一组 files 等表单参数,为每个文件创建 Collection 与 Document 实例,并调度一个创建索引的 Celery 任务。

@collections_router.post("/create")
async def create_collection(
    request,
    title: str = Form(...),
    description: str = Form(...),
    files: list[UploadedFile] = File(...),
):
    key = None if getattr(request, "auth", None) is None else request.auth
    if key is not None:
        key = await key

    collection_instance = Collection(
        api_key=key,
        title=title,
        description=description,
        status=CollectionStatusEnum.QUEUED,
    )

    await sync_to_async(collection_instance.save)()

    for uploaded_file in files:
        doc_data = uploaded_file.file.read()
        doc_file = ContentFile(doc_data, uploaded_file.name)
        document = Document(collection=collection_instance, file=doc_file)
        await sync_to_async(document.save)()

    create_index.si(collection_instance.id).apply_async()

    return await sync_to_async(CollectionModelSchema)(...)
  1. /collections/query —— 用 LLM 查询某个文档集合的 POST 端点。接受包含 collection_id 与 query_str 的 JSON 载荷,返回通过查询该集合生成的回答。我们的聊天界面并没有真的使用这个端点(我们走 WebSocket,见下文),但你完全可以做一个应用通过这条 REST 端点来查询指定集合。
@collections_router.post(
    "/query",
    response=CollectionQueryOutput,
    summary="Ask a question of a document collection",
)
def query_collection_view(
    request: HttpRequest, query_input: CollectionQueryInput
):
    collection_id = query_input.collection_id
    query_str = query_input.query_str
    response = query_collection(collection_id, query_str)
    return {"response": response}
  1. /collections/available:返回使用该用户 API key 创建的全部集合列表的 GET 端点。输出通过 CollectionModelSchema 序列化。
@collections_router.get(
    "/available",
    response=list[CollectionModelSchema],
    summary="Get a list of all of the collections created with my api_key",
)
async def get_my_collections_view(request: HttpRequest):
    key = None if getattr(request, "auth", None) is None else request.auth
    if key is not None:
        key = await key

    collections = Collection.objects.filter(api_key=key)

    return [{...} async for collection in collections]
  1. /collections/{collection_id}/add_file:向既有集合添加文件的 POST 端点。接受 collection_id 路径参数,以及 file、description 等表单参数。会把该文件作为与指定集合关联的 Document 实例加入。
@collections_router.post(
    "/{collection_id}/add_file", summary="Add a file to a collection"
)
async def add_file_to_collection(
    request,
    collection_id: int,
    file: UploadedFile = File(...),
    description: str = Form(...),
):
    collection = await sync_to_async(Collection.objects.get)(id=collection_id)

WebSocket 入门

WebSocket 是一种通信协议,它让客户端与服务端在一条长期存活的连接上进行双向、全双工通信。WebSocket 协议被设计为与 HTTP/HTTPS 使用相同端口(分别是 80 和 443),并采用类似的握手过程来建立连接。连接一旦建立,数据就能以“帧”的形式双向收发,而不必像传统 HTTP 请求那样每次都重新建立连接。

使用 WebSocket 有很多理由,尤其是当你要对接「载入内存很慢、但载入之后运行很快」的代码时:

  1. 性能:WebSocket 免去了为每个请求反复打开与关闭连接所带来的开销,降低了延迟。
  2. 效率:WebSocket 支持实时通信而无需轮询,资源利用更高效、响应也更敏捷。
  3. 可扩展性:WebSocket 能处理大量并发连接,非常适合需要高并发的应用。

就 Delphic 应用而言,使用 WebSocket 非常合理,因为 LLM 载入内存的代价可能很高。建立起 WebSocket 连接后,LLM 可以一直驻留在内存中,后续请求因而能被快速处理,不必每次都重新加载模型。

ASGI 配置文件 ./config/asgi.py 规定了应用如何处理传入连接:使用 Django Channels 的 ProtocolTypeRouter,按协议类型来路由连接。这里有两个协议类型:“http” 与 “websocket”。

“http” 协议类型使用标准的 Django ASGI 应用来处理 HTTP 请求;“websocket” 协议类型则使用自定义的 TokenAuthMiddleware 为 WebSocket 连接做认证。其中的 URLRouter 为 CollectionQueryConsumer 定义了一条 URL 模式,由它负责处理与查询文档集合相关的 WebSocket 连接。

application = ProtocolTypeRouter(
    {
        "http": get_asgi_application(),
        "websocket": TokenAuthMiddleware(
            URLRouter(
                [
                    re_path(
                        r"ws/collections/(?P<collection_id>\w+)/query/$",
                        CollectionQueryConsumer.as_asgi(),
                    ),
                ]
            )
        ),
    }
)

有了这套配置,客户端就能与 Delphic 应用建立 WebSocket 连接,高效地用 LLM 查询文档集合,而不必每次请求都重新加载模型。

WebSocket 处理器

位于 config/api/websockets/queries.py 的 CollectionQueryConsumer 类负责处理与查询文档集合相关的 WebSocket 连接。它继承自 Django Channels 提供的 AsyncWebsocketConsumer 类。

CollectionQueryConsumer 类有三个主要方法:

  1. connect:在 WebSocket 作为连接过程一部分进行握手时被调用。
  2. disconnect:在 WebSocket 因任何原因关闭时被调用。
  3. receive:当服务器从 WebSocket 收到消息时被调用。

WebSocket 的 connect 监听器

connect 方法负责建立连接:从连接路径中取出集合 ID,加载集合模型,然后接受该连接。

async def connect(self):
    try:
        self.collection_id = extract_connection_id(self.scope["path"])
        self.index = await load_collection_model(self.collection_id)
        await self.accept()

    except ValueError as e:
        await self.accept()
        await self.close(code=4000)
    except Exception as e:
        pass

WebSocket 的 disconnect 监听器

这里的 disconnect 方法是空的,因为 WebSocket 关闭时不需要做任何额外动作。

WebSocket 的 receive 监听器

receive 方法负责处理从 WebSocket 收到的消息:拿到传入消息、解码,然后用给出的查询去查询已加载的集合模型。回答会被格式化成 markdown 字符串,再通过 WebSocket 连接发回客户端。

async def receive(self, text_data):
    text_data_json = json.loads(text_data)

    if self.index is not None:
        query_str = text_data_json["query"]
        modified_query_str = f"Please return a nicely formatted markdown string to this request:\n\n{query_str}"
        query_engine = self.index.as_query_engine()
        response = query_engine.query(modified_query_str)

        markdown_response = f"## Response\n\n{response}\n\n"
        if response.source_nodes:
            markdown_sources = (
                f"## Sources\n\n{response.get_formatted_sources()}"
            )
        else:
            markdown_sources = ""

        formatted_response = f"{markdown_response}{markdown_sources}"

        await self.send(json.dumps({"response": formatted_response}, indent=4))
    else:
        await self.send(
            json.dumps(
                {"error": "No index loaded for this connection."}, indent=4
            )
        )

加载集合模型用的是 load_collection_model 函数,它位于 delphic/utils/collections.py。该函数按给定的集合 ID 取出集合对象,检查集合模型对应的 JSON 文件是否存在、不存在就创建一个,然后在配置好 LLM 与 Settings 之后,用这个缓存文件加载 VectorStoreIndex。

from llama_index.core import Settings

async def load_collection_model(collection_id: str | int) -> VectorStoreIndex:
    """
    Load the Collection model from cache or the database, and return the index.

    Args:
        collection_id (Union[str, int]): The ID of the Collection model instance.

    Returns:
        VectorStoreIndex: The loaded index.

    This function performs the following steps:
    1. Retrieve the Collection object with the given collection_id.
    2. Check if a JSON file with the name '/cache/model_{collection_id}.json' exists.
    3. If the JSON file doesn't exist, load the JSON from the Collection.model FileField and save it to
       '/cache/model_{collection_id}.json'.
    4. Call VectorStoreIndex.load_from_disk with the cache_file_path.
    """
    # Retrieve the Collection object
    collection = await Collection.objects.aget(id=collection_id)
    logger.info(f"load_collection_model() - loaded collection {collection_id}")

    # Make sure there's a model
    if collection.model.name:
        logger.info("load_collection_model() - Setup local json index file")

        # Check if the JSON file exists
        cache_dir = Path(settings.BASE_DIR) / "cache"
        cache_file_path = cache_dir / f"model_{collection_id}.json"
        if not cache_file_path.exists():
            cache_dir.mkdir(parents=True, exist_ok=True)
            with collection.model.open("rb") as model_file:
                with cache_file_path.open(
                    "w+", encoding="utf-8"
                ) as cache_file:
                    cache_file.write(model_file.read().decode("utf-8"))

        # define LLM
        logger.info(
            f"load_collection_model() - Setup Settings with tokens {settings.MAX_TOKENS} and "
            f"model {settings.MODEL_NAME}"
        )
        Settings.llm = OpenAI(
            temperature=0, model="gpt-3.5-turbo", max_tokens=512
        )

        # Call VectorStoreIndex.load_from_disk
        logger.info("load_collection_model() - Load llama index")
        index = VectorStoreIndex.load_from_disk(
            cache_file_path,
        )
        logger.info(
            "load_collection_model() - Llamaindex loaded and ready for query..."
        )

    else:
        logger.error(
            f"load_collection_model() - collection {collection_id} has no model!"
        )
        raise ValueError("No model exists for this collection!")

    return index

React 前端

概述

Delphic 项目的前端我们选择 TypeScript + React + Material-UI(MUI),有两个原因。其一,MUI 是最流行的前端框架(React)里最流行的组件库,这个组合能让本项目触达庞大的开发者群体。其二,React 如今已经成熟且普遍受欢迎,它用虚拟 DOM 提供了很有价值的抽象,同时相对稳定,而且我们觉得它相当好上手——这同样降低了门槛。

前端项目结构

前端位于仓库的 /frontend 目录,其中与 React 相关的组件在 /frontend/src。你会注意到 frontend 目录里有一个 DockerFile,以及若干用于配置前端 Web 服务器 —— nginx —— 的目录与文件。

/frontend/src/App.tsx 是应用的入口文件。它定义了若干主组件,比如登录表单、抽屉布局以及创建集合的模态框。这些主组件会根据用户是否已登录、是否持有认证令牌来条件渲染。

DrawerLayout2 组件定义在 DrawerLayour2.tsx 文件里。它负责管理应用的布局,提供导航区与主内容区。

由于应用逻辑比较简单,我们不必引入 Redux 这类复杂的状态管理方案,用 React 的 useState hook 就够了。

从后端拉取集合列表

登录用户可见的集合会在 DrawerLayout2 组件里被取出并展示,整个过程可以拆成下面几步:

  1. 初始化状态变量:
const [collections, setCollections] = useState<CollectionModelSchema[]>([]);
const [loading, setLoading] = useState(true);

这里我们初始化两个状态变量:collections 用于存放集合列表,loading 用于标记集合是否正在拉取。

  1. 通过 fetchCollections() 函数为登录用户拉取集合:
const
fetchCollections = async () = > {
try {
const accessToken = localStorage.getItem("accessToken");
if (accessToken) {
const response = await getMyCollections(accessToken);
setCollections(response.data);
}
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
};

fetchCollections 函数带着用户的访问令牌调用 getMyCollections API,取回该用户的集合,然后用拿到的数据更新 collections 状态,并把 loading 置为 false 表示拉取完成。

展示集合

最新的集合在抽屉里这样展示:

< List >
{collections.map((collection) = > (
    < div key={collection.id} >
    < ListItem disablePadding >
    < ListItemButton
    disabled={
    collection.status != = CollectionStatus.COMPLETE | |
    !collection.has_model
    }
    onClick={() = > handleCollectionClick(collection)}
selected = {
    selectedCollection & &
    selectedCollection.id == = collection.id
}
>
< ListItemText
primary = {collection.title} / >
          {collection.status == = CollectionStatus.RUNNING ? (
    < CircularProgress
    size={24}
    style={{position: "absolute", right: 16}}
    / >
): null}
< / ListItemButton >
    < / ListItem >
        < / div >
))}
< / List >

你会注意到,每个集合的 ListItemButton 是否 disabled,取决于该集合状态是不是 CollectionStatus.COMPLETE、或者它是否没有模型(!collection.has_model)。只要这两个条件之一成立,按钮就被禁用,避免用户选中尚未处理完或没有模型的集合。当 CollectionStatus 处于 RUNNING 时,我们还会在按钮上叠一个加载转圈。

在另一个 useEffect hook 里,我们检查 collections 状态中是否存在状态为 CollectionStatus.RUNNING 或 CollectionStatus.QUEUED 的集合。若有,就设置一个定时器,每 15 秒(15,000 毫秒)重复调用一次 fetchCollections 来刷新集合状态。这样应用会周期性检查是否有集合处理完成,处理完毕时 UI 也随之更新。

useEffect(() = > {
    let
interval: NodeJS.Timeout;
if (
    collections.some(
        (collection) = >
collection.status == = CollectionStatus.RUNNING | |
collection.status == = CollectionStatus.QUEUED
)
) {
    interval = setInterval(() = > {
    fetchCollections();
}, 15000);
}
return () = > clearInterval(interval);
}, [collections]);

聊天视图组件

frontend/src/chat/ChatView.tsx 里的 ChatView 组件负责实现并展示聊天界面,让用户与某个集合交互。该组件建立一条 WebSocket 连接,与服务端实时收发消息。

ChatView 组件的主要能力包括:

  1. 与服务端建立并维护 WebSocket 连接。
  2. 以聊天形式展示用户与服务端的消息。
  3. 处理用户输入并把消息发给服务端。
  4. 根据服务端返回的消息更新消息状态与界面。
  5. 展示连接状态与错误,例如正在加载消息、正在连接服务端,或加载集合时出错。

这些能力合在一起,让用户能以非常顺滑、低延迟的方式与自己选定的集合交互。

聊天 WebSocket 客户端

ChatView 组件里的 WebSocket 连接用于建立客户端与服务端之间的实时通信。这条连接的建立与管理过程如下:

首先,我们要初始化 WebSocket 的引用:

const websocket = useRef`<WebSocket | null>`(null);

这里用 useRef 创建了一个 websocket 引用,用来持有负责通信的 WebSocket 对象。useRef 是 React 的一个 hook,它创建一个跨多次渲染持续存在的可变引用对象。当你需要持有某个可变对象(比如 WebSocket 连接)却又不想引发多余渲染时,它特别合适。

在 ChatView 组件里,WebSocket 连接需要在整个组件生命周期内保持存在,并且连接状态变化时不应触发重新渲染。用 useRef 就能把连接作为引用保留下来,组件只在真正发生状态变化(比如更新消息、展示错误)时才重新渲染。

setupWebsocket 函数负责建立 WebSocket 连接,并设置处理各类 WebSocket 事件的处理器。

总的来说,setupWebsocket 函数长这样:

const setupWebsocket = () => {
  setConnecting(true);
  // Here, a new WebSocket object is created using the specified URL, which includes the
  // selected collection's ID and the user's authentication token.

  websocket.current = new WebSocket(
    `ws://localhost:8000/ws/collections/${selectedCollection.id}/query/?token=${authToken}`,
  );

  websocket.current.onopen = (event) => {
    //...
  };

  websocket.current.onmessage = (event) => {
    //...
  };

  websocket.current.onclose = (event) => {
    //...
  };

  websocket.current.onerror = (event) => {
    //...
  };

  return () => {
    websocket.current?.close();
  };
};

注意其中有不少地方,我们依据 WebSocket 客户端提供的信息来驱动界面更新。

组件初次打开、我们尝试建立连接时会触发 onopen 监听器。在其回调里,组件更新状态以反映连接已建立、清除先前的错误,并标记没有等待回复的消息:

websocket.current.onopen = (event) => {
  setError(false);
  setConnecting(false);
  setAwaitingMessage(false);

  console.log("WebSocket connected:", event);
};

当通过 WebSocket 连接收到服务端的新消息时触发 onmessage。回调里解析收到的数据,并把来自服务端的新消息更新进 messages 状态:

websocket.current.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log("WebSocket message received:", data);
  setAwaitingMessage(false);

  if (data.response) {
    // Update the messages state with the new message from the server
    setMessages((prevMessages) => [
      ...prevMessages,
      {
        sender_id: "server",
        message: data.response,
        timestamp: new Date().toLocaleTimeString(),
      },
    ]);
  }
};

当 WebSocket 连接被关闭时触发 onclose。回调里会检查特定的关闭码(4000),据此弹出警告提示并相应更新组件状态,同时记录这条关闭事件:

websocket.current.onclose = (event) => {
  if (event.code === 4000) {
    toast.warning(
      "Selected collection's model is unavailable. Was it created properly?",
    );
    setError(true);
    setConnecting(false);
    setAwaitingMessage(false);
  }
  console.log("WebSocket closed:", event);
};

最后,当 WebSocket 连接出错时触发 onerror。回调里更新状态以反映错误,并记录这条错误事件:

websocket.current.onerror = (event) => {
  setError(true);
  setConnecting(false);
  setAwaitingMessage(false);

  console.error("WebSocket error:", event);
};

渲染聊天消息

在 ChatView 组件里,布局由 CSS 样式与 Material-UI 组件共同决定。主布局是一个 flex 显示、方向为列(column-oriented flexDirection)的容器,从而让容器内容纵向排列。

布局内有三个主要区域:

  1. 聊天消息区:占据大部分可用空间,展示用户与服务端之间的消息列表。它的 overflow-y 设为 ‘auto’,内容超出可用空间时可以滚动。每条消息用 ChatMessage 组件渲染,等待服务端回复时则用 ChatMessageLoading 组件展示加载状态。
  2. 分隔线:用 Material-UI 的 Divider 组件把聊天消息区与输入区分开,形成清晰的视觉分界。
  3. 输入区:位于底部,让用户输入并发送消息。它包含 Material-UI 的 TextField 组件,设置为可多行输入、最多 2 行。输入区还有一个用于发送消息的 Button 组件。用户既可以点击 “Send” 按钮发送,也可以按键盘上的 “Enter”。

ChatView 组件接收的用户输入,就是用户在 TextField 里键入的文本消息。组件处理这些文本输入,并通过 WebSocket 连接把它们发给服务端。

部署

前提条件

部署应用需要装好 Docker 与 Docker Compose。如果你用的是 Ubuntu 或其他常见 Linux 发行版,DigitalOcean 有一篇很棒的 Docker 教程,以及另一篇关于 Docker Compose的教程可以照着做。如果这两篇不合适,试试 Docker 官方文档。

构建与部署

该项目基于 django-cookiecutter,把它部署到一台虚拟机上并为指定域名提供 HTTPS 服务并不难。不过配置过程相对繁琐——这不是本项目的问题,而是配置证书、DNS 等本身就是一项内容较多的工作。

本指南我们就只在本地把它跑起来。之后也许会出一篇生产部署指南。在此之前,可以先看 Django Cookiecutter 项目文档入门。

本指南假定你的目标是把应用跑起来使用。如果你想做开发,多半不会用 --profiles fullstack 启动整个 compose 栈,而是会用 node 开发服务器来启动 React 前端。

部署前,先克隆仓库:

git clone https://github.com/yourusername/delphic.git

进入项目目录:

cd delphic

复制示例环境变量文件:

mkdir -p ./.envs/.local/
cp -a ./docs/sample_envs/local/.frontend ./frontend
cp -a ./docs/sample_envs/local/.django ./.envs/.local
cp -a ./docs/sample_envs/local/.postgres ./.envs/.local

编辑 .django 与 .postgres 配置文件,填入你的 OpenAI API key,并为数据库用户设一个独立密码。你还可以在 .django 文件里设置回答的 token 上限,或改用你想用的 OpenAI 模型。GPT4 是支持的,前提是你有访问权限。

用 --profiles fullstack 标志构建 docker compose 栈:

sudo docker-compose --profiles fullstack -f local.yml build

fullstack 标志会让 compose 从 frontend 目录构建一个 docker 容器,并与后端各容器一起启动。但构建生产级 React 容器非常耗时,因此不建议用这种方式开发。开发环境的配置方式请照 项目 readme.md 中的说明来做。

最后,把应用启动起来:

sudo docker-compose -f local.yml up

现在在浏览器里访问 localhost:3000 就能看到前端,并在本地使用 Delphic 应用了。

使用应用

设置用户

要真正使用这个应用(目前需要登录;我们打算之后允许把某些模型分享给未认证用户),你需要一个账号,超级用户或普通用户都行。但无论哪种,都得先有人在命令行里创建一个 superuser:

为什么要设置 Django superuser? Django 的 superuser 拥有应用内的全部权限,可以管理系统方方面面,包括创建、修改和删除用户、集合及其他数据。设置 superuser 让你能完全掌控并管理这个应用。

如何创建 Django superuser:

1 运行以下命令创建 superuser:

sudo docker-compose -f local.yml run django python manage.py createsuperuser

2 系统会提示你输入 superuser 的用户名、邮箱和密码。按要求填写即可。

如何用 Django admin 创建更多用户:

  1. 按上面的部署说明在本地启动你的 Delphic 应用。
  2. 在浏览器里访问 http://localhost:8000/admin 打开 Django admin 界面。
  3. 用刚才创建的 superuser 凭据登录。
  4. 在 “Authentication and Authorization” 一节下点击 “Users”。
  5. 点击右上角的 “Add user +” 按钮。
  6. 填写新用户必需的信息,例如用户名与密码,点击 “Save” 创建用户。
  7. 若要给新用户额外权限或把他设为 superuser,可在用户列表里点击他的用户名,滚动到 “Permissions” 一节按需配置权限,然后保存修改。

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。