python + django 搭建网页(尝试5):用户登录
参考来源:
[1] https://zhuanlan.zhihu.com/p/425426994
[2] https://zhuanlan.zhihu.com/p/423436751
[3] https://www.runoob.com/django/django-admin-manage-tool.html
[3] https://www.runoob.com/django/django-model.html
看了 [1-4] ,我意识到接口都是现成的,只需要做适当的设置,把现成的东西组装起来。
1. 模型+数据库
我之前建的站叫做 mysite,然后在 mysite 下试了一下模型+数据库,感觉好像在 mysite 的基础上再安装一个 app,底层可能就是新增一个类。
django-admin startapp TestModel
会生成 mysite/TestModel 文件夹,文件夹下有一系列文件。在 TestModel/models.py 中定义新的类:
# models.py
from django.db import models
class Test(models.Model):
name = models.CharField(max_length=20)
其中新类 Test 继承自内置的 models.Model。
然后在 mysite/mysite/settings.py 中的 APP 列表中加入 TestModel:
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'TestModel', # 添加此项
)
然后需要“migrate”,貌似类似于重载设置:
$ python3 manage.py migrate # 创建表结构
$ python3 manage.py makemigrations TestModel # 让 Django 知道我们在我们的模型有一些变更
$ python3 manage.py migrate TestModel # 创建表结构
然后可以使用数据库(可能用户多了会用得着),我只把数据库操作的函数抄录在这里,使用的时候需要做相应的 url 配置。
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from TestModel.models import Test
# 数据库操作
def testdb(request):
test1 = Test(name='runoob')
test1.save()
return HttpResponse("<p>数据添加成功!</p>")
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from TestModel.models import Test
# 数据库操作
def testdb(request):
# 初始化
response = ""
response1 = ""
# 通过objects这个模型管理器的all()获得所有数据行,相当于SQL中的SELECT * FROM
list = Test.objects.all()
# filter相当于SQL中的WHERE,可设置条件过滤结果
response2 = Test.objects.filter(id=1)
# 获取单个对象
response3 = Test.objects.get(id=1)
# 限制返回的数据 相当于 SQL 中的 OFFSET 0 LIMIT 2;
Test.objects.order_by('name')[0:2]
#数据排序
Test.objects.order_by("id")
# 上面的方法可以连锁使用
Test.objects.filter(name="runoob").order_by("id")
# 输出所有数据
for var in list:
response1 += var.name + " "
response = response1
return HttpResponse("<p>" + response + "</p>")
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from TestModel.models import Test
# 数据库操作
def testdb(request):
# 修改其中一个id=1的name字段,再save,相当于SQL中的UPDATE
test1 = Test.objects.get(id=1)
test1.name = 'Google'
test1.save()
# 另外一种方式
#Test.objects.filter(id=1).update(name='Google')
# 修改所有的列
# Test.objects.all().update(name='Google')
return HttpResponse("<p>修改成功</p>")
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from TestModel.models import Test
# 数据库操作
def testdb(request):
# 删除id=1的数据
test1 = Test.objects.get(id=1)
test1.delete()
# 另外一种方式
# Test.objects.filter(id=1).delete()
# 删除所有数据
# Test.objects.all().delete()
return HttpResponse("<p>删除成功</p>")
2. Admin 管理工具
要激活 admin,只需在 urls.py 中 的 urlpatterns 里加入(模块也抄在下面)
from django.contrib import admin
path('admin/', admin.site.urls),
就可以从 localhost:8000/admin 得到登录界面。
创建超级用户以后就可以进行登录:
python3 manage.py createsuperuser
注意,在第一次 migrate 之前,打上面的代码会报错。
3. 增加 APP: user
先在 settings.py 里增加设置一下语言、时区,模板路径
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
静态文件路径
# 配置静态文件路径与 url
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
'/var/www/static',
]
# 配置用户上传文件路径和 url
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join( BASE_DIR, "media")
然后在 urls.py 中设置
from django.conf import settings # 使用 settings.py 中的变量
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) # 配置静态文件url
# 配置用户上传文件url
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
后面两行是把静态文件、上传文件的 url 加入 urlpatterns。
然后生成 user app,和前面的 TestModel 一样,也要把 users 注册到 settings.py 中的 INSTALLED_APPS 中。
然后在 users/models.py 中定义新的类 UserProfile,使用内置的 User 类,进行一对一关联(OneToOneField),
from django.contrib.auth.models import User
# 完整如下
class UserProfile(models.Model):
USER_GENDER_TYPE = (
('male', '男'),
('female', '女'),
)
owner = models.OneToOneField(User, on_delete=models.CASCADE, verbose_name='用户')
nike_name = models.CharField('昵称', max_length=23, blank=True, default='')
birthday = models.DateField('生日', null=True, blank=True)
gender = models.CharField('性别', max_length=6, choices=USER_GENDER_TYPE, default='male')
address = models.CharField('地址', max_length=100, blank=True, default='')
image = models.ImageField(upload_to='images/%Y/%m', default='images/default.png', max_length=100, verbose_name = '用户头像')
class Meta:
verbose_name = '用户数据'
verbose_name_plural = verbose_name
def __str__(self):
return self.owner.username
用户上传的静态图片会自动储存,需要在 settings.py 中 TEMPLATES 的 OPTIOINS 中添加
'django.template.context_processors.media',
在 users/admin.py 中注册 UserProfile 模型
# 首先引入User
from django.contrib.auth.models import User
# 我们看到的这个用户选项就是官方默认通过UserAdmin这个类注册到后台的,那么我们也引入进来,后边继承这个类
from django.contrib.auth.admin import UserAdmin
# 再引入我们定义的模型
from .models import UserProfile
# 必须先通过unregister将User取消注册
admin.site.unregister(User)
# 定义关联对象的样式,StackedInline为纵向排列每一行,TabularInline为并排排列
class UserProfileInline(admin.StackedInline):
model = UserProfile # 关联的模型
# 关联字段在User之内编辑,关联进来
class UserProfileAdmin(UserAdmin):
inlines = [UserProfileInline]
# 重新注册User
admin.site.register(User, UserProfileAdmin)
然后重新 migrate, migrations, migrate。
我感觉这个做的有点啰嗦。
我不知道为什么不直接用内置的 User 类。
4. 静态登录页
搞个 user/templates/user/login.html
<form action=""method="post">
{% csrf_token %} # 模板标签,用来通过 csrf 伪造防护
<label for="id_username">用户名:</label>
<input type="text" name="username" id="id_username">
<label for="id_password">密码:</label>
<input type="password"name="password"id="id_password">
<input type="submit"value="提交">
</form>
然后想办法让 urls.py 调用 views.login_view,让用户输入用户名和密码,然后和数据库中信息进行比照:
# users/views.py
from django.shortcuts import render, HttpResponse
from django.contrib.auth import authenticate, login
def login_view(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
# 与数据库中的用户名和密码比对,django默认保存密码是以哈希形式存储,并不是明文密码,这里的password验证默认调用的是User类的check_password方法,以哈希值比较。
user = authenticate(request, username=username, password=password)
# 验证如果用户不为空
if user is not None:
# login方法登录
login(request, user)
# 返回登录成功信息
return HttpResponse('登陆成功')
else:
# 返回登录失败信息
return HttpResponse('登陆失败')
return render(request, 'users/login.html')
url 设置为: mysite/urls.py 中
path('users/', include('users.urls')), # 这里使用include()引入users.urls文件
然后在 users/urls.py 中
from django.urls import path
from . import views
app_name = 'users' # 定义一个命名空间,用来区分不同应用之间的链接地址
urlpatterns = [
path('login.html', views.login_view, name='login')
]
5. 总结+展望
一边联系这些操作,一边尝试,通过阅读命令行中的报错信息,我重复出了登录界面: localhost:8000/users/login.html
这个界面只能用来核实:用户名+密码 是否存在,没有真的“登录”什么东西。
下一步可以尝试增加注册、上传功能,就可以满足《计算物理》的需求了。我感觉可以尝试搞懂几个自己需要的功能,然后自己尝试尝试,不用这么亦步亦趋地跟着做了。