Django创建用户中心应用users

Django创建用户中心应用users

本章节配套视频教程

在settings.py文件中配置项目

1、语言配置: LANGUAGE_CODE = 'zh-hans’
2、时区配置: TIME_ZONE = 'Asia\Shanghai’
3、模板路径配置:‘DIRS’: [os.path.join(BASE_DIR, ‘templates’)], 并创建templates文件夹
4、配置静态文件: docs.djangoproject.com/ (官方文档地址)
5、在与项目同级创建static与media文件夹

在urls.py中设置静态文件url及上传文件url

在mysite/urls.py中引入:

from django.conf import settings 
from django.conf.urls.static import static

然后在urls.py中设置:

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)
在做完基本的配置之后,我们开始来创建用户中心应用`users`,在上一章中我们已经通过创建`blog`博客应用学习了如何使用命令来创建应用,好,下来我们直接使用`manage.py`为我们提供的`startapp`命令来创建用户中心应用`users`。

1、首先,激活虚拟环境

env\Scripts\activate

2、激活成功之后 cd mysite 文件夹

3、命令行创建 users 应用

py manage.py startapp users

在创建好`users`应用之后,我们现在就开始在`users`文件夹下的`models.py`中创建`UserProfile`模型数据。

在创建模型数据之前,我们先来了解一下django中的模型指的是什么?

Django的模型其实是一个个类,不是对象,模型数据在应用users文件夹下的models.py中定义,直接与数据库交互。

在创建模型数据之前,我们首先必须把应用注册到settings.py文件中

在项目设置文件settings.py中的 INSTALLED_APPS 设置中添加包含你 models.py文件的模块(users)的名字。

注册方法有两种方式:

INSTALLED_APPS = [
    # 可以这样引用
    'users',
    # 也可以这样引用
    'users.apps.UsersConfig',
]

注册成功后,开始在users文件夹下的models.py中添加用户数据,我们知道django中的模型其实就是一个个类,这些类继承 django.db.models.Model ,模型类的每个属性都相当于一个数据库的字段。这些字段用来创建数据库表,并且以此来定义数据的类型/存储/关联等数据交互的方式。

# 首先引入django内置的一个用户User模型,然后通过一对一关联关系为默认的User扩展用户数据
from django.contrib.auth.models import User

我们点击User进入django内部去看User模型的源码,可以看到他是继承了`AbstractUser`类的所有数据,我们再去看一下`AbstractUser`都有哪些数据?可以看到它里边创建了用户的几个基本信息,用户名称`username`、`first_name`、`last_name`、`email`、`is_staff`、`is_active`、`date_joined`,这几个字段远远不能全面记录一个用户的信息,比如我们还想知道用户的性别、手机号、个人介绍、让用户还拥有自己的头像,那么我们就得去扩展用户的模型。

扩展用户模型的方法有两种,一种是模仿官方的方法,直接继承`AbstractUser`类来扩展用户数据,另外一种是通过一对一关系关联User类,来扩展用户数据,我这里选择采用第二种一对一关联的方式来扩展,这样的好处是不需要再setiings.py中另外配置,也有利于我们理解和学习django的关联关系用法。

class UserProfile(models.Model):
    owner = models.OneToOneField(User, on_delete=models.CASCADE, verbose_name = '用户')

django 提供了定义三种最常见的数据库关联关系的方法: 多对一 多对多 一对一

我们为默认的User扩展数据便是使用一对一关系即 OneToOneField ,字段来相互关联扩展,一个用户只能对应唯一的一组数据,因此上这里就必须使用一对一关系关联。

多对一关联为 ForeignKey ,多对多关联为 ManyToManyField ,这两种的用法与一对一关系用法类似,在以后具体用到的时候我们在单独拿出来讲。

下来,我们继续扩充我们的用户信息

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=50, 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 = '用户头像')

我们为用户扩展的`昵称`采用的是`CharField`字段,这是一个短文本字段,我称之为标题字段,用来设置用户的昵称。

我们为用户扩展的`生日`采用的是`DateField`字段,这是一个时间字段,与本字段类似的字段还有`DateTimeField`。

