Fork me on GitHub

python自动化编程-第十九天 django


上节回顾

Django请求生命周期

先到路由模式(urls.py),然后到对应的函数,函数体中,有对 db和html模板的操作;

URL对应关系(匹配)
视图函数 渲染网页
返回用户字符串或 打开一个html文件,读取内容

创建django project

django-admin startproject 工程名
cd 工程名
python3 manage.py startapp cmdb

工程名
    工程名
        models.py  创建数据表的文件

配置

  1. 模板路径

  2. 静态文件路径

  3. 注释csrf

  4. 编写程序

    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变更

  1. 字段长度变了,则需要重新创建数据表;
  2. 新增一个字段的话,也需要创建数据表,但是在创建数据表示,有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,              # 默认创建第三张表时,数据库中表的名称
posted @ 2019-04-13 18:22  耳_东  阅读(165)  评论(0)    收藏  举报