python自动化编程-第十九天 django
上节回顾
Django请求生命周期
先到路由模式(urls.py),然后到对应的函数,函数体中,有对 db和html模板的操作;
URL对应关系(匹配)
视图函数 渲染网页
返回用户字符串或 打开一个html文件,读取内容
创建django project
django-admin startproject 工程名
cd 工程名
python3 manage.py startapp cmdb
工程名
工程名
models.py 创建数据表的文件
配置
-
模板路径
-
静态文件路径
-
注释csrf
-
编写程序
urls.py /index/ => func views.py def func(request): # 包含所有请求的数据 return HttpResponse('字符串') return render(request,'index.html',{}) return redirect('URL') 模板语言
路由系统,urls.py
普通匹配
urlpatterns = [
path('admin/', admin.site.urls),
path('index', views.index),
]
使用正则表达式匹配url
严格按照顺讯进行匹配
from django.urls import include, re_path
urlpatterns = [
re_path(r'^detail-(\d+).html$', views.detail),
path('home', views.Home.as_view()), #CBV的方式
]
分组命名的方式
urlpatterns = [
path('admin/', admin.site.urls),
path('index', views.index),
path('login', views.login),
re_path(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail),
# (?P<匹配名>) 这种分组模式,就是给分组模式命名,相当于设置关键字参数;传递给函数;那么函数就是就最好使用参数组的方式
path('home', views.Home.as_view()), #CBV的方式
]
name参数
urls.py中的name参数,会替换掉html模板中的{% url "name的值" %}
urlpatterns = [
path('admin/', admin.site.urls),
path('index', views.index,name='indedddx'),
path('login', views.login),
]
对URL路由关系进行命名;以后可以根据此名称生成自己想要的URL;
path('indeddddx', views.index,name='i1'),
re_path(r'indeddddx/(\d+)/(\d+)', views.index,name='i2'),
re_path(r'indeddddx/(?P<nid>\d+)/(?P<uid>\d+)', views.index,name='i3'),
views.py中配置
def index(request,*args,**kwargs):
v = reverse("i1") # indeddddx
v = reverse("i2",args=(90,1,)) # indeddddx/90/1
v = reverse("i3",kwargs={'nid':1,'uid':99}) # indeddddx/1/99
模板语言:
{% url 'i1' %} # indeddddx
{% url 'i2' 10 30 %} # indeddddx/10/30
{% url 'i2' nid=10 uid=20 %} # indeddddx/10/20
request.path_info 当前url
路由分发
# mysite urls.py
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r"cmdb/",include("app01.urls")),
re_path(r"app02/",include("app02.urls")),
]
# app02 urls.py
urlpatterns = [
path('login', views.login),
]
# 组合起来的url: 域名/app02/login
视图
获取用户请求数据
request.GET 获取数据
request.POST 提交数据
request.FILES
checkbox等多选的内容
request.POST.getlist()
上传文件
form标签做特殊设置
obj = request.FILES.get('file') # 文件内容
import os
file_path = os.path.join('upload', obj.name)
f = open(file_path,mode='wb')
obj.size #文件字节
for line in obj.chunks(): # 直接循环文件对象也可以;
f.write(line)
f.close()
FBV & CBV
urls.py
/index/ => func
function base view
/index/ ==》函数名
/index/ ==》类
django在处理CBV时,首先运行View中的diapath方法;找到URL和Method
ORM操作
code first => 先写代码,通过代码的类,来操作数据库
db first => 自己创建表,及对应关系,然后通过读取表结构,生成类
创建类
1. 根据类自动创建数据库表
找到app下的models.py, 创建数据库表
class UserInfo(models.Model):
# id列,自动创建,主键,自增列
# 用户名列,字符串类型,指定长度
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
前提:
在settings.py中,注册app
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01' # 创建数据库表时,django找models的路径
]
创建 数据库表
# chenzhuanglan @ chenzhuanglandeMacBook-Pro in ~/OneDrive/learning/python/python_scripts/LearnPython/day19/mysite [0:07:50]
$ python3 manage.py makemigrations
Migrations for 'app01':
app01/migrations/0001_initial.py
- Create model UserInfo
# chenzhuanglan @ chenzhuanglandeMacBook-Pro in ~/OneDrive/learning/python/python_scripts/LearnPython/day19/mysite [0:08:05]
$ 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 auth.0009_alter_user_last_name_max_length... OK
Applying sessions.0001_initial... OK
数据库引擎配置: mysite/mysite/settings.py
https://docs.djangoproject.com/en/2.0/ref/databases/#mysql-notes
在使用MYSQL时,数据库需要手动创建
create database django_test charset utf8;
Query OK, 1 row affected (0.00 sec)
MariaDB [(none)]> grant all on django_test.* to 'czlan'@'%' identified by 'czlan';
Query OK, 0 rows affected (0.01 sec)
# mysite/mysite/__init__.py
import pymysql
pymysql.install_as_MySQLdb()
## mysite/mysite/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_test', # 数据库名
'USER': 'czlan', # 用户名
'PASSWORD': 'czlan', # 密码
'HOST': '192.168.255.128', # MySQL主机
'PORT': '3306', # MySQL端口
}
}
models变更
- 字段长度变了,则需要重新创建数据表;
- 新增一个字段的话,也需要创建数据表,但是在创建数据表示,有2个选项,一般选择第一个,然后使用字符串的方式设置一个默认值;
ps:如果字段中有null=True;则直接重新创建数据表即可,不会弹出选项,因为django中字段默认不能为空;
class UserInfo(models.Model):
# id列,自动创建,主键,自增列
# 用户名列,字符串类型,指定长度
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
email = models.CharField(max_length=60)
gender = models.CharField(max_length=60,null=True)
# chenzhuanglan @ chenzhuanglandeMacBook-Pro in ~/OneDrive/learning/python/python_scripts/LearnPython/day19/mysite [15:20:24]
$ python3 manage.py makemigrations
You are trying to add a non-nullable field 'email' to userinfo without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
Select an option: 1
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
>>> "alex"
Migrations for 'app01':
app01/migrations/0002_userinfo_email.py
- Add field email to userinfo
# chenzhuanglan @ chenzhuanglandeMacBook-Pro in ~/OneDrive/learning/python/python_scripts/LearnPython/day19/mysite [15:21:12]
$ python3 manage.py migrate
System check identified some issues:
WARNINGS:
?: (mysql.W002) MySQL Strict Mode is not set for database connection 'default'
HINT: MySQL's Strict Mode fixes many data integrity problems in MySQL, such as data truncation upon insertion, by escalating warnings into errors. It is strongly recommended you activate it. See: https://docs.djangoproject.com/en/2.0/ref/databases/#mysql-sql-mode
Operations to perform:
Apply all migrations: admin, app01, auth, contenttypes, sessions
Running migrations:
Applying app01.0002_userinfo_email... OK
# chenzhuanglan @ chenzhuanglandeMacBook-Pro in ~/OneDrive/learning/python/python_scripts/LearnPython/day19/mysite [15:21:23]
$
django的数据库数据类型
字段
字符串、数字、时间、二进制、自增(models.AutoField(primary_key=True))
自增列 必须添加主键;否则报错;
整数类型 无法指定长度;
class UserGroup(models.Model):
uid = models.AutoField(primary_key=True)
caption = models.CharField(max_length=32)
class UserInfo(models.Model):
# id列,自动创建,主键,自增列
# 用户名列,字符串类型,指定长度
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
email = models.EmailField(max_length=60,null=True)
gender = models.CharField(max_length=60,null=True)
test = models.URLField(max_length=19,null=True)
test2 = models.GenericIPAddressField(max_length=19,null=True)
user_type_choice =(
(1,'超级用户'),
(2,'普通用户'),
(3,'查询用户')
)
user_type_id = models.IntegerField(choices=user_type_choice,default=1)
https://docs.djangoproject.com/en/2.0/ref/forms/fields/#built-in-field-classes
字段的参数
null 数据库中字段是否可以为空
db_column 数据库中字段的列名
db_tablespace
default 数据库中字段的默认值
primary_key 数据库中字段是否为主键
db_index 数据库中字段是否可以建立索引
unique 数据库中字段是否可以建立唯一索引
unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引
unique_for_month 数据库中字段【月】部分是否可以建立唯一索引
unique_for_year 数据库中字段【年】部分是否可以建立唯一索引
auto_now 创建时,自动生成时间
auto_now_add 更新时,自动更新为当前时间
# obj = models.UserGroup.objects.filter(id=1).update(caption='CEO')
# 上面这种方式,auto_now_add是不生效的
# obj = models.UserGroup.objects.filter(id=1).first()
# obj.caption='CEO'
# obj.save()
verbose_name Admin中显示的字段名称
blank Admin中是否允许用户输入为空
editable Admin中是否可以编辑,false则不能编辑
help_text Admin中该字段的提示信息
choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
django admin中显示下拉框
error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息;
字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
如:{'null': "不能为空.", 'invalid': '格式错误'}
validators 自定义错误验证(列表类型),从而定制想要的验证规则
from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
如:
test = models.CharField(
max_length=32,
error_messages={
'c1': '优先错信息1',
'c2': '优先错信息2',
'c3': '优先错信息3',
},
validators=[
RegexValidator(regex='root_\d+', message='错误了', code='c1'),
RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
EmailValidator(message='又错误了', code='c3'), ]
)
创建admin用户
$ python3 manage.py createsuperuser
Username (leave blank to use 'chenzhuanglan'): root
Email address: #可以不写
Password:
Password (again):
This password is too short. It must contain at least 8 characters.
Password:
Password (again):
Superuser created successfully.
2. 根据类对数据库表中的数据进行各种操作
from app01 import models
# 创建
# models.UserInfo.objects.create(
# username = 'root',
# password = '123',
# )
obj = models.UserInfo(username = 'root',password = '123',)
obj.save()
dic = {'username':'alex','password':'3333'}
# models.UserInfo.objects.create(**dic)
obj = models.UserInfo(**dic)
obj.save()
# 查
# result = models.UserInfo.objects.all()
result = models.UserInfo.objects.filter(username='root')
print(result)
# queryset理解为一个列表;
for row in result:
print(row.id,row.username,row.password)
#
# 删除
models.UserInfo.objects.filter(username='root').delete()
# 更新
models.UserInfo.objects.all().update(password='66668')
models.UserInfo.objects.filter(id=3).update(password='69')
外键操作
class UserGroup(models.Model):
uid = models.AutoField(primary_key=True)
caption = models.CharField(max_length=32)
ctime = models.DateField(max_length=60,auto_now=True)
class UserInfo(models.Model):
# id列,自动创建,主键,自增列
# 用户名列,字符串类型,指定长度
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
email = models.EmailField(max_length=60,null=True)
gender = models.CharField(max_length=60,null=True)
test = models.URLField(max_length=19,null=True)
test2 = models.GenericIPAddressField(max_length=19,null=True)
user_group = models.ForeignKey(UserGroup,to_field='uid',default=1,on_delete=models.CASCADE)
to_field 表示关联的列,默认是自增列也就是主键
此时,UserInfo表中,存储的有 user_group_id(就是UserGroup的uid),
另外还存储的有UserGroup的对象;因此在循环时,可以通过 row.usergroup.caption来获取值,做跨表查询;
创建数据时
models.UserInfo.objects.create(
username='root',
password='123',
email='saasg',
gender='mm',
test='jsjgjsg',
test2='jsjgjsg',
user_group_id = 1, #此处可以直接使用user_group的uid
)
ForeignKey(ForeignObject) # ForeignObject(RelatedField)
to, # 要进行关联的表名
to_field=None, # 要关联的表中的字段名称
on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为
- models.CASCADE,删除关联数据,与之关联也删除
- models.DO_NOTHING,删除关联数据,引发错误IntegrityError
- models.PROTECT,删除关联数据,引发错误ProtectedError
- models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
- models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
- models.SET,删除关联数据,
a. 与之关联的值设置为指定值,设置:models.SET(值)
b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
def func():
return 10
class MyModel(models.Model):
user = models.ForeignKey(
to="User",
to_field="id"
on_delete=models.SET(func),)
related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:
# 如:
- limit_choices_to={'nid__gt': 5}
- limit_choices_to=lambda : {'nid__gt': 5}
from django.db.models import Q
- limit_choices_to=Q(nid__gt=10)
- limit_choices_to=Q(nid=8) | Q(nid__gt=10)
- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
db_constraint=True # 是否在数据库中创建外键约束
parent_link=False # 在Admin中是否显示关联数据
OneToOneField(ForeignKey)
to, # 要进行关联的表名
to_field=None # 要关联的表中的字段名称
on_delete=None, # 当删除关联表中的数据时,当前表与其关联的行的行为
###### 对于一对一 ######
# 1. 一对一其实就是 一对多 + 唯一索引
# 2.当两个类之间有继承关系时,默认会创建一个一对一字段
# 如下会在A表中额外增加一个c_ptr_id列且唯一:
class C(models.Model):
nid = models.AutoField(primary_key=True)
part = models.CharField(max_length=12)
class A(C):
id = models.AutoField(primary_key=True)
code = models.CharField(max_length=1)
ManyToManyField(RelatedField)
to, # 要进行关联的表名
related_name=None, # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
related_query_name=None, # 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
limit_choices_to=None, # 在Admin或ModelForm中显示关联数据时,提供的条件:
# 如:
- limit_choices_to={'nid__gt': 5}
- limit_choices_to=lambda : {'nid__gt': 5}
from django.db.models import Q
- limit_choices_to=Q(nid__gt=10)
- limit_choices_to=Q(nid=8) | Q(nid__gt=10)
- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
symmetrical=None, # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
# 做如下操作时,不同的symmetrical会有不同的可选字段
models.BB.objects.filter(...)
# 可选字段有:code, id, m1
class BB(models.Model):
code = models.CharField(max_length=12)
m1 = models.ManyToManyField('self',symmetrical=True)
# 可选字段有: bb, code, id, m1
class BB(models.Model):
code = models.CharField(max_length=12)
m1 = models.ManyToManyField('self',symmetrical=False)
through=None, # 自定义第三张表时,使用字段用于指定关系表
through_fields=None, # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=50)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(
Person,
through='Membership',
through_fields=('group', 'person'),
)
class Membership(models.Model):
group = models.ForeignKey(Group, on_delete=models.CASCADE)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
inviter = models.ForeignKey(
Person,
on_delete=models.CASCADE,
related_name="membership_invites",
)
invite_reason = models.CharField(max_length=64)
db_constraint=True, # 是否在数据库中创建外键约束
db_table=None, # 默认创建第三张表时,数据库中表的名称


浙公网安备 33010602011771号