使用 uv 创建 Django 项目

该项目将以顶部的文本框开始,用于添加待办事项,并以水平组件的形式列出当前待办事项。第一个版本将仅支持项目的创建和完成。

我们希望拥有的下两个功能是截止日期的概念和侧边栏,它允许我们按今天截止、明天截止和逾期的任务进行筛选,并使用自然语言添加待办事项,例如写入“明天 8:30 给医生打电话”应该会创建一个标题为“给医生打电话”的项目,截止日期为第二天上午 8:30。

这些类型的功能可以从 TDD 中受益匪浅,因为它使我们能够专注于如何处理自然语言,而不必过多担心如何将其与前端集成。

Prototype of the UI of the to-do app, with a textbox on top, a button with text

使用 uv 创建项目

我们将使用“uv”启动该项目,其网站上的定义是

“一个非常快的 Python 包和项目管理器,用 Rust 编写 [...] 一个可以替代 pip、pip-tools、pipx、poetry、pyenv、twine、virtualenv 等的工具。”

我特别感兴趣的是使用“pyproject.toml”和虚拟环境来简单管理依赖项。

要在您的机器上安装 uv,请按照其网站上的说明进行操作。

❯ uv init
Initialized project `todo-mx`
❯ uv venv
Using CPython 3.12.8
Creating virtual environment at: .venv
Activate with: source .venv/bin/activate
❯ source .venv/bin/activate

现在我们有了一个项目和一个虚拟环境,我们可以添加前两个依赖项:Django 和 pytest。我们还将添加一个可选依赖项 pytest-sugar,它为我们的测试提供了更好的界面。

❯ uv add django
Resolved 5 packages in 248ms
Installed 3 packages in 350ms
 + asgiref==3.8.1
 + django==5.1.4
 + sqlparse==0.5.3
❯ uv add pytest pytest-sugar --dev
Resolved 12 packages in 206ms
Installed 6 packages in 14ms
 + iniconfig==2.0.0
 + packaging==24.2
 + pluggy==1.5.0
 + pytest==8.3.4
 + pytest-sugar==1.0.0
 + termcolor==2.5.0

创建 django 项目

要在当前目录中创建 Django 项目,我们可以运行以下 uv 命令:

uv run django-admin startproject todomx .

我们可以通过运行“runserver”命令来确保安装有效:

❯ uv run python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
January 01, 2025 - 16:12:00
Django version 5.1.4, using settings 'todomx.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

打开链接后,我们会看到 Django 欢迎屏幕

Home page for Django with the text

覆盖默认的用户身份验证模型

在运行待处理的迁移之前,正如执行“runserver”命令时所建议的那样,我们将覆盖 Django 的默认用户模型,这是新项目的最佳实践。有很多文献说明了为什么这是一个好主意,包括官方文档。

稍后我们可能想要将其纳入项目,但我们希望保持简单并尽快启动和运行,所以让我们只需创建一个名为“core”的应用程序,创建一个从“AbstractUser”继承的“UserProfile”类,并将我们的项目设置为使用此类作为其身份验证模型。

❯ uv run python manage.py startapp core

让我们在“core/models.py”中添加模型:

from django.contrib.auth.models import AbstractUser

class UserProfile(AbstractUser):
    pass

在“settings.py”中,让我们添加新的应用并更改身份验证用户模型:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'core', # <-- NEW
]

AUTH_USER_MODEL = 'core.UserProfile' # <-- NEW

我们现在可以进行迁移、应用它们,并为应用程序创建超级用户:

❯ uv run python manage.py makemigrations
Migrations for 'core':
  core/migrations/0001_initial.py
    + Create model UserProfile
❯ uv run python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, core, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0001_initial... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying core.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying sessions.0001_initial... OK
❯ uv run python manage.py createsuperuser
Username: admin
Email address: admin@email.com
Password:
Password (again):
This password is too short. It must contain at least 8 characters.
This password is too common.
This password is entirely numeric.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
❯

再次使用“runserver”运行应用程序并打开“localhost:8000 / admin”将显示Django的管理页面:

Django admin site

总结第 1 部分,我们可以为 `UserProfile` 注册一个管理视图:

# core/admin.py

from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import UserProfile

@admin.register(UserProfile)
class UserProfileAdmin(UserAdmin):
    model = UserProfile
    list_display = ['email', 'username']

刷新管理站点将会向用户展示管理界面

User admin in the main page of the admin siteUser admin page in the admin site

这就是我们项目的初始设置!在第 2 部分中,我们将使用 pytest 实现 Todo 模型的第一个版本