我们为用户扩展的`头像`采用的是`ImageField`字段, 值得注意的是这个字段必须定义`upload_to`选项, 这个选项用来指定用于上传文件的`MEDIA_ROOT`的子目录 。例如我们在最开始配置settings.py的时候配置了`MEDIA_ROOT = os.path.join(BASE_DIR, 'media')`,那么我们这里设置了`upload_to='images/%Y/%m'`, `upload_to`的`'%Y /%m /%d'`部分是`strftime()`格式; '%Y'是四位数年份,`%m`是两位数月份,`%d`是两位数日期。 如果您在2020年1月15日上传文件,它将保存在目录`/media/images/2020/01`中。

# 在settings中TEMPLATES的OPTIONS添加
'django.template.context_processors.media',

在使用`ImageField`字段还必须安装`pillow`模块,django默认使用pillow模块来处理图片。将我们提前准备好的用户头像图复制到media/images/目录中。

刚才这个提到了一个**字段选项**的概念,我们现在来看一下什么是字段选项?

每一种字段都需要指定一些特定的参数,在官方文档中我们可以参考模型字段章节来具体了解。以我们这个例子来讲, CharField(以及它的子类)需要接收一个 max_length 参数,用以指定数据库存储 `VARCHAR` 数据时用的字节数。

一些可选的参数是通用的,可以用于任何字段类型:

null

  • 如果设置为 True ,当该字段为空时,Django 会将数据库中该字段设置为 NULL 。默认为 False

blank

choices

  • 一系列二元组,用作此字段的选项。如果提供了二元组,默认表单小部件是一个选择框,而不是标准文本字段,并将限制给出的选项。
  • 每个二元组的第一个值会储存在数据库中,而第二个值将只会用于在表单中显示。
  • 对于一个模型实例,要获取该字段二元组中相对应的第二个值,使用 get_FOO_display() 方法。

生成默认的数据库sqlite3

Python 内置了 SQLite,所以你无需安装额外东西来使用它。通过一个命令即可快速生成sqlite数据库文件。

py manage.py migrate

开发阶段我们来使用默认的数据库来快速开发,当真正部署的时候我们更换为mysql数据库。

然后通过运行 makemigrations 命令

py manage.py makemigrations users

来生成数据迁移文件,生成迁移文件在migrations文件夹下

再通过 migrate 命令

py manage.py migrate

这个命令将选中所有还没有执行过的迁移,将未迁移的数据同步到数据库中,迁移是非常强大的功能,它能让你在开发过程中持续的改变数据库结构而不需要重新删除和创建表 - 它专注于使数据库平滑升级而不会丢失数据。我们会在后面的教程中更加深入的学习这部分内容,现在,你只需要记住,改变模型需要这三步:

  1. 编辑 models.py 文件,改变模型。
  2. 运行 python manage.py makemigrations 为模型的改变生成迁移文件。
  3. 运行 python manage.py migrate 来应用数据库迁移。

下来,我们创建一个超级管理员用户:

py manage.py createsuperuser

超级管理员创建成功后,通过runserver命令快速启动网站

py manage.py runserver

进入管理站点页面: 127.0.0.0:8000/admin

进入页面之后,发现错误提示:`A server error occurred. Please contact the administrator.`再去编辑器终端去看看错误提示为:`pytz.exceptions.UnknownTimeZoneError: 'Asia\\Shanghai'`,我们发现最后出现了跟时区配置相关的错误提示,我们去到settings.py文件中去查看修改,发现我们把`Asia\Shanghai`这两个之间的斜杠写反了,windows系统应该写成 `/`。

打开管理站点页面首页,我们发现有用户这一项,那么我们将关联的信息也关联到这一项里边,向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)

注册成功之后我们去看看,添加一个新用户,进行测试,我们看到用户里边成功多出了我们添加的条目,但这些信息的标题显示的是模型的名称的大写字母,我们通过设置模型数据的元数据来自定义这个标题。

users/models.py 中的 UserProfile 模型下定义:

# 完整如下
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 = '用户头像')