赞
踩
Django
实现简单的注册登录功能流水帐结构的介绍,适合Django
的新手作为Hello World级别的第一个练习项目。
项目使用Docker
容器提供环境,Python
版本3.8.10。
创建一个目录account_app,作为本次项目的主目录。
创建一个本地的虚拟环境,不为别的,,就是为了在vscode
里可以使用自动补全。
py -m venv env
创建一个虚拟环境。python -m venv env
创建一个虚拟环境。Django
项目切换到account_app目录下,使用命令django-admin startporject saccount_app .
创建一个Django
项目。使用django-admin startapp accounts
创建一个小应用。
Django
简单的先设置一下:
MySQL
)。django-crispy-forms
工具包(至于这个包的信息去pypi查。TIME_ZONE = 'Asia/Shanghai' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'accounts', 'HOST': 'mysqldb', 'port': 3306, 'USERNAME': 'root', 'PASSWORD': 'password', } INSTALLED_APPS = [ ..... # forms crispy 'crispy_forms', # custom app 'accounts', ] AUTH_USER_MODEL = 'accounts.Account' TEMPLATES = [ { 'DIRS': ['templates'], ] STATICFILES_DIRS = [ BASE_DIR / "static", ] # Crispy Forms options CRISPY_TEMPLATE_PACK = 'bootstrap4' }
先简单的创建应用的模型,继承自Django
自带的AbstractUser。
class Account(AbstractUser):
token = models.CharField(max_length=256, blank=False)
Docerk
相关的文件先创建一个runserver.sh, 为了方便启动项目
#!/bin/sh
# Make migrate
python manage.py makemigrations
python manage.py migrate
# Start Server
python manage.py runserver 0.0.0.0:8000
创建requirements.txt
记录需要安装的Python
包。目前只需要这几个。因为mysqlclient
的特殊,它需要一些以来所以,放在了容器创建的时候单独安装。
django>=3.0
django-mysql>=3.8
django-crispy-forms
创建Dockerfile
FROM python:3.8.10-alpine
ENV PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt requirements.txt
COPY . /app
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk update \
&& apk add --virtual python3-dev musl-dev build-base \
&& apk add --no-cache mariadb-dev \
&& pip config set global.index-url https://mirrors.aliyun.com/pypi/simple \
&& pip install --upgrade pip \
&& pip install mysqlclient \
&& apk del build-base \
&& pip install -r requirements.txt
创建docker-compose.yml
这里可能会出现很多小问题,自己谷歌吧。如果MySQL
无法自己创建初始的数据库,就在本地的db文件下自己添加sql
文件创建用的数据库。这里在后面启动的时候,创建数据库的操作只会发生在第一次构建容器的时候(说的不具体,具体的写在了官方文档里),如果因为某些错误没有建立初始的数据库,可以在启动构造容器的时候强制重构。
version: '3' services: app: build: . ports: - 8000:8000 volumes: - .:/app command: sh runserver.sh depends_on: - mysqldb mysqldb: image: mysql container_name: account_mysql volumes: - ./db:/docker-entrypoint-initdb.d/:ro environment: - MYSQL_ROOT_PASSWORD=password - MYSQL_DATABASE=accounts
创建static和templates文件夹
存放静态文件和模板文件,具体看Django
的文档。
urlpatterns = [
path('', home_view, name='home'),
path('regist/', regist_view, name='regist'),
path('login/', login_view, name='login'),
path('logout/', logout_view, name='logout'),
path('forget_password/', forget_password_view, name='forgetpasswd'),
path('new_password/', new_password_view, name='new_password'),
path('activate/<token>/', activate_view, name='activate'),
]
urlpatterns = [
path('account/', include('accounts.urls')),
]
html
模板文件,在templates文件夹下添加account文件夹与accounts应用相关的模板文件放到其中。至于css
、js
和图片文件放在static文件夹下。 def home_view(request):
return render(request, 'account/index.html')
def regist_view(request):
return render(request, 'account/form.html')
def login_view(request):
return render(request, 'account/form.html')
使用命令 docker-compose up --build -d
或者可以不用-d
。命令的具体细节看官方文档。然后在浏览器查看localhost:8000/account/login
等前面文件中定义的链接。
至此算是简单的把项目创建出来了。剩下的就是完善具体的accounts应用下的功能了。
前面的步骤是在创建项目,现在开始进一步完善功能。下面以注册功能为主介绍。
使用Django
内置forms
。实现表单、表单字段的校验和使用django-crispy-forms
与bootstrap4
简单的美化表单。所有的具体细节多看官方文档都会知晓。
注册表单文件accounts/forms.py
class RegistForm(forms.Form): username = forms.CharField( label='username', required=True, min_length=4, max_length=80, ) email = forms.EmailField( label='email', required=True, ) first_name = forms.CharField( label='first_name', required=True, min_length=1, max_length=80, ) last_name = forms.CharField( label='last_name', required=True, min_length=1, max_length=80, ) password = forms.CharField( label='passowrd', widget=forms.PasswordInput, required=True, min_length=8, max_length=80, ) passwd_confirm = forms.CharField( label='passwd_confirm', widget=PasswordInput, required=True, min_length=8, max_length=80, ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = FormHelper() self.helper.form_id = "id-registForm" self.helper.form_method = 'post' self.helper.form_action = 'regist' self.helper.form_show_labels = False self.helper.layout = Layout( Div( HTML('<span><i class="icon icon-user"></i></span>'), css_class="form-icon" ), Field('username', css_class="form-control item", placeholder='usernmae'), Field('email', css_class="form-control item", placeholder='Email'), Row( Column( Field('first_name', css_class="form-control item", placeholder='First Name'), css_class="form-group col-md-6 mb-0"), Column( Field('last_name', css_class="form-control item", placeholder='Last Name'), css_class="form-group col-md-6 mb-0"), css_class="form-row" ), Field('password', css_class="form-control item", placeholder='Password'), Field('passwd_confirm', css_class="form-control item", placeholder='Password Confirm'), ButtonHolder( Submit('submit', 'Regist', css_class="btn btn-block create-account") ) ) def clean_username(self): value = self.cleaned_data['username'] if Account.objects.filter(username=value): raise forms.ValidationError('Username has been registed!', code='invalide') else: return value def clean_email(self): value = self.cleaned_data['email'] if Account.objects.filter(email=value): raise forms.ValidationError('Email has been used!', code='invalid') else: return value def clean_password(self): value = self.cleaned_data['password'] if value.isdigit(): raise forms.ValidationError('Password must hava characters', code='invalid') else: return value def clean_passwd_confirm(self): value = self.cleaned_data['passwd_confirm'] try: target = self.cleaned_data['password'] except Exception as e: raise forms.ValidationError('Password is valid!', code='invalid') else: if value != target or target is None: raise forms.ValidationError('Passwords are not same!', code='invalid') else: return value
有了表单之后,接着需要处理来自表单的数据和完善注册视图函数的功能。
token
本项目使用了pyJWT
这个包来产生token
。但是从之前的Dockerfile中可以知道,本次项目中使用的基础环境是一个alpine linux
。所以安装pyJWT
的时候得稍微费点力,如果想使用更多的生成token
的算法,还需要名为cryptography
的包。所以又得安装一些依赖来编译这个包。实际上本次项目也没有用到其中的算法。
完善后的Dockerfile
FROM python:3.8.10-alpine
ENV PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt requirements.txt
COPY . /app
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk update \
&& apk add --virtual python3-dev musl-dev build-base \
&& apk add --no-cache mariadb-dev libffi-dev \
&& pip config set global.index-url https://mirrors.aliyun.com/pypi/simple \
&& pip install --upgrade pip \
&& pip install mysqlclient cryptography \
&& apk del build-base \
&& pip install -r requirements.txt
可以使用命令单独编译这个app容器docker-compose up --detach --build app
。记得在requirements.txt中添加pyJWT
。
如果在Django
里直接发送邮件可能会有点慢,所以本项目使用celery
来异步发送,选择了redis
作为celery
的消息和返回结果存储的工具。
celery:
build: .
command: celery -A account_app worker -l info
volumes:
- .:/app
depends_on:
- redis
redis:
image: redis
Django
配置使用celery
和邮件服务import os from celery import Celery # Set the default Django settings module for the 'celery' program. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'account_app.settings') app = Celery('account_app') # Using a string here means the worker doesn't have to serialize # the configuration object to child processes. # - namespace='CELERY' means all celery-related configuration keys # should have a 'CELERY_' prefix. app.config_from_object('django.conf:settings', namespace='CELERY') # Load task modules from all registered Django apps. app.autodiscover_tasks()
celery
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app
__all__ = ('celery_app',)
@shared_task(name="send_email")
def send_email(mail_subject, message, to):
email = EmailMessage(
mail_subject,
message,
to=to
)
email.send()
完善后的注册视图函数
def regist_view(request): if request.method == 'POST': regist_form = RegistForm(request.POST) if regist_form.is_valid(): username = regist_form.cleaned_data['username'] email = regist_form.cleaned_data['email'] first_name = regist_form.cleaned_data['first_name'] last_name = regist_form.cleaned_data['last_name'] password = regist_form.cleaned_data['password'] new_account = Account.objects.create( username=username, email=email, first_name = first_name, last_name = last_name, ) new_account.set_password(password) # Set verify token here new_account.token = VerifyToken.token_generator( { 'id': new_account.pk, 'username': username, } ) # set user not active new_account.is_active = False new_account.save() # send activate emial here. current_site = get_current_site(request) mail_subject = 'Activate your account' message = render_to_string( 'email/activate_email.html', { 'user': new_account, 'domain': current_site, 'token': new_account.token, } ) send_email.delay(mail_subject, message, [email,]) return render(request, 'account/info.html', { 'info': 'Success! please activate your account from E-mail.'}) else: return render(request, 'account/form.html', {'form': regist_form, 'title': 'Register'}) form = RegistForm() return render(request, 'account/form.html', {'form': form, 'title': 'Register'})
至此简单的注册功能算是实现了。其他的功能类似注册功能一样实现。
本项目实现的功能都是最最简单的,所以作为Django
入门的第一个小例子非常合适。自我感觉没人会看到最后,所以本文的源代码链接就放在最后了。欢迎分享更多的知识。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。