Django基础知识 ->(个人学习记录笔记)
本文参考:https://www.bilibili.com/video/BV1i7411e7CY?p=1
1、初识
创建工程:django-admin startproject 工程名
创建应用:python manage.py startapp 应用名
激活应用:settings.py中的INSTALLED_APPS添加应用名
查看功能:python manage.py
生成迁移文件:python manage.py makemigrations
执行迁移:python manage.py migrate
启动服务器:python manage.py runserver 127.0.0.1:8000
2、登录首页实现步骤
2.1创建一个Djano项目
方式一:PyCharm创建Django项目

方式二:命令行创建
切换到创建项目的目录 cd C:\Users\admin\Desktop\DjangoProject
创建名为test01的项目命令:django-admin startproject test01
注:所有路径不要有中文
2.2 创建应用
进到Terminal终端,执行python manage.py startapp stu

2.3在settings.py中添加应用
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'stu' #添加应用 ]
2.4 确定访问路径
http://127.0.0.1:8000/student/
2.5配置项目根路由(test01/urls.py)
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('student/', include('stu.urls')) # ctrl+目标即可超链接,,include是添加子路由 ]
2.6配置应用子路由(stu/urls.py)
应用包下创建并配置url.py文件
from django.conf.urls import url from . import views # python3 必须加 from . urlpatterns=[ url('', views.login_view) ]
2.7创建处理函数(stu/views.py)
from django.shortcuts import render # Create your views here. def login_view(request): return render(request,'login.html')
2.8创建login.html(template/login.html)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form action="" method="get"> <p> <label>用户名:</label><input type="text" name="uname"/> </p> <p> <label>密 码:</label><input type="password" name="pwd"/> </p> <p> <input type="submit" value="登录"> </p> </form> </body> </html>
效果图:

3、GET&POST登录功能
3.1post请求的请求报文
POST /06_web_HTTP/success.html HTTP/1.1 Host: localhost:8080 Connection: keep-alive Content-Length: 30 请求体中数据的长度(请求参数) Cache-Control: max-age=0 不缓存 Origin: http://localhost:8080 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36 Content-Type: application/x-www-form-urlencoded Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Referer: http://localhost:8080/06_web_HTTP/login.html Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.8 3、空行 4、请求体(请求参数 多个参数之间使用&连接) username=admin&password=123213
3.2post响应报文
HTTP/1.1 200 OK
Date:Sun,01 Apr 2020 13:14:07 GMT(成功响应的时间)
Server: Apache-Coyote/1.1 (服务器内核版本)
Accept-Ranges: bytes (数据单位)
ETag: W/"157-1504593208325"
Content-Type: text/html;charset=utf-8 (响应文件的类型)
Content-Length: 15 (响应体内容大小)
3、空行
4、响应体(服务器给浏览器的响应体中的内容才是浏览器解析显示在页面中的内容)
3.3GET和POST请求区别
1、POST请求的请求参数在请求实体内容中,GET请求的请求参数存放在URL中
2、GET请求相对不安全,post相对安全 (其实都不安全)
3、GET请求的URL参数长度有限(不超过2K),post参数大小没有限制
4、GET请求一般做查询(有缓存),POST请求一般做添加/删除/修改(无缓存)
5、Django服务器GET/POST请求为什么接受参数方式一样?
因为他们都是QueryDict对象(django.http.request)
3.4解决POST请求错误403
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', #'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
或者在html文件加入这个
<body> <form action="/register/" method="post"> {% csrf_token %} <input type="submit" value="注册"/> </form> </body>
4、连接mysql实现注册/登录/查询功能
需求:
- 注册页面:http://127.0.0.1:8000/student/register/
- 登录页面:http://127.0.0.1:8000/student/login/
- 数据展示页面:http://127.0.0.1:8000/student/showall/
4.1 配置mysql连接信息(test01/settings.py)
ATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'mysql', # 数据库名称 'HOST': '127.0.0.1', # 服务器 'PORT': '3306', 'USER': 'root', 'PASSWORD': '123456' # 密码 } }
4.2 创建model模型(stu/model.py)
from django.db import models class Student(models.Model): # 创建模型类 sname = models.CharField(max_length=30, unique=True) # 设置唯一密码 字段类型 最大长度 唯一约束的意思 spwd = models.CharField(max_length=30) def __str__(self): return u'Student:%s'%self.sname # Student:lisi # def __unicode__(self): # python2.0版本这样写 # return u'Student:%s'%self.sname
4.3 配置项目pymysql(test01/__init__.py)
import pymysql pymysql.install_as_MySQLdb()
4.4 创建数据库表
#创建当前应用的迁移文件 python manage.py makemigrations stu #生成数据库表 python manage.py migrate # 生成项目下所有数据库表 python manage.py migrate stu # 只生成stu下对应数据表 #查看迁移文件生成的SQL语句 python manage.py sqlmigrate stu 0001
4.5 配置应用URL(stu/urls.py)
from django.urls import path from . import views urlpatterns = [ path('register/',views.register_view), #注册 path('login/',views.login_view), #登录 path('showall/',views.showall_view) #查询 ]
4.6 处理函数(stu/views.py)
from django.http import HttpResponse from django.shortcuts import render from . models import * # Create your views here. def register_view(request): #获取请求方式,如果为GET就渲染register页面 if request.method == 'GET': return render(request,'register.html') else: #如果为POST,获取请求参数(用户前端输入) uname = request.POST.get('uname','') pwd = request.POST.get('pwd','') #判断非空 if uname and pwd: #插入数据 student.objects.create(sname=uname,spwd=pwd) #页面响应 return HttpResponse('注册成功') return HttpResponse('注册失败') def login_view(request): # 获取请求方式,如果为GET就渲染login页面 if request.method == 'GET': return render(request,'login.html') else: #获取请求参数 uname = request.POST.get('uname','') pwd = request.POST.get('pwd','') #判断非空 if uname and pwd: #查询数据,如果查询出记录数大于1,代表登录成功 c = student.objects.filter(sname=uname, spwd=pwd).count() if c >=1: return HttpResponse("登录成功") return HttpResponse("登录失败") def showall_view(request): #查询所有数据 students = student.objects.all() #通过字典传值返回给前端 return render(request,'showall.html',{'students':students})
4.7html文件源码
1)register.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册页面</title> </head> <body> <form action="/student/register/" method="post"> {% csrf_token %} <p> <label>用户名:</label><input type="text" name="uname"/> </p> <p> <label>密 码:</label><input type="password" name="pwd"/> </p> <p> <input type="submit" value="注册"> </p> </form> </body> </html>
2)login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <form action="/student/login/" method="post"> {% csrf_token %} <p> <label>用户名:</label><input type="text" name="uname"/> </p> <p> <label>密 码:</label><input type="password" name="pwd"/> </p> <p> <input type="submit" value="登录"> </p> </form> </body> </html>
3)showall.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <table border="1" cellpadding="0" width="500px"> <tr> <td>编号</td> <td>姓名</td> <td>密码</td> </tr> {% for st in students %} <tr> <th>{{ forloop.counter }}</th> <th>{{ st.sname }}</th> <th>{{ st.spwd }}</th> </tr> {% endfor %} </table> </body> </html>
4.8admin后台管理类操作数据库
#创建管理员用户: python manage.py createsuperuser #汉化: 修改project\settings.py中作如下设定: LANGUAGE_CODE = 'zh-Hans' TIME_ZONE = 'Asia/Shanghai' #管理数据表: 修改 myAPP\admin.py 如下: from django.contrib import admin from .models import * #注册站点 admin.site.register(student) #登陆: http://127.0.0.1:8000/admin/
5、单表查询
定义一个函数_显示ORM底层生成SQL
def showsql(): from django.db import connection print(connection.queries[-1]['sql'])
逆向生成模型
python manage.py inspectdb > student/models.py # 前提是创建了app(student)并且在setting.py文件中注册过
5.1查询单个对象
ASC升序 --------------------- DESC降序
所有的继承自model.Model的类 都会有一个叫objects(管理者) ----查询一个 (有且只能有一个)(少于一个或者多于一个都报错 ) 返回值Movie对象 Movie.object.get(mid=147) 注意当不存在时会报错!!! SELECT `movie`.`mid`, `movie`.`mname`, `movie`.`mdesc`, `movie`.`mimg`, `movie`.`mlink` FROM `movie` LIMIT 21 ----获得第一个 Movie.objects.first() Movie.objects.filter() ----获得最后一个 Movie.objects.last() ----获得记录的总数 Movie.objects.count()
5.2 查询多个对象
----获得所有的记录 Movie.objects.all() #在django的1.11.6中默认中只是获得21个 #懒加载 Movie.objects.filter() ----切片 (不支持负数索引) Movie.objects.all()[20:40] # 底层直接使用了limit字句,可以自动的分页 # django的orm性能非常强大,能节省很多工作 ----过滤 # 集合(游标,结果集,查询集) Movie.objects.filter(mname=‘麻辣学院’) # 底层直接使用了limit字句,可以自动的分页 # django的orm性能非常强大,能节省很多工作 ----模糊查询 like %(多个字符) _(一个字符) SELECT * from movie WHERE mname LIKE '%爱情' ----查询爱情结尾的 SELECT * from movie WHERE mname LIKE '%爱情' Movie.objects.filter(mname__endswith='爱情') ----忽略大小写 Movie.objects.filter(mname__istartswith='h') ----查询某个字段是否为null Movie.objects.filter(mname__isnull=True) ----多条件查询 Movie.objects.filter(mname__contains='爱情',mid=147) and Movie.objects.filter(mname__contains='爱情').filter(mid=147) ----部分查询 Movie.objects.values('mname','mid').filter(mname__contains='爱情') ----排除一部分 Movie.objects.filter(mname__contains='爱情').exclude(mname__startswith='爱情') ----排序 Movie.objects.order_by('mid') 升序 Movie.object.order_by('-mid') 降序
5.3 日期查询
----查询大于某个时间的记录 Post.objects.filter(created__gt='2017-10-20') ----查询最近一个月的帖子(查询最近不活跃的用户) def get_recent_month_post(): import datetime current = date.date.today()-datetime.timedelta(days=30) current = str(current) return Post.objects.filter(created__gt=current) ----查询十月二十号--十一月二十号的所有的记录 错误的 Post.objects.filter(created__in=('2017-10-20','2017-11-20')) 指的是这两个时间中的一个 正确的(SQL语句) Post.objects.filter(created__range=('2017-10-20','2017-11-20')) Post.objects.filter(created__range=(147,149)) 或者 BETWEEN 147 AND 149
6、单表增_删 改
6.1增加
#方法1 post = Post(title='博客11',created='2017-2-20') post.save() #方法2 Post.objects.create(title='博客12',created='2018-11-11') 返回值是添加的对象
6.2 删除
#方法1 m = Movie.objects.filters(mname__startswith='h') m.delete() # BINARY不是函数,是类型转换运算符,比较时,区分大小写 DELETE FROM 'movie' WHERE 'movie', 'mname' LIKE BINARY ‘h%’ #方法2(删除所有包含博客名字的帖子) Post.objects.filter(tiltle__contains='博客').delete()
6.3 修改
#方法1 (更新的是所有的字段) post = Post.objects.first() post.title='更新了' post.save() UPDATE 'post_post' SET 'title' = '更新了','created' = '2017-11-27' WHERE 'post_post' ,'id' = 26 #方法2(只更新修改的字段),推荐使用 Post.objects.filter(id=26).update(title='又更新了') UPDATE 'post_post' SET 'title' = '又更新了' WHERE 'post_post'.'id' = 26
7、创建单表
7.1 常用字段类型
—> django所有的数据模型都继承自model.Model —> CharField max_length (输入框) —> TextField 没有长度限制的字符串(文本域) —> DateField 日期 —> DateTimeField 日期+时间 —> BooleanField 真假 —> NullBooleanField ,Null 真假 —> Integer 整数 —> PositiveIntegerField 正整数 —> DecimalField max_digits(几位数) decimal_place (小数点后保留几位) —> ImageField 图片 依赖于Pillow(处理图片)upload_to='upload'指定文件上传到目录 —> FileField(ImageField继承FileField) —> AutoField —> OneToOneField 1:1 一对一 学生和学生证 CASCADE 级联删除 —> ForeignKey 1:n 一对多 班级和学生 —> ManyToManyField n:n 多对多 学生和课程 —> EmailField 邮箱 #字符串@域名.comn —> UUIDField 重复的概率非常低基本可以忽略,全世界都不一样的标示,uuid的产生和服务器的环境有关(CPU,网关)唯一的标示,用户模块,订单号 #唯一标识符 —> 不同的字段在后台对应不同的html的组件 —> ImageField 依赖于Pillow组件(python库)
7.2常用属性
—> unique 标示这个字段唯一 —> default 默认的意思,(如果不写的话就使用默认的值) —> null=True 允许字段为null,(允许数据库为null)数据库层面的 —> blank=True 表单阶段的,admin后台的 可以为空 —> auto_now 针对时间段,自动调整单签,(当修改目的时候,这个时间会更新),每次修改都会更新(修改,保存的时候才会生效) —> auto_now_add 针对时间的,只添加一次,(创建的时间)
7.3 重点理解属性
—> 表单层面的东西(js判断字段是否是“”),不需要重写迁移数据库 —> unique = True 可以任何字段 —> default 数据库+表单层面(同时生效) —> auto_now_add 创建的时候回自动的添加时间(数据库)(后台表单层面找不到这个字段)
7.4 一对一关系
7.41使用OneToOneField()
from django.db import models
#学生对学生证,一对一关系 class Student(models.Model): #学号 sno = models.AutoField(primary_key=True) #姓名 sname = models.CharField(max_length=30,unique=True) class Meta: db_table='t_student' def __str__(self): return u'Student:%s'%self.sname class Scard(models.Model): student = models.OneToOneField(Student,primary_key=True,on_delete=models.CASCADE) major = models.CharField(max_length=30) class Meta: db_table='t_scard' def __str__(self): return u'Scard:%s'%self.major
7.42查询过程
from movie.models import * student = Student.objects.create(sname='zhangsan') Scard.objects.create(student=student,major='计算机') <Scard: Scard:计算机> Student.objects.first().scard #正向查询,返回的是Object对象 <Scard: Scard:计算机> Scard.objects.first().student #逆向查询,返回的是Object对象 <Student: Student:zhangsan>
7.5 一对多关系
7.51使用ForeignKey()
from django.db import models #课程对学生,一对多的关系 class Clazz(models.Model): cno = models.AutoField(primary_key=True) cname = models.CharField(max_length=30) def __str__(self): return u'Clazz:%s' % self.cname # 学生表 class Student(models.Model): sno = models.AutoField(primary_key=True) sname = models.CharField(max_length=30) cno = models.ForeignKey(Clazz, on_delete=models.CASCADE, related_name='sts') def __str__(self): return u'Student:%s' % self.sname
7.52查询过程
from movie.models import *
#课程表Clazz插入数据 cls = Clazz.objects.create(cname='B201Python') cls1 = Clazz.objects.create(cname='B202Java')
#学生表插入数据(多,引用课程表) Student.objects.create(sname='zhangsan',cno=cls) <Student: Student:zhangsan> Student.objects.create(sname='lisi',cno=cls) <Student: Student:lisi> Student.objects.create(sname='wangwu',cno=cls1) <Student: Student:wangwu>
#正向查询(返回的是QuerSet) Clazz.objects.first().sts.all() <QuerySet [<Student: Student:zhangsan>, <Student: Student:lisi>]> Clazz.objects.last().sts.all() <QuerySet [<Student: Student:wangwu>]> #逆向查询(返回的是object对象)
Student.objects.first().cno <Clazz: Clazz:B201Python> Student.objects.last().cno <Clazz: Clazz:B202Java>
7.53函数封装,打包输入,->>>多表的插入
def insertData(clsname, *snames): try: cls = Clazz.objects.get(cname=clsname) except Clazz.DoesNotExist: cls = Clazz.objects.create(cname=clsname) for sn in snames: try: stu = Student.objects.get(sname=sn) except Student.DoesNotExist: Student.objects.create(sname=sn,cno=cls)
7.54可变参数
def demo(*args, **kwargs): print args,kwargs demo(1,2,c='a',b='d') ''' (1,2) {'c':'a','b':'d'} # * args : 将手机所有位置相关的参数,并放到一个元组中,最后将这个元组赋值给args # **kwargs : 针对关键字参数(a=3这一类型)这些关键字参数会放到一个相应的字典中, 然后同样的赋值给kwargs '''
7.6 多对多关系
7.61使用ManyToManyField()
# 课程表 和 教师表 n:n class Course(models.Model): course_id = models.AutoField(primary_key=True) course_name = models.CharField(max_length=30,unique=True) class Meta: db_table='t_course' def __str__(self): return u'Course:%s' % self.course_name class Teacher(models.Model): tid= models.AutoField(primary_key=True) tname = models.CharField(max_length=30,unique=True) course = models.ManyToManyField(Course) class Meta: db_table='t_teacher' def __str__(self): return u'Teacher:%s--%s' % (self.tname,self.course)
7.62查询过程
from stu.models import * cour1 = Course.objects.create(course_name='Python') cour2 = Course.objects.create(course_name='Java') cour3 = Course.objects.create(course_name='HTML5') t = Teacher.objects.create(tname='zhangsan') t2 = Teacher.objects.create(tname='lisi') t.cour.add(cour1,cour2,cour3) Course.objects.first().teacher_set.all() # 正向查询# related_name='sts'修改名字_set # <QuerySet [<Teacher: Teacher:zhangsan>]> Teacher.objects.first().cour.all() # 逆向查询 # <QuerySet [<Course: Course:Python>, <Course: Course:Java>, <Course: Course:HTML5>]>
7.63函数封装,打包输入,->>>多表的插入
def insertData(tname, *coursenames): try: t = Teacher.objects.get(tname=tname) except Teacher.DoesNotExist: t = Teacher.objects.create(tname=tname) courseList = [] for cn in coursenames: try: cou = Course.objects.get(course_name=cn) except Course.DoesNotExist: cou = Course.objects.create(course_name=cn) courseList.append(cou) t.cour.add(*courseList)
7.64可变参数
def demo(*args, **kwargs): print(args) print(kwargs) demo() () {} demo(1,2,3) (1, 2, 3) {} demo(1,2,3,c='a') (1, 2, 3) {'c': 'a'}
7.65 参数解包
def demo(a,b,c): print a,b,c kwargs = {'a':1,'b':'2','c':3} demo(**kwargs) # 结果: 1 2 3 args = (1,2,3) demo(*args) # 结果:1 2 3 def demo(a,b,c) print(a,b,c) demo(1,2,3) # 1 2 3 str = {'a':'a1','b':'b1','c':'c1'} demo(**str) # a1 b1 c1 str2 = (1,2,3,) demo(*str2) # 1 2 3 ''' 可变参数和采纳数解包的区别 可变参数是在 形参 中,利用*,**来实现的 参数解包是在 实参 中,李颖*,**来实现的
作者:杰宏唯一
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
浙公网安备 33010602011771号