本文将记录一下我在Django框架开发学习过程中的一些步骤(坑),方便查阅。
安装与框架介绍
Django安装与项目创建
安装Django
首先需要安装Django的包,直接pip install即可,如果出现超时,可以换源。
bash
pip install -i https://pypi.douban.com/simple django
创建Django项目
PyCharm专业版在创建项目的时候会出现一个左侧栏,能够直接帮我们创建Django项目。但是我用的是免费的社区版,所以需要使用命令行创建。
在要创建项目的文件夹下打开命令行,输入如下命令:
bash
django-admin startproject 项目名
注意,我使用anaconda管理我的包,所以我的django-admin.exe在D:\anaconda\envs\虚拟环境名\Scripts这里,如果报错需要输入绝对地址。
创建App
创建了Django项目后,我们还需要创建一个App应用。在命令行输入如下:
bash
python manage.py startapp App名
这时可能报错:
bash
ImportError: Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?
按照提示,我们需要启动虚拟环境,我直接在anaconda里的虚拟环境中输入上面的命令即可运行。记得要先activate哦。
然后在新创建的apps.py中我们会发现一个类WebConfig。(这个web是我的app名)
我们要把这个添加到项目名文件夹下的settings.py中,如下所示:
Django框架介绍
默认文件
完成上述步骤后,我们的文件树应该显示如下:(其他的文件是我训练模型创建的,和Django无关,忽略)
其中,红色框框是创建Django项目时出现的。
我们需要关注的是manage.py,正如我们刚刚创建App时用到的那样,manage.py负责管理Django项目,我们以后会经常用到它,但我们不需要更改它。
其他的文件是一些配置文件,我们需要关注setting.py和urls.py。settings.py顾名思义是一些设置,例如模板的地址、连接数据库等,我们刚刚就配置了app的相关信息。
urls.py建立起了网页和函数的对应关系,比如默认的内容是:
python
urlpatterns = [
path('admin/', admin.site.urls),
]
意思是admin这个网页和admin.site.urls这个函数绑定,当我们访问admin网页时,后端会执行这个函数的操作。
蓝色框框是创建App时出现的。我们需要重点关注views.py,也就是视图文件,我们在这个文件里写前端访问网页时后端需要执行的函数。
静态文件和模板
我们在写网页的时候往往会用到一些静态文件和模板(网页),那么这些文件应该放在哪里呢?我们再看到settings.py中有个静态变量是TEPLATES,这就是我们的模板,其中DIRS是它所在的地址,默认为空,Django会在项目名下寻找templates文件夹。
但是我们如果不想把templates放在项目名文件夹下,可以修改DIRS,比如我把templates文件夹放到和项目名文件夹同级的地方,可以这样写:
python
import os
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'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',
],
},
},
]
此时我的templates文件夹在这里就可以被找到了。
同样的,我们来找一下静态文件,在settings.py中的这里:
上图已经被我修改过了,这样我可以把静态文件放在assets文件夹中,和项目名同级。
需要注意的是,在网页中我们引用静态文件的地址需要和STATIC_URL中一致。
运行Django
接下来我们来测试一下运行效果。我们可以先简单的写一个网页,或者我直接用找的模板。如何让Django找到我们的网页呢?
写一个简单的网页
首先在urls.py里,建立网页和函数的对应关系。我们把原来的默认admin网页注释掉,加上自己的网页,例如index网页,和views文件中的index函数对应:
python
urlpatterns = [
# path('admin/', admin.site.urls),
path('index/', views.index)
]
在views.py中,我们加上index函数,用于处理用户访问index页面时的请求。
python
def index(request):
name = 'Roslin'
return render(request, 'index.html', {'user': name})
request是用户访问页面时发来的请求,我们在这个函数里可以对他进行一些处理,这个之后再写。现在我们先简单地返回一个名字。使用render函数,把name返回给网页,注意传参必须是字典类型。
在index.html中,我们可以处理后端传来的参数。
html
<p>Hello, {{user}}</p>
这样我们就完成了在Django框架下一个简单页面的制作。
运行Django
接下来我们运行Django,和创建App的方法类似,注意同样需要在虚拟环境下。
bash
python manage.py runserver 8082
其中,8082是我指定的端口,如果不写,将默认在8000端口,大家可以先运行看看自己的8000端口是否被占用。
运行成功后如下图所示:
我们打开127.0.0.1:8082/index/, 就可以看到我们刚刚写的界面了。注意不加index并不会默认到index界面哦。
Django+MySQL数据库
配置数据库
Django提供工具可以帮助我们创建数据库,但是我这里用Navicat更方便。这里我们利用数据库实现一个用户登录的功能。事先创建好数据库和user表后,我们可以将其配置到Django中。
在settings.py中,我们找到数据库的配置。
把默认的注释掉,换乘自己的数据库信息:
python
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': '数据库名字',
'USER': 'root',
'PASSWORD': '密码',
'HOST': 'localhost',
'PORT': 3306,
}
}
我们还需要下载mysqlclient包。
bash
pip install mysqlclient
注意这个包有版本要求,目前要求1.4.3以上的,如果已经安装的朋友们注意下版本哦。
接下来,我们将数据库的表导入到Django。
bash
python manage.py inspectdb > models.py
在models.py中我们可以看到数据库的表结构。
之后将models.py的内容复制到我们App目录下的models.py,并将红框部分改为True。然后就可以将生成的models.py删掉了。
接下来我们进行迁移,将django与数据库进行同步,后续可以进行增删改查。
bash
python manage.py migrate
运行成功后,刷新一下Navicat,可以看到除了自己创建的user表外,Django帮我们创建了很多表,但是我们不需要关注这些表。
使用数据库实现用户登录
创建表单类
我们知道实现用户登录一般是通过前端提交一个表单,后端判断用户名和密码是否正确。在Django中提供了Form类,能够实现表单的功能。
我们可以新建一个forms.py,在这里写我们需要的表单。创建一个LoginForm登录表单,包含邮箱和密码,这就是用户登录需要输入的内容。其中,label是前端页面会显示的标签。
python
from django import forms
class LoginForm(forms.Form):
email = forms.CharField(label="邮箱", max_length=20, widget=forms.TextInput(attrs={'class': 'form-control'}))
passwd = forms.CharField(label="密码", max_length=50, widget=forms.PasswordInput(attrs={'class': 'form-control'}))
用户登录功能
然后我们就可以利用这个表单类和数据库实现用户登录的主要功能了。
当前端发来的请求是GET,也就是用户刚刚打开这个登录网页时,我们只需要返回一个空的表单。
python
def login(request):
if request.method == 'GET':
login_form = LoginForm()
return render(request, 'login.html', {'login_form': login_form})
当前端发来的请求是POST,也就是用户提交了表单时,我们可以生成一个LoginForm对象。调用它的is_valid()函数,可以检查表单是否有效(是否为空、长度是否满足等)。如果表单有效,则检查用户是否存在、密码是否正确,如果正确,则跳转index主页;如果错误,则留在login页面。
python
login_form = LoginForm(request.POST)
if login_form.is_valid():
email = str(login_form.cleaned_data.get('email'))
password = str(login_form.cleaned_data.get('passwd'))
# 用户存在
if User.objects.filter(email=email):
user = User.objects.get(email=email)
hash_passwd = sha256(password.encode('utf-8')).hexdigest()
# 密码正确
if user.password == hash_passwd:
return render(request, 'index.html')
# 用户不存在或密码错误
return render(request, 'login.html', {'login_form': login_form})
网页编写
在前端网页中,我们只需要简单的写一个form表单即可。有了Django的Form类,使用下列语句,和直接写<label>和<input>的前端效果是一样的。
html
<form action="#" method="post">
<div class="row g-4">
<div>
{{ data.email.label_tag }}
{{ data.email }}
</div>
<div>
{{ data.passwd.label_tag }}
{{ data.passwd }}
</div>
<div class="col-12" align="center">
<button type="submit">登录</button>
</div>
</div>
</div>
</form>
别忘了在urls.py中将网页和函数对应起来。用刚刚的方式就可以运行查看效果了。
但是这样会报错:
这是个安全性问题,只需要在网页的form里加上这个即可:
python
<form action="#" method="post">
{% csrf_token %}
使用session保持用户登录
但是编写一个网页我们还需要保持用户登录。在Django中,我们可以使用session实现这一功能。如果函数判断登录成功,则在session中加上这些信息。
python
request.session['is_login'] = True
request.session['user_id'] = user.id
request.session['user_name'] = user.name
在函数一开始,还需要加上判断用户是否登录,避免重复登录。
python
if request.session.get('is_login', None):
return HttpResponseRedirect(reverse('index'))
在页面中,我们可以用session来判断用户是否登录,如果登录,显示用户名。
html
{% if request.session.is_login %}
<li class="dropdown">
<button>Hello, {{ request.session.user_name }}</button>
<ul>
<li><a href="../logout">退出登录</a></li>
</ul>
</li>
{% else %}
<li><a href="../login"><button>登录</button></a></li>
{% endif %}
当然,有了保持登录的功能,还需要能够登出。
python
def logout(request):
if not request.session.get('is_login', None):
return redirect("../index")
request.session.flush()
return redirect("../index")