Python Django 学习 (二) 【Django 模型】
2019-11-22

注: 由于自己排版确实很难看,本文开始使用markdown编辑,希望有所改善

官方定义

A model is the single, definitive source of information about your data. It contains the essential fields and behaviors of the data you’re storing. Generally, each model maps to a single database table.

一个模型是关于你的数据的单个的、确定的信息源。它包含了你储存数据的必要的列和行为,基本上,一个模型映射一个单个的数据库表。

更改Django数据库配置

由于原生的django使用的是sqlite3, 本人熟悉mysql 所以最后使用mysql。

注:本文接着上一篇文章来的,如果没有相应的项目请按照上一篇内容操作一下。[Python Django 学习 (一) 【Django 框架初探】]

在 test_project项目中找到文件 test_project/test_project/settings.py 找到如下代码

DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": os.path.join(BASE_DIR, "db.sqlite3"), }}将上述代码注释掉,添加如下代码:

DATABASES = { "default": { "ENGINE": "django.db.backends.mysql", "NAME": "mysql",#数据库名字 "USER":"root", "PASSWORD":"*****", "HOST":"localhost", "PORT":"3306", }} 确保一件事情,你的python3 的版本安装了 pymysql 、mysqlclient 使用pip 安装

pip3.6 install pymysqlpip3.6 install mysqlclient # 我在安装mysqlclient时出现了问题,到 https://www.lfd.uci.edu找的包自己安装的

创建 test_app

在使用model时,官方文档说,“当你定了模型之后,你需要告诉Django你将使用这些模型。通过编辑setting.py中 INSTALL_APPS,将包含你的模型的app的名字放到里面”

打开 CMD 键入 如下指令:

python36 manage.py startapp test_app

将会在 test_project项目下 新建一个 test_app文件目录

作用说明

文件名作用
migrations将模型的更改,形成可执行的PY文件,使用指令迁移到数据库中
_init_.py标识当前文件路径是一个python包
admin.py可以在其中添加当前model,然后使用界面对数据库进行操作
apps.py当前app 配置
models.py存放当前app存在的模型,与数据库一一对应
tests.py存放当前app的测试
views.py存在当前app的页面模板
将 test_app 添加到 test_project/test_project/settings.py文件中,如下:

INSTALLED_APPS = [ "django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", # new add "test_app",]

添加 testmodel 到 test_app中、迁移到数据库

打开 文件 test_project/test_app/modes.py 更改代码如下:

from django.db import models# Create your models here.class TestModel(models.Model): # django 有一个机制 在没有设置自增主键的时候会自动创建一个主键, test_name = models.CharField(max_length=100, default="no_name") # 字符类型的字段 设置最大长度与默认值 test_content = models.CharField(max_length=50,default="male") # 字符类型的字段 设置最大长度与默认值 # 如果不指定表名,django默认表明是 "appname_classname" class Meta: """ 使用如下语句定义表名 db_table = "test_model" """ def __unicode__(self): return "%d: %s" % (self.pk, self.test_name)打开 CMD 键入 如下命令:

python36 manage.py makemigrations #不指定app将迁移全部数据python36 manage.py makemigrations test_app # 可以选择单个app进行数据迁移#以上两个都可以,在app多的时候,建议使用下面的单个迁移#该命令只是生成迁移文件,并没有真正的操作数据库########################################################################################返回如下结果Migrations for "test_app": test_appmigrations1_initial.py - Create model TestModel下面我查看文件夹 test_projectest_appmigrations 增加了文件 0001_initial.py,第一次迁移文件名应该都是这个,之后会不同。查看 文件 0001_initial.py 内容如下:

# Generated by Django 2.0 on 2018-11-15 03:00from django.db import migrations, modelsclass Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name="TestModel", fields=[ ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("test_name", models.CharField(default="no_name", max_length=100)), ("test_content", models.CharField(default="male", max_length=50)), ], ), ]# 我们可以看到,钱 Migration类中,定义了新的 模型 TestModel,并且有三个字段 id、test_name、test_content我每次迁移的时候都会查看,生成的迁移文件,确保都是我想要的数据库改动。打开CMD 键入指令:

python36 manage.py migrate#该指令将,真正将建表操作到mysql数据库中########################################################################################会看到如下提示Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions, test_appRunning migrations: Applying test_app.0001_initial... OK#可以发现执行了 刚才的 0001_initial.py 文件中的内容我们打开mysql 数据库查看,是否存在表

mysql> show create table test_app_testmodel -> ;+--------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| Table | Create Table |+--------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+| test_app_testmodel | CREATE TABLE `test_app_testmodel` ( `id` int(11) NOT NULL AUTO_INCREMENT, `test_name` varchar(100) NOT NULL, `test_content` varchar(50) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |+--------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+1 row in set (0.01 sec)至此,模型与数据库已经实现了同步。

使用 django admin管理数据库数据

之前说过 test_app下的文件 admin.py 添加如下内容:

from django.contrib import adminfrom .models import TestModel# Register your models here.@admin.register(TestModel)class TestModelAdmin(admin.ModelAdmin): list_display = ("pk", "test_name") #在后台列表下显示的字段

进入 django admin页面 输入超级用户用户名、密码

通过 admin 管理 test model,点击上面的 Test models 可以通过页面进行增、删、改、查的操作

介绍一下Django提供的字段类型

基本类型

AutoField #自增列,如果不存在的话会添加一个自增的ID列BigAutoField # 64位的,比上面自增列大BigIntegerField #64 位的整型BinaryField #原生的二进制列BooleanField#布尔CharField#字符串,注意该字段必须指定 max_lengthDateField#日期,可以指定auto_now 与 auto_now_add可以自动填充当前列为当前时间DateTimeField# datetimeDecimalField# 小数点DurationField# 与python的timedelta对应EmailFieldFileFieldFileField and FieldFileFilePathFieldFloatFieldImageFieldIntegerFieldGenericIPAddressFieldNullBooleanFieldPositiveIntegerFieldPositiveSmallIntegerFieldSlugFieldSmallIntegerFieldTextFieldTimeFieldURLFieldUUIDField# 不是所有的 field 都用过,有兴趣请自行尝试ArrayField

最近使用 Postgresql 开发,发现它支持,array类型。在Django,中同样支持,代码如下:

class TestModel(models.Model): test_array = ArrayField(models.CharField(max_length=96, null=False, default=""), default="{}", size="99") # 意思为增加一个 test_array数组字段,并且数组元素都是char ,可以更换成其他类型 #此处default {}是因为 postgresql在检测的时候强制插入数据为 "{a,b,c,d}",default空的话会报错 class Meta: db_table = "test_model" def __str__(self): return self.node

代码中的增删改查

分别在以下文件中添加如下代码,路由具体说明将会重新写一篇文章

# test_project/test_project/urls.pyfrom django.conf.urls import urlfrom django.contrib import adminfrom django.urls import path,includeurlpatterns = [ url(r"^admin/", admin.site.urls), path("", include("test_app.urls")),#包括test_app的url]

#创建 test_project/test_app/urls.pyfrom django.conf.urls import urlfrom test_app import viewsurlpatterns = [ url("test_app/test_model", views.test_model),]

# 需要定义一个查询的api# test_project/test_app/views.pyfrom django.shortcuts import renderfrom django.http import HttpResponsefrom . import modelsimport json as jsonfrom django.core import serializersdef test_model(request): data = models.TestModel.objects.all() data_json = json.loads(serializers.serialize("json", data))#将queryset变成json输出 print(str(data_json)) return HttpResponse(data_json); #启动Django服务后,在浏览器中输入 localhost:8000/test_app/test_model#打印结果将在cmd显示

# 更换不同的查询方式,打印输出结果# 数据库中插入了两条数据models.TestModel.objects.all() #获取所有的数据 返回querysetmodels.TestModel.objects.all().values("test_name") #只取test_name列 返回querysetmodels.TestModel.objects.get("id=1") #只要id=1 返回objectmodels.TestModel.objects.all().filter("id=2") #只要id=2 返回querysetmodels.TestModel.objects.all().exclude("id=2") #排除id=2 返回queryset#打印结果*******[{"model": "test_app.testmodel", "pk": 1, "fields": {"test_name": "name1", "test_content": "content1"}}, {"model": "test_app.testmodel", "pk": 2, "fields": {"test_name": "test2", "test_content": "content2"}}]*******<QuerySet [{"test_name": "name1"}, {"test_name": "test2"}]>*******TestModel object (1)*******[{"model": "test_app.testmodel", "pk": 2, "fields": {"test_name": "test2", "test_content": "content2"}}]*******<QuerySet [<TestModel: TestModel object (1)>]>*******#更细节的查询,官网查看吧https://docs.djangoproject.com/en/2.0/topics/db/queries/

#更改 test_project/test_app/urls.py,添加对于增加数据的url配置from django.conf.urls import urlfrom test_app import viewsurlpatterns = [ url("test_app/test_model", views.test_model), # new add url("test_app/test_addto_model", views.add_test_model),]

#更改 test_project/test_app/views.py 新增如下函数代码def add_test_model(request): models.TestModel.objects.create( test_name="name_add_by_code",test_content="content_add") new_data = models.TestModel.objects.all() new_data_json = json.loads(serializers.serialize("json", new_data)) return HttpResponse(new_data_json);#启动 django 服务后,访问链接 localhost:8000/test_app/test_addto_model

页面输入结果:{"model": "test_app.testmodel", "pk": 1, "fields": {"test_name": "name1", "test_content": "content1"}}{"model": "test_app.testmodel", "pk": 2, "fields": {"test_name": "test2", "test_content": "content2"}}{"model": "test_app.testmodel", "pk": 3, "fields": {"test_name": "name_add_by_code", "test_content": "content_add"}}数据库查询结果mysql> select * from test_app_testmodel;+----+------------------+--------------+| id | test_name | test_content |+----+------------------+--------------+| 1 | name1 | content1 || 2 | test2 | content2 || 3 | name_add_by_code | content_add |+----+------------------+--------------+3 rows in set (0.00 sec)增加成功

# 由于考虑到数据完整行,简单介绍一下 Django 的 【事物】from django.db import transactionwith transaction.atomic(): #数据库操作#上面是最简单的方法,过程中报错将不会操作数据库#详情参加官网:https://docs.djangoproject.com/en/2.0/topics/db/transactions/

#不做演示了,直接上代码models.UserInfo.objects.filter(test_name="nam1").update(test_content="content1_update")

#删除的时候一定要filter一下呦models.UserInfo.objects.filter(test_name="test2").delete()

数据库结构的导入到代码

    下载了项目代码,但是本地数据库中没有项目表结构数据库在后台改动了,要同步到代码中

python36 manage.py inspectdb

注:在使用makemigrations 与 migrate时,每一次的 makemigrations 是基于上一个makemigrations进行比较的,如果某一次的makemigrations后,migrate失败,切记到 app下 migrations文件夹下删除,最新的makemigrations文件,然后修改model代码,重新makemigrations,否则将会报错一直迁移不到数据库中。被这个坑了好久。

, 1, 0, 9);