使用Django Ninja进行尝试,第二部分(用户认证编写)

环境

苹果操作系统 Ventura
Python 3.10.7版本
Poetry 1.3.2版本

首先

这篇文章是之前那篇的续篇。
https://qiita.com/ps0317ix/items/344471dd89a10ab520cd

让我们立即开始

首先,我们需要创建一个针对用户的目录。

python manage.py startapp user

我会将models.py更改为以下内容。
由于本次主要使用Django-ninja,因此省略了有关Django模型的详细说明。

from django.db import models
from django.contrib.auth.models import PermissionsMixin, Group, Permission
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
from django.core.mail import send_mail
from django.utils.translation import gettext_lazy as _


class UserManager(BaseUserManager):
    use_in_migrations = True

    def _create_user(self, username, email, password, **extra_fields):
        if not email:
            raise ValueError('Emailを入力して下さい')
        email = self.normalize_email(email)
        username = self.model.normalize_username(username)
        user = self.model(username=username, email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self.db)
        return user

    def create_user(self, username, email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(username, email, password, **extra_fields)

    def create_superuser(self, username, email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        if extra_fields.get('is_staff') is not True:
            raise ValueError('is_staff=Trueである必要があります。')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('is_superuser=Trueである必要があります。')
        return self._create_user(username, email, password, **extra_fields)

    def update_or_create_user(self, username=None, email=None, password=None, username_new=None, **extra_fields):
        try:
            user = self.get(email=email)
            updated = False
            if username_new:
                user.username = username_new
                updated = True
            for key, value in extra_fields.items():
                if getattr(user, key) != value:
                    setattr(user, key, value)
                    updated = True
            if updated:
                user.save(using=self.db)
        except self.model.DoesNotExist:
            user = self.create_user(username, email, password, **extra_fields)
        return user


class User(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(_("username"), max_length=50, blank=True)
    email = models.EmailField(_("email"), unique=True)
    avatar = models.ImageField(_("avatar"), upload_to='avatars', blank=True)
    avatar_url = models.URLField(_("avatar_url"), max_length=1500, blank=True)
    router = models.JSONField(_("router"), blank=True, null=True)
    is_staff = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    groups = models.ManyToManyField(Group, verbose_name=_("groups"), blank=True, related_name="users")
    user_permissions = models.ManyToManyField(Permission, verbose_name=_("user permissions"), blank=True, related_name="users")
    created_at = models.DateTimeField(_("created_at"), auto_now_add=True)
    updated_at = models.DateTimeField(_("updated_at"), auto_now=True)

    objects = UserManager()
    USERNAME_FIELD = "email"
    EMAIL_FIELD = "email"
    REQUIRED_FIELDS = ['username']

    class Meta:
        db_table = 'user_user'
        verbose_name = "user"
        verbose_name_plural = "users"

    def clean(self):
        super().clean()
        self.email = self.__class__.objects.normalize_email(self.email)

    def email_user(self, subject, message, from_email=None, **kwargs):
        send_mail(subject, message, from_email, [self.email], **kwargs)

接下来,我们将定义schema。

from pydantic.types import SecretStr
from ninja import Schema
from ninja import ModelSchema
from django.contrib.auth import get_user_model


class UserSchema(ModelSchema):
    class Config:
        model = get_user_model()
        model_fields = ['id', 'username', 'email', 'is_staff', 'is_active', 'is_superuser']


class UseLogin(Schema):
    username: str
    email: str
    password: SecretStr


class UserIn(Schema):
    id: str
    username: str
    email: str
    openai_api_key: str


class UserOut(Schema):
    id: int
    username: str
    email: str
    roles: list[str] = ['client']

如果上述事项完成,我们将继续创建API。

from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model

from ninja_extra import (
    http_get, http_post, http_generic, http_put, http_delete,
    api_controller, status, ControllerBase, pagination
)
from ninja_extra.controllers.response import Detail
from ninja_jwt.authentication import JWTAuth

from .schema import UserSchema, UseLogin, UserIn, UserOut,

@api_controller('user', tags=['User'], auth=[JWTAuth()])
class UserController(ControllerBase):
    user_model = get_user_model()

    @http_get("/me", response=UserOut)
    def get_user(self, request):
        roles = []
        if request.user.is_superuser:
            roles.append('admin')
        elif request.user.is_staff:
            roles.append('staff')
        else:
            roles.append('client')

        if len(request.user.avatar_url) > 0:
            avatar = request.user.avatar_url
        else:
            avatar = request.user.avatar
        return {
            'id': request.user.id,
            'username': request.user.username,
            'email': request.user.email,
            'avatar': avatar,
            'roles': roles
        }

    @http_post('/create', response=UserSchema)
    def create_user(self, payload: UseLogin):
        return User.objects.create_user(**payload.dict())

    @http_put('/update', response=UserSchema)
    def update_user(self, request, payload: UserIn):
        user = self.user_model.objects.update_or_create_user(
            username=request.user.username,
            email=request.user.email
        )
        return user

    @http_delete('/{int:user_id}', response=Detail(status_code=status.HTTP_204_NO_CONTENT))
    def delete_user(self, user_id: int):
        user = self.get_object_or_exception(self.user_model, id=user_id)
        user.delete()
        return self.create_response('', status_code=status.HTTP_204_NO_CONTENT)

返回到DJANGO_NINJA_TEMPLETE目录,并注册上述的Controller和apps。

from ninja_jwt.controller import NinjaJWTDefaultController
from ninja_extra import NinjaExtraAPI

from user.api import UserController # 追加

api = NinjaExtraAPI()
api.register_controllers(NinjaJWTDefaultController)
api.register_controllers(UserController) # 追加
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'user', # 追加
]

生成迁移文件 (generate migration file)

python manage.py makemigrations
# ImageFieldを入れる場合、pip install Pillowしてください

然后,产生迁移 ,

python manage.py migrate
スクリーンショット 2023-03-13 19.13.46.png

确定

使用以下命令创建超级用户

python manage.py createsuperuser
スクリーンショット 2023-03-13 19.17.00.png

最终

只用非常少的代码就可以实现,并且比Django更快,还可以自动生成文档等等,难道只有我觉得它是革命性的吗?

因为我们正在进行这样的服务运营,所以如果您感兴趣的话,请务必点击以下链接查看:
https://data-lab.project-g.co.jp?utm_source=Qiita&utm_medium=qiita&utm_campaign=qiita_20230313

请参考

 

※2023/05/17补充
已发布部署教程
https://qiita.com/ps0317ix/items/07af7a863ff63ad3dc81

广告
将在 10 秒后关闭
bannerAds