Django 从0开始创建一个项目
创建Django工程及配置
创建工程:django-admin starproject 项目名
创建APP:Python3 manage.py startapp app名称
- 可以创建多个app,每个app代表不同的业务,开发的时候互不影响
- URL通过路由分发实现跳转
注册APP:在后面加上app的名称
1 2 3 4 5 6 7 8 9 10 11
| INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', 'app02', 'app03', ]
|
配置模板路径:'DIRS': [os.path.join(BASE_DIR, 'templates')],
配置静态文件路径:STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
注释配置文件的一行: 'django.middleware.csrf.CsrfViewMiddleware',
Django的目录结构:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| |--mysite01 |---|app01 |----------|migrations | |admin.py | |apps.py | |models.py | |tests.py | |views.py |mysite01 |--------|__init__.py | |settings.py | |urls.py | |wsgi.py | |templates | |manage.py
|
- migrations 存放有关数据库的文件,保存数据库的修改信息
- admin Django自己的后台管理
- models 通过ORM用类创建数据库和表
- tests 单元测试
- views 视图函数,业务处理,可以继续进行分类,此时就是views文件夹
- apps app的配置文件
- /mysite01/mysite01/__init__.py 配置数据库,默认是sqllite,这里配置成mysql,通过pymysql连接数据库
import pymysql
pymysql.install_as_MySQLdb()
-urls 路由系统
- wsgi web服务
路由系统:
URL-函数 的对应关系
/login/ 一一对应 静态路由
/add-user/(\d+) 支持正则 动态路由
/add-user/(\d+).html 伪静态
具体实现
把URL变美观 ,视图函数要有参数接收def edit(request,arg):
1 2 3 4 5 6 7 8 9 10 11 12 13
| from django.shortcuts import render, HttpResponse, redirect def index(request): user_list = [ 'aaa', 'bbb', 'ccc', ] return render(request, 'index.html', {'user_list': user_list}) def edit(request, a1): print(a1) return HttpResponse("ok")
|
1 2 3 4 5
| <ul> {% for i in user_list %} <li>{{ i }}| <a href="/edit/{{ i }}/">编辑</a></li> {% endfor %} </ul>
|
总结:
- 在函数中通过参数a1接收url
- 点击的标签上添加路径结尾要用
/
url(r'^edit/(\w+)/', views.edit),通常这里是以/结尾的
正则匹配
1 2 3 4 5
| url(r'^edit/(\w+)/(\w+)/', views.edit), def edit(request, a1, a2): print(a1, a2) return HttpResponse("ok")
|
- 按照名称(关键字)(?P\w+)
- 注意是在正则表达式的括号里面传参数
- 可以没有顺序,这个过程相当于找到相应的参数名进行赋值
1 2 3 4 5 6 7 8 9 10 11 12
| url(r'^edit/(?P<a1>\w+)/(?P<a2>\w+)/', views.edit), def edit(request, a1, a2): return HttpResponse("ok") ``` **注意:**这两种是不能混合使用的,必须是统一的形式,这样才能用` *args, **kwargs`. 要主要下面的情况是,*args用来接收按位置传值,**kwargs用来接收按关键字传值的 ```python def edit(request, *args, **kwargs): return HttpResponse("ok")
|
路由分发(涉及多个app的时候)
在处理不同业务的时候,多个app
引入include
1 2 3 4 5 6 7 8 9
| from django.conf.urls import url, include from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^app01/', include('app01.urls')), url(r'^app02/', include('app02.urls')), ]
|
1 2 3 4 5 6 7
| from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^index/', views.index), ]
|
1 2 3 4 5 6 7
| from django.conf.urls import url from django.contrib import admin from app02 import views urlpatterns = [ url(r'^index/', views.index), ]
|
url 关系命名
通过刚给URL设置别名,可以通过别名反向获取URL
url(r'^index,views.index,name =n1)
在index函数中就可以通过’n1’获取路径
1 2 3
| from django.urls import reverse v = reverse('n1') print(v)
|
还可以自己定义,返回的路径名
根据名字反生成URL
name reverse
URL的后缀可以自己任意定义
1 2 3 4 5 6 7 8 9
| url(r'^index/(\w+)/', views.index, name='n1'), def index(request, a1): user_list = [ 'aaa', 'bbb', 'ccc', ] v = reverse('n1', args=(1,)) print(v) return render(request, 'index.html', {'user_list': user_list})
|
1 2 3 4 5 6 7 8 9 10
| url(r'^index/(?P<a1>\w+)/', views.index, name='n1'), def index(request, a1): user_list = [ 'aaa', 'bbb', 'ccc', ] v = reverse('n1', kwargs={'a1': 123}) print(v) return render(request, 'index.html', {'user_list': user_list})
|
应用:
1 2
| {% url “m1” %} {% url “m1” "m2" %}
|
- 在模板中的form表单中不用action写具体的路径,直接获取路径
1 2 3 4
| url(r'^login/', views.login, name='m1'), def login(request): return render(request, 'login.html')
|
注意的是’m1’ 要加引号
1 2 3
| <form method="POST" action="{% url "m1" %}"> <input type="text"> </form>
|
1 2
| url(r'^index/', views.index, name='n1'), url(r'^edit/(\w+)/', views.edit, name='n2'),
|
下面的url "n2"接收URL ,i是拼接的路径,后面还可以添加 用空格分割
1 2 3 4 5 6 7
| <ul> {% for i in user_list %} <li>{{ i }}| <a href="{% url "n2" i %}/">编辑</a></li> {% endfor %} </ul>
|
别名是用于权限管理
- 前端处理 在模板中通过别名反向获取
- Python处理
视图函数 CBV(class based view) FBV(function based view)
CBV是URL对应类,FBV是URL对应函数
from表单提交
get 查
post 创建
View 下面的常用方法,实现增删改查
“””
get 查
post 创建
put 更新
delete 删除
“””
通过Class来获取get和post的数据,具体的实现方法是继承了View类中的dispath中的handle方法,handle通过把获取的GET/POST转换成小写,然后返回函数并执行
1 2 3 4 5
| if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs)
|
具体实现
url
CBV用类的方法as_view(),返回值是一个函数,在这里是get/post
url(r'^login.html$',views.Login.as_view()),
类
注意下面注释中的三点
1 导入View
2 继承View
3 request 获取全部的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| from django.views import View class Login(View): """ get 查 post 创建 put 更新 delete 删除 """ def get(self, request): return render(request, 'login.html') def post(self, request): user = request.POST.get('user') print(user) return HttpResponse('login.post')
|
login的前端
1 2 3 4
| <form method="POST" action="/login.html"> <input type="text" name="user"> <input type="submit" value="提交"> </form>
|
自己重写dispath方法
内部是通过反射getattr具体是dispatch函数
关键点:
1 super继承
2 返回值
3 前后加上相应的操作(批量操作),实现了装饰器的功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Login(View): def dispath(self,request,*args,**kwargs): print("before") obj = super(Login, self).dispath(request,*args,**kwargs) print('after') return obj def get(self, request): return render(request, 'login.html') def post(self, request): user = request.POST.get('user') print(user) return HttpResponse('login.post')
|
参考文章
在models中使用反射
修改类的__str__
1
1 2 3 4 5 6 7
| class UserType(models.Model): """ 用户类型 """ title = models.CharField(max_length=32) def __str__(self): return "%s-%s" %(self.id,self.title)
|
1 2 3
| v= models.UserType.objects.all().first() v= models.UserType.objects.all() print(v)
|
2
1 2 3 4 5 6 7 8 9
| class UserInfo(models.Model): """ 用户表 """ name = models.CharField(max_length=16) age = models.IntegerField() ut = models.ForeignKey('UserType') def __str__(self): return "%s-%s-%s-%s" %(self.id,self.name,self.age,self.ut)
|
1 2 3 4 5 6
| obj = models.UserType.objects.all().first() result = obj.userinfo_set.all() print(result) "<QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>" for i in result: print(i)
|
结果:
1 2 3
| 1-用户1-19-1-普通用户 3-蛋子-19-1-普通用户 4-钢弹-19-1-普通用户
|
Django的ORM操作
http请求
URL-视图(模板+数据)
ORM利用pymysql第三方连接数据库
Django默认的是MySQLDB,需要修改成pymysql
Django默认
ORM 操作表
Django自己有ORM框架,类-表,对象-行
其他的框架自己用pymysql和SqlAchemy
- 创建表
- 修改表(SQLAchemery不能修改表)
- 删除表
1 创建数据库
####2 django默认的数据库是SQLlite,修改配置文件,设置连接的数据库为MySQL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'dataname', 'USER': 'root', 'PASSWORD': '', 'HOST': 'localhost', 'PORT': 3306, } } ``` 在工程的`__init__`中添加 ```python import pymysql pymysql.install_as_MySQLdb()
|
ORM操作数据行
在models中创建类
创建user_info表,默认id自动生成,注意数据长度
1 2 3 4 5 6
| from django.db import models class UserInfo(models.Model): nid = models.BigAutoField(primary_key=True) user = models.CharField(max_length=32) password = models.CharField(max_length=64)
|
注册app
在settings中的添加
1 2 3 4 5 6 7 8 9 10 11
| INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', 'app02', 'app03', ]
|
创建表的命令
python3 manage.py makemigrations
python3 manage.py migrate
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| D:\mysite01>python3 manage.py makemigrations Migrations for 'app01': app01\migrations\0001_initial.py - Create model UserInfo D:\mysite01>python3 manage.py migrate Operations to perform: Apply all migrations: admin, app01, auth, contenttypes, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying admin.0002_logentry_remove_auto_add... OK Applying app01.0001_initial... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length... OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying auth.0007_alter_validators_add_error_messages... OK Applying auth.0008_alter_user_username_max_length... OK Applying sessions.0001_initial... OK
|
最后生成的表的名字是app01_userifo
修改表的列名
在类中直接修改,然后执行创建表的命令。
数据库的修改的内容都保存在migrations文件中,修改前会先读取,然后就行修改
输入y确认修改
1 2 3 4 5 6 7 8 9 10 11 12
| D:\mysite01>python3 manage.py makemigrations Did you rename userinfo.password to userinfo.pwd (a CharField)? [y/N] y Migrations for 'app01': app01\migrations\0004_auto_20170624_2021.py - Rename field password on userinfo to pwd D:\mysite01>python3 manage.py migrate Operations to perform: Apply all migrations: admin, app01, auth, contenttypes, sessions Running migrations: Applying app01.0004_auto_20170624_2021... OK
|
数据表增加
注意的是是否为空,有两种方案
创建外键关系
新建usergroup表,然后在userinfo表中增加一列外键关系表
ug = models.ForeignKey('UserGroup',null=True)
数据行增删改查操作
增加一行数据
1 2 3 4 5
| from app01 import models def index(request): models.UserGroup.objects.create(title="技术部") return HttpResponse("...")
|
导入多条数据
外键用ug_id,添加前要有外键的数据
1
| models.UserInfo.objects.create(user='abc', pwd='123', age=18, ug_id=1)
|
查看数据
1 2 3 4
| group_list = models.UserGroup.objects.all() print(group_list) QuerySet [<UserGroup: UserGroup object>, <UserGroup: UserGroup object>]
|
得到的结果是一个QuerySet对象,可以看做一个列表,列表中的每一个对象代表一行数据
1 2 3 4 5 6 7
| def index(request): group_list = models.UserGroup.objects.all() print(group_list) for row in group_list: print(row.id, row.title) return HttpResponse("...")
|
1 2 3 4 5
| <ul> {% for row in user_list %} <li>{{ row.nid }} | {{row.user }} | {{ row.pwd }} | {{ row.age }}</li> {% endfor %} </ul>
|
结果:
1 | abc | 123 | 18
2 | abc | 123 | 18
查看数据的范围filter
使用了双下划线
1 2 3
| user_list = models.UserInfo.objects.filter(nid=1) user_list = models.UserInfo.objects.filter(nid__gt=1) user_list = models.UserInfo.objects.filter(nid__lt=2)
|
删除数据
注意有外键的不能删除
models.UserInfo.objects.filter(nid=3).delete()
更新数据
models.UserGroup.objects.filter(id=2).update(title="新的部门")
连表操作
和SQLAchemy类似
对象可以跨表
在循环的时候跨表
拿一个的时候是obj
all 是QerySet[obj,obj]
filterQerySet[obj,obj]
正向操作
1 all()使用点
通过UserInfo 的ut(外键)连表UserType
1 2
| v = models.UserInfo.objects.all().first() print(v.ut.id,v.ut.title)
|
2 values() 使用双下划线进行跨表
返回值是字典
1 2 3 4 5 6 7 8 9 10 11
| v2 = models.UserInfo.objects.values('id','name','age','ut__id','ut__title') for i in v2: print(i) """ {'id': 1, 'name': '用户1', 'age': 19, 'ut__id': 1, 'ut__title': '普通用户'} {'id': 2, 'name': '用户2', 'age': 19, 'ut__id': 2, 'ut__title': '超级用户'} {'id': 3, 'name': '蛋子', 'age': 19, 'ut__id': 1, 'ut__title': '普通用户'} {'id': 4, 'name': '钢弹', 'age': 19, 'ut__id': 1, 'ut__title': '普通用户'} {'id': 5, 'name': '钢珠', 'age': 19, 'ut__id': 3, 'ut__title': '白金用户'} """
|
3 value_list()
values_lis也是用双下划线
返回值是元组
1 2 3 4 5 6 7 8 9
| v2 = models.UserInfo.objects.values_list('id','name','age','ut__id','ut__title') for i in v2: print(i) (1, '用户1', 19, 1, '普通用户') (2, '用户2', 19, 2, '超级用户') (3, '蛋子', 19, 1, '普通用户') (4, '钢弹', 19, 1, '普通用户') (5, '钢珠', 19, 3, '白金用户')
|
反向操作
1 小写的表名_set
下面是通过all().first()获取第一个对象。只能通过对象进行反向操作userinfo_set.all()
1 2 3 4 5 6 7 8 9 10 11
| obj = models.UserType.objects.all().first() result = obj.userinfo_set.all() print(result) "<QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>" for i in result: print(i) 下面是通过反射获得的: 1-用户1-19-1-普通用户 3-蛋子-19-1-普通用户 4-钢弹-19-1-普通用户
|
2 values
返回的是字典
1 2 3 4 5 6 7 8 9 10 11
| v = models.UserType.objects.values('id','title','userinfo') for i in v: print(i) ``` 结果: ``` {'id': 1, 'title': '普通用户', 'userinfo': 1} {'id': 1, 'title': '普通用户', 'userinfo': 3} {'id': 1, 'title': '普通用户', 'userinfo': 4} {'id': 2, 'title': '超级用户', 'userinfo': 2} {'id': 3, 'title': '白金用户', 'userinfo': 5}
|
1 2 3
| v = models.UserType.objects.values('id', 'title', 'userinfo__id','userinfo__name','userinfo__age') for i in v: print(i)
|
结果:
1 2 3 4 5
| {'id': 1, 'title': '普通用户', 'userinfo__id': 1, 'userinfo__name': '用户1', 'userinfo__age': 19} {'id': 1, 'title': '普通用户', 'userinfo__id': 3, 'userinfo__name': '蛋子', 'userinfo__age': 19} {'id': 1, 'title': '普通用户', 'userinfo__id': 4, 'userinfo__name': '钢弹', 'userinfo__age': 19} {'id': 2, 'title': '超级用户', 'userinfo__id': 2, 'userinfo__name': '用户2', 'userinfo__age': 19} {'id': 3, 'title': '白金用户', 'userinfo__id': 5, 'userinfo__name': '钢珠', 'userinfo__age': 19}
|
3 values_list
values_list返回的是元组对象
用filter进行跨表
正向操作
1 2 3 4
| v=models.UserInfo.objects.filter(ut__title='普通用户').values('id','name','ut__title') for i in v: print(i)
|
结果:
1 2 3 4
| {'id': 1, 'name': '用户1', 'ut__title': '普通用户'} {'id': 3, 'name': '蛋子', 'ut__title': '普通用户'} {'id': 4, 'name': '钢弹', 'ut__title': '普通用户'}
|
反向操作
A.onjects.filter(b__id=xx 或 b__age=xx 或 b__name=)
下面测试的是age=19的用户
1 2 3 4
| v=models.UserType.objects.filter(userinfo__age=19).values('id','title','userinfo__name') print(v) for i in v: print(i)
|
结果:
1 2 3 4 5
| {'id': 1, 'title': '普通用户', 'userinfo__name': '用户1'} {'id': 2, 'title': '超级用户', 'userinfo__name': '用户2'} {'id': 1, 'title': '普通用户', 'userinfo__name': '蛋子'} {'id': 1, 'title': '普通用户', 'userinfo__name': '钢弹'} {'id': 3, 'title': '白金用户', 'userinfo__name': '钢珠'}
|