Python Django 学习 (二) 【Django 模型】

Stella981
• 阅读 601

注: 由于自己排版确实很难看,本文开始使用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 pymysql pip3.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_app\migrations\0001_initial.py - Create model TestModel

  • 下面我查看文件夹 test_project\test_app\migrations 增加了文件 0001_initial.py,第一次迁移文件名应该都是这个,之后会不同。查看 文件 0001_initial.py 内容如下:

    Generated by Django 2.0 on 2018-11-15 03:00

    from django.db import migrations, models class 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_app Running 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 admin

    from .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_length DateField#日期,可以指定auto_now 与 auto_now_add可以自动填充当前列为当前时间 DateTimeField# datetime DecimalField# 小数点 DurationField# 与python的timedelta对应 EmailField FileField FileField and FieldFile FilePathField FloatField ImageField IntegerField GenericIPAddressField NullBooleanField PositiveIntegerField PositiveSmallIntegerField SlugField SmallIntegerField TextField TimeField URLField UUIDField

    不是所有的 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.py

    from django.conf.urls import url from django.contrib import admin from django.urls import path,include urlpatterns = [ url(r'^admin/', admin.site.urls), path('', include('test_app.urls')),#包括test_app的url ]

    #创建 test_project/test_app/urls.py from django.conf.urls import url from test_app import views urlpatterns = [ url('test_app/test_model', views.test_model), ]

  • 需要定义一个查询的api

    test_project/test_app/views.py

    from django.shortcuts import render from django.http import HttpResponse from . import models import json as json from django.core import serializers def 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() #获取所有的数据 返回queryset models.TestModel.objects.all().values('test_name') #只取test_name列 返回queryset models.TestModel.objects.get("id=1") #只要id=1 返回object models.TestModel.objects.all().filter("id=2") #只要id=2 返回queryset models.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 url from test_app import views urlpatterns = [ 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 transaction with 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()

数据库结构的导入到代码

  1. 下载了项目代码,但是本地数据库中没有项目表结构

  2. 数据库在后台改动了,要同步到代码中

    python36 manage.py inspectdb

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

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这