Skip to content

Commit

Permalink
drf 登录/注册功能
Browse files Browse the repository at this point in the history
  • Loading branch information
Sonder-MX committed Jun 12, 2023
1 parent 9175864 commit 01cada4
Show file tree
Hide file tree
Showing 21 changed files with 715 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"python.analysis.typeCheckingMode": "basic"
}
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# DRF + Vue 用户登录模块
# Django + DRF

开发 ing......
## 1.Django + DRF 用户登录注册

Django+DRF+Vue 实现用户登录
👉 [django app](/da_user)
👉 [登录/注册前端页面](/frontend/user-login.html)
28 changes: 28 additions & 0 deletions da_token/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from rest_framework_simplejwt.serializers import (TokenObtainPairSerializer, TokenRefreshSerializer)


class DaTokenSerializer(TokenObtainPairSerializer):
"""自定义获取token序列化器"""

def validate(self, attrs):
data = super().validate(attrs)
refresh = self.get_token(self.user) # 获取Token对象
data['refresh'] = str(refresh)
data['access'] = str(refresh.access_token)
return data

@classmethod
def get_token(cls, user):
token = super().get_token(user)
token['username'] = user.username
token['is_staff'] = user.is_staff
token['is_superuser'] = user.is_superuser
return token


class DaRefreshTokenSerializer(TokenRefreshSerializer):
"""自定义刷新token序列化器"""

def validate(self, attrs):
data = super(DaRefreshTokenSerializer, self).validate(attrs)
return data
11 changes: 11 additions & 0 deletions da_token/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from rest_framework_simplejwt.views import (TokenObtainPairView, TokenRefreshView)

from .serializers import DaRefreshTokenSerializer, DaTokenSerializer


class DaTokenObtainPairView(TokenObtainPairView):
serializer_class = DaTokenSerializer


class DaTokenRefreshView(TokenRefreshView):
serializer_class = DaRefreshTokenSerializer
Empty file added da_user/__init__.py
Empty file.
5 changes: 5 additions & 0 deletions da_user/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.contrib import admin

from .models import DaUser

admin.site.register(DaUser)
6 changes: 6 additions & 0 deletions da_user/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class DaUserConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'da_user'
36 changes: 36 additions & 0 deletions da_user/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Generated by Django 4.1.7 on 2023-06-11 03:34

from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]

operations = [
migrations.CreateModel(
name='DaUser',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('email', models.EmailField(max_length=60, unique=True, verbose_name='邮箱地址')),
('username', models.CharField(blank=True, max_length=20, null=True, verbose_name='用户昵称')),
('date_joined', models.DateTimeField(auto_now_add=True, verbose_name='注册时间')),
('is_active', models.BooleanField(default=True)),
('is_staff', models.BooleanField(default=False)),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
],
options={
'verbose_name': '用户',
'verbose_name_plural': '用户',
'db_table': 'da_user',
},
),
]
17 changes: 17 additions & 0 deletions da_user/migrations/0002_remove_dauser_last_login.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.1.7 on 2023-06-11 03:36

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('da_user', '0001_initial'),
]

operations = [
migrations.RemoveField(
model_name='dauser',
name='last_login',
),
]
Empty file added da_user/migrations/__init__.py
Empty file.
44 changes: 44 additions & 0 deletions da_user/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from django.contrib.auth.models import (AbstractBaseUser, BaseUserManager, PermissionsMixin)
from django.db import models


class UserManager(BaseUserManager):

def create_user(self, email, password, **kwargs):
if not email:
raise ValueError("Users must have an email address")
user = self.model(email=self.normalize_email(email), **kwargs)
user.set_password(password)
user.save(using=self._db)
return user

def create_superuser(self, email, password, **kwargs):
kwargs.setdefault("is_staff", True)
kwargs.setdefault("is_superuser", True)
if kwargs.get('is_staff') is not True:
raise ValueError('Superuser must have is_staff=True.')
if kwargs.get('is_superuser') is not True:
raise ValueError('Superuser must have is_superuser=True.')
return self.create_user(email, password, **kwargs)


class DaUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(verbose_name="邮箱地址", max_length=60, unique=True)
username = models.CharField(verbose_name="用户昵称", max_length=20, blank=True, null=True)
date_joined = models.DateTimeField(verbose_name="注册时间", auto_now_add=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)

last_login = False

objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []

def __str__(self) -> str:
return self.username if self.username else self.email

class Meta:
db_table = "da_user"
verbose_name = '用户'
verbose_name_plural = verbose_name
28 changes: 28 additions & 0 deletions da_user/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from rest_framework import serializers

from .models import DaUser


class UserListSerializer(serializers.ModelSerializer):
"""用户列表序列化器"""

class Meta:
model = DaUser
fields = ('id', 'username', 'email')


class UserRegisterSerializer(serializers.ModelSerializer):
"""用户注册序列化器"""
password = serializers.CharField(write_only=True, help_text='密码')

class Meta:
model = DaUser
fields = ['email', 'password']

# 验证
# def validate(self, attrs):
# return attrs

# 保存
def create(self, validated_data):
return DaUser.objects.create_user(**validated_data)
3 changes: 3 additions & 0 deletions da_user/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.
21 changes: 21 additions & 0 deletions da_user/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from rest_framework import generics, status, viewsets
from rest_framework.response import Response

from .models import DaUser
from .serializers import UserListSerializer, UserRegisterSerializer


class UserListViewSet(viewsets.ReadOnlyModelViewSet):
queryset = DaUser.objects.all()
serializer_class = UserListSerializer


class UserRegisterApiView(generics.CreateAPIView):
serializer_class = UserRegisterSerializer

# 注册时检查用户邮箱是否存在
def post(self, request, *args, **kwargs):
email = request.data.get('email')
if DaUser.objects.filter(email=email).exists():
return Response({'message': "该邮箱已被注册!"}, status=status.HTTP_400_BAD_REQUEST)
return self.create(request, *args, **kwargs)
Empty file added django_advance/__init__.py
Empty file.
16 changes: 16 additions & 0 deletions django_advance/asgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
ASGI config for django_advance project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.1/howto/deployment/asgi/
"""

import os

from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_advance.settings')

application = get_asgi_application()
141 changes: 141 additions & 0 deletions django_advance/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"""
Django settings for django_advance project.
Generated by 'django-admin startproject' using Django 4.1.7.
For more information on this file, see
https://docs.djangoproject.com/en/4.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.1/ref/settings/
"""

import os
from datetime import timedelta

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-(3aa@@!=ma%$1!jzt*av!@w0731)u0raa_hf5!s#+%vx2^4=r_'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ["*"]

# Application definition
INSTALLED_APPS = [
'corsheaders', # 跨域
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'da_user',
]

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware', # 跨域
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'django_advance.urls'

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

WSGI_APPLICATION = 'django_advance.wsgi.application'

# Database
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_advance',
'USER': 'root',
'PASSWORD': 'sql_1',
'HOST': '127.0.0.1',
'PROT': 3306,
}
}

# Password validation
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]

# Internationalization
# https://docs.djangoproject.com/en/4.1/topics/i18n/
LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.1/howto/static-files/
STATIC_URL = 'static/'

# Default primary key field type
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# User Model
AUTH_USER_MODEL = 'da_user.DaUser'

# 跨域
CORS_ORIGIN_ALLOW_ALL = True

# rest_framework
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': ['rest_framework_simplejwt.authentication.JWTAuthentication',],
}

# simple jwt
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30),
'REFRESH_TOKEN_LIFETIME': timedelta(days=10),
}
Loading

0 comments on commit 01cada4

Please sign in to comment.