django入门基础

  首先要说的是django与其余的框架分裂,django是一个包裹的及其完善的框架,我们利用django也不会像从前写学生系统那样,django操作数据库使用自带的O昂科雷M来进展操作,Torando与Flask的数据库使用就很自由(当然也得以使用大家事先的SQL
helper),并且Flask的模板都不是自带的而是利用的第一方插件。

  首先创制三个工程:

django-admin startproject mysite

  创制一个接纳:

python manage.py starapp app01

  每一个新建的app下都有多少个文件:

  migrations文件夹,存放数据库的连带音讯;

  admin.py文件,Django自带后台管理有关布署;

  modals.py,OMuranoM的连带操作;

  tests.py,单元测试;

  views文件夹大概文件,业务处理。

  路由系统

  此前的学习者系统传递nid都是由此url进行传递,那样造成链接的seo权重比较低,所以大家得以开始展览简短的优化。

  动态路由:当一条url被路由url(r’^edit/(\w+)/’,
views.edit)匹配到,那么在视图函数中定义的函数就要传播额外的参数来盛放被正则匹配到的值。

#url
url(r'^edit/(\w+)/(\w+)/', views.edit)
#视图函数
def edit(request,a1,a2):
    print(a1)
    print(a2)
    return HttpResponse('...')

  下边包车型客车例子是各类传参,当然也得以内定传参,

#指定传参
url(r'^edit/(?P<a2>\w+)/(?P<a1>\w+)/', views.edit)

#视图函数
def edit(request,a2,a1):
    print(a1)
    print(a2)
    return HttpResponse('...')

  注:那二种传参方式不得以混着用,与函数字传送参分裂的是此处的传参不可能用*args和**kwargs接收。

  伪静态:

终止符:
^edit$
伪静态:
url(r'^edit/(\w+).html$', views.edit),

  路由分发

  为了以免分化业务线(app)的开支进度中冒出的名称再一次,所以才有了路由分发的须要性。

from django.conf.urls import url,include
urlpatterns = [
    url(r'^app01/', include('app01.urls')),]

  那样路由进入就被分发到app01里面包车型大巴urls举行更进一步路由十分。

  外号与反向生成url

url(r'^edit/(\w+)/(\w+)/', views.edit,name='n2') #name就是别名
#在视图函数中:
from django.urls import reverse
v = reverse('n2',args=(1111,))
#url要是指定传参,reverse里就要用kwargs存放字典指定返回值。

  反生成url可利用在html页面中,

#url(r'^login/', views.login,name='m1'),
# def login(request):
#     return render(request,'login.html')
#login.html
<form method="POST" action="{% url "m1" %}">
        <input />

  那里的{% url “m1” %}会被渲染成能被^login/匹配的地方。

  url(r’^edit/(\w+)/’, views.edit,name=’n2′),

  {% url “n2” i %}与/edit/{{ i
}}/一样,那里n2先被替换来正则前半有个别,前面匹配的部分由i传参进去。

  ORM框架

  OLANDM一般用来做原生数据库语句转换,使我们开发特别急忙。O哈弗M不仅能够开始展览数据行的增加和删除改查操作,还足以创立,修改,删除数据表(所以作用很强劲,可以做到超越十分之五的数据库操作)。

  注:python没有主意创制数据库,只好是接二连三数据库。

  O福特ExplorerM利用pymysql等第①方工具连接数据库(无法直接链接数据库,并且暗中认可不是连连MySQL而是SQLlite)。而且默认链接MySQL的是MySQLDB模块。python3暗中同意没装MySQLDB模块,所以最利于就是改变它暗中认可连接MySQL的布署。

#默认
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
#连接MySQL
DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME':'dbname',
    'USER': 'root',
    'PASSWORD': 'xxx',
    'HOST': '',
    'PORT': '',
    }
}

  最后,大家还索要改变project下边包车型大巴init,

import pymysql
pymysql.install_as_MySQLdb()

  那样大家就足以采纳OQashqaiM操作pymysql连接MySQL数据库了。

  models文件中开创数据表的种种品质:

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)#位数也很重要
    age = models.IntegerField(default=1)

  接着要在INSTALLED_APPS[]里进入大家报了名的app名。

MySQL 1MySQL 2

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'mysite',
]

INSTALLED_APPS

  最终一步,在顶峰输入

python manage.py makemigrations
python manage.py migrate

  再去查看数据库就会增多很多表,其中app01_userinfo才是大家刚刚创设的那张表。

  那两行操作便是在app下migrations生成配置文件有关操作,migrate拿着布署音信去数据库进行连锁操作。

  今后我们假使修改表的名字就直接修改类,然后再次在终端履行那两条命令即可,当然比如要追加一行数据(例如UserInfo表里的末尾一行age),假使以前有数量,从前的数目可不曾age参数,那该怎么做呢,要么把那行数据设置为null允许为空,要么就安装私下认可值。

  外键创立

class UserGroup(models.Model):
    """
    部门
    """
    title = models.CharField(max_length=32)
class UserInfo(models.Model):
    """
    员工
    """
    nid = models.BigAutoField(primary_key=True)
    user = models.CharField(max_length=32)
    password = models.CharField(max_length=64)
    age = models.IntegerField(default=1)
    # ug_id
    ug = models.ForeignKey("UserGroup",null=True)

        ug =
models.ForeignKey(“UserGroup”,null=True)暗许在数据库中多出去的多少是ug_id。

  O昂CoraM的增加和删除改查

  增

models.UserGroup.objects.create(title='销售部')

  查

group_list = models.UserGroup.objects.all()#所有
group_list = models.UserGroup.objects.filter(id=1)#过滤
group_list = models.UserGroup.objects.filter(id__gt=1)#神奇的双下划线

  删

models.UserGroup.objects.filter(id=2).delete()

  更新

models.UserGroup.objects.filter(id=2).update(title='公关部')

MySQL 3MySQL 4

# 数据库相关操作
def index(request):
    # 增删改查
    from app01 import models
    # 新增
    # models.UserGroup.objects.create(title='销售部')
    # models.UserInfo.objects.create(user='root',password='pwd',age=18,ug_id=1)
    # 查找
    # group_list = models.UserGroup.objects.all()
    # group_list = models.UserGroup.objects.filter(id=1)
    # group_list = models.UserGroup.objects.filter(id__gt=1)
    # group_list = models.UserGroup.objects.filter(id__lt=1)

    # 删除
    # models.UserGroup.objects.filter(id=2).delete()

    # 更新
    models.UserGroup.objects.filter(id=2).update(title='公关部')

    # group_list QuerySet类型(列表)
    # QuerySet类型[obj,obj,obj]
    # print(group_list)
    # for row in group_list:
    #     print(row.id,row.title)
    # models.UserInfo.objects.all()


    group_list = models.UserGroup.objects.all()
    return render(request,'newindex.html',{"group_list": group_list})

Views.py

  这里大家寻找的group_list是相似列表的QuerySet类型。QuerySet类型能够知晓为[obj,obj,obj]。

for row in group_list:
    print(row.id,row.title)

  同理在前端一样适用

{% for row in group_list %}
    <li>{{ row.id }} === {{ row.title }}</li>
{% endfor %}

   O景逸SUVM之连表操作

  大家事先的两张表,通过外键连接,在那之中ut直接连接UserType,ut代指了usertype的一行数据,大家可以平昔动用ut.title直接跨表查询。

MySQL 5MySQL 6

from django.db import models
class UserType(models.Model):
    """
    用户类型
    """
    title = models.CharField(max_length=32)

class UserInfo(models.Model):#必须继承
    """
    员工
    """
    id = models.BigAutoField(primary_key=True)#自增可不写
    name = models.CharField(max_length=32)
    age = models.IntegerField(default=1)
    # ug_id
    ut = models.ForeignKey("UserType",null=True)#外键操作
#创建用户数据
from app01 import models
def test(request):
    # 创建数据
    # models.UserType.objects.create(title='普通用户')
    # models.UserType.objects.create(title='二逼用户')
    # models.UserType.objects.create(title='牛逼用户')
    #不要重复添加
    # models.UserInfo.objects.create(name='方',age=18,ut_id=1)
    # models.UserInfo.objects.create(name='由',age=18,ut_id=2)
    # models.UserInfo.objects.create(name='刘',age=18,ut_id=2)
    # models.UserInfo.objects.create(name='陈',age=18,ut_id=3)
    # models.UserInfo.objects.create(name='王',age=18,ut_id=3)
    # models.UserInfo.objects.create(name='杨',age=18,ut_id=1)
    return HttpResponse('...')

开创数据表的数目

MySQL 7MySQL 8

# 获取
# result取到的是QuerySet[obj,obj,obj]
result = models.UserInfo.objects.all()
for obj in result:
    print(obj.name,obj.age,obj.ut_id,obj.ut.title)#直接就连表取到值

一向跨表

MySQL 9MySQL 10

# UserInfo,ut是FK字段 - 正向操作  PS: 一个用户只有一个用户类型
obj = models.UserInfo.objects.all().first()#取出第一个queryset数据
print(obj.name,obj.age,obj.ut.title)#因为obj只是一个数据只能对应一种用户

正向跨表

MySQL 11MySQL 12

# UserType, 表名小写_set.all()  - 反向操作   PS: 一个用户类型下可以有很多用户
obj = models.UserType.objects.all().first()
print('用户类型',obj.id,obj.title)
for row in obj.userinfo_set.all():#obj.userinfo_set里是userinfo的query对象,.all()取出所有数据
    print(row.name,row.age)

反向跨表

MySQL 13MySQL 14

#反向取出每一行的queryset
result = models.UserType.objects.all()
for item in result:#相当于取出每一行用户类型对应的用户的queryset
    for i in item.userinfo_set.all():
        print(i.name)
#过滤每一行
result = models.UserType.objects.all().filter(id= 1 )#<QuerySet [<UserType: UserType object>]>
for item in result:
    print(item.userinfo_set.filter(id =1))#<QuerySet [<UserInfo: UserInfo object>]>

反向跨表补充

MySQL 15MySQL 16

result = models.UserInfo.objects.all().values('id','name')#只取两列
# 并且每列的QuerySet[{'id':'xx','name':'xx'} ]都是这样的字典
for row in result:
    print(row)
result2 = models.UserInfo.objects.all().first()
print(result2)#UserInfo object

字典取值

MySQL 17MySQL 18

result = models.UserInfo.objects.all().values_list('id','name')
# QuerySet[(1,'f'), ]
for row in result:
    print(row)

元组取值

MySQL 19MySQL 20

当取出的queryset里面是obj对象的时候,可以直接在for循环里跨表,但是当取出的queryset里是字典或者元祖对象的时候,那么在for循环里就不可以跨表了,这时候就要使用神奇的双下划线
models.UserInfo.objects.filter(id__gt=1).values('id','name')#可以取到id>1的queryset对象。
# [{id:1,name:fd},{id:1,name:fd},{id:1,name:fd},]
# models.UserInfo.objects.all().values('id','name')
# models.UserInfo.objects.filter(id__gt=1).values('id','name')
# 无法跨表
# result = models.UserInfo.objects.all().values('id','name')
# for item in result:
#     print(item['id'],item['name'])
# 夸表  __
# result = models.UserInfo.objects.all().values('id','name',"ut__title")
# for item in result:
#     print(item['id'],item['name'],item['ut__title'])
# [(1,df),(2,'df')]
# models.UserInfo.objects.all().values_list('id','name')
# models.UserInfo.objects.filter(id__gt=1).values_list('id','name')
# 无法跨表
# result = models.UserInfo.objects.all().values_list('id','name')
# for item in result:
#     print(item[0],item[1])
# 夸表  __
# result = models.UserInfo.objects.all().values_list('id','name',"ut__title")
# for item in result:
#     print(item[0],item[1],item[2])

神奇的双下划线

    v = models.UserInfo.objects.values('id','name') # 6
    v = models.UserInfo.objects.values('id','name','ut__title') # 6
    # select * from userinfo left join usertype

    v1 = models.UserType.objects.values('id','title')
    print(v1) # 4
    v2 = models.UserType.objects.values('id','title','userinfo__name')
    print(v2) #7
    # select  * from usertype left join userinfo
#正向跨表与反向跨表与left join类似,谁在前面就是查他的所有,没有匹配到的那一行值为none填充
正:
1. q = UserInfo.objects.all().first()
    q.ug.title
2. 
     UserInfo.objects.values('nid','ug_id')              
     UserInfo.objects.values('nid','ug_id','ug__title')  
3. UserInfo.objects.values_list('nid','ug_id','ug__title')
反:
1. 小写的表名_set
     obj = UserGroup.objects.all().first()
   result = obj.userinfo_set.all() [userinfo对象,userinfo对象,]

2. 小写的表名
     v = UserGroup.objects.values('id','title')          
     v = UserGroup.objects.values('id','title','小写的表名称')          
     v = UserGroup.objects.values('id','title','小写的表名称__age')          

3. 小写的表名
     v = UserGroup.objects.values_list('id','title')          
     v = UserGroup.objects.values_list('id','title','小写的表名称')          
     v = UserGroup.objects.values_list('id','title','小写的表名称__age') 
正向:
    xxxx.filter(ut__title='超级用户').values('id','name','ut__title')
反向:
    xxxx.filter(表名称__title='超级用户').values('id','name','表名称__title')

MySQL 21MySQL 22

# 1.增删改查
# 2. 一般:
    # models.UserInfo.objects.filter(id__gt=1)
    # models.UserInfo.objects.filter(id__lt=1)
    # models.UserInfo.objects.filter(id__lte=1)
    # models.UserInfo.objects.filter(id__gte=1)
    # models.UserInfo.objects.filter(id__in=[1,2,3])
    # models.UserInfo.objects.filter(id__range=[1,2])
    # models.UserInfo.objects.filter(name__startswith='xxxx')
    # models.UserInfo.objects.filter(name__contains='xxxx')
    # models.UserInfo.objects.exclude(id=1)
# 3. 排序
    user_list = models.UserInfo.objects.all().order_by('-id','name')

# 4. 分组
    from django.db.models import Count,Sum,Max,Min
    # v =models.UserInfo.objects.values('ut_id').annotate(xxxx=Count('id'))
    # print(v.query)
    # v =models.UserInfo.objects.values('ut_id').annotate(xxxx=Count('id')).filter(xxxx__gt=2)
    # print(v.query)having
    # v =models.UserInfo.objects.filter(id__gt=2).values('ut_id').annotate(xxxx=Count('id')).filter(xxxx__gt=2)
    # print(v.query)where



# 5. F,更新时用于获取原来的值
    # from django.db.models import F,Q
    # models.UserInfo.objects.all().update(age=F("age")+1)

# 6. Q,用于构造复杂查询条件
    # 应用一:
            # models.UserInfo.objects.filter(Q(id__gt=1))
            # models.UserInfo.objects.filter(Q(id=8) | Q(id=2))
            # models.UserInfo.objects.filter(Q(id=8) & Q(id=2))
    # 应用二:
            # q1 = Q()
            # q1.connector = 'OR'
            # q1.children.append(('id__gt', 1))
            # q1.children.append(('id', 10))
            # q1.children.append(('id', 9))
            #
            #
            # q2 = Q()
            # q2.connector = 'OR'
            # q2.children.append(('c1', 1))
            # q2.children.append(('c1', 10))
            # q2.children.append(('c1', 9))
            #
            # q3 = Q()
            # q3.connector = 'AND'
            # q3.children.append(('id', 1))
            # q3.children.append(('id', 2))
            # q2.add(q3,'OR')
            #
            # con = Q()
            # con.add(q1, 'AND')
            # con.add(q2, 'AND')
            # (id=1 or id = 10 or id=9 or (id=1 and id=2)) and (c1=1 or c1=10 or c1=9)
            # models.UserInfo.objects.filter(con)
    # condition_dict = {
    #     'k1':[1,2,3,4],
    #     'k2':[1,],
    # }
    # con = Q()
    # for k,v in condition_dict.items():
    #     q = Q()
    #     q.connector = 'OR'
    #     for i in v:
    #         q.children.append(('id', i))
    #     con.add(q,'AND')
    # models.UserInfo.objects.filter(con)

# 7. extra, 额外查询条件以及相关表,排序

    models.UserInfo.objects.filter(id__gt=1)
    models.UserInfo.objects.all() 
    # id name age ut_id


    models.UserInfo.objects.extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
    # a. 映射
        # select 
        # select_params=None
        # select 此处 from 表

    # b. 条件
        # where=None
        # params=None,
        # select * from 表 where 此处

    # c. 表
        # tables
        # select * from 表,此处

    # c. 排序
        # order_by=None
        # select * from 表 order by 此处


    models.UserInfo.objects.extra(
        select={'newid':'select count(1) from app01_usertype where id>%s'},
        select_params=[1,],
        where = ['age>%s'],
        params=[18,],
        order_by=['-age'],
        tables=['app01_usertype']
    )
    """
    select 
        app01_userinfo.id,
        (select count(1) from app01_usertype where id>1) as newid
    from app01_userinfo,app01_usertype
    where 
        app01_userinfo.age > 18
    order by 
        app01_userinfo.age desc
    """

    result = models.UserInfo.objects.filter(id__gt=1).extra(
        where=['app01_userinfo.id < %s'],
        params=[100,],
        tables=['app01_usertype'],
        order_by=['-app01_userinfo.id'],
        select={'uid':1,'sw':"select count(1) from app01_userinfo"}
    )
    print(result.query)
    # SELECT (1) AS "uid", (select count(1) from app01_userinfo) AS "sw", "app01_userinfo"."id", "app01_userinfo"."name", "app01_userinfo"."age", "app01_userinfo"."ut_id" FROM "app01_userinfo" , "app01_usertype" WHERE ("app01_userinfo"."id" > 1 AND (app01_userinfo.id < 100)) ORDER BY ("app01_userinfo".id) DESC

# 8. 原生SQL语句

    from django.db import connection, connections

    cursor = connection.cursor() # connection=default数据
    cursor = connections['db2'].cursor()

    cursor.execute("""SELECT * from auth_user where id = %s""", [1])

    row = cursor.fetchone()
    row = cursor.fetchall()


    - extra
    - 原生SQL语句
    - raw
        result = models.UserInfo.objects.raw('select * from userinfo')
        [obj(UserInfo),obj,]
        result = models.UserInfo.objects.raw('select id,1 as name,2 as age,4 as ut_id from usertype')
        [obj(UserInfo),obj,]

        v1 = models.UserInfo.objects.raw('SELECT id,title FROM app01_usertype',translations=name_map)

# 9. 简单的操作
    http://www.cnblogs.com/wupeiqi/articles/6216618.html

Django ORM操作

MySQL 23MySQL 24

# """
    #     select
    #         id,
    #         name,
    #         (select count(1) from tb) as n
    #     from xb where ....
    # """
    #
    # v = models.UserInfo.objects.all().extra(
    #     select={
    #         'n':"select count(1) from app01_usertype where id=%s or id=%s",
    #         'm':"select count(1) from app01_usertype where id=%s or id=%s",
    #     },
    #     select_params=[1,2,3,4])
    # for obj in v:
    #     print(obj.name,obj.id,obj.n)

    # models.UserInfo.objects.extra(
    #     where=["id=1","name='alex'"]
    # )
    # models.UserInfo.objects.extra(
    #     where=["id=1 or id=%s ","name=%s"],
    #     params=[1,"alex"]
    # )

    # models.UserInfo.objects.extra(
    #     tables=['app01_usertype'],
    # )
    # """select * from app01_userinfo,app01_usertype"""


    # result = models.UserInfo.objects.filter(id__gt=1)
    # print(result.query)
    # result = models.UserInfo.objects.filter(id__gt=1).extra(
    #     where=['app01_userinfo.id < %s'],
    #     params=[100,],
    #     tables=['app01_usertype'],
    #     order_by=['-app01_userinfo.id'],
    #     select={'uid':1,'sw':"select count(1) from app01_userinfo"}
    # )
    # print(result.query)

    # v = models.UserInfo.objects.all().order_by('-id','name')
    # v = models.UserInfo.objects.all().order_by('-id','name').reverse()#只有加order by才可以用reverse
    # v = models.UserInfo.objects.all().order_by('id','-name')
    # print(v)

    # v = models.UserInfo.objects.all()
    # [obj]
    # v = models.UserInfo.objects.all().only('id','name')#只拿id,only,还是obj,能取到age但是不要用only还去取,因为每次取都增加一次查询
    # v = models.UserInfo.objects.all().defer('name')#除了name以外的数据
    # # [obj]
    # for obj in v:
    #     obj.id,obj.name
    # models.UserInfo.objects.values('id','name')
    # [{id,nam}]

    # models.UserInfo.objects.all().using('db2')#指定去哪个数据库取

    # models.UserInfo.objects.all().filter().all().exclude().only().defer()

    # models.UserInfo.objects.none()
    # result = models.UserInfo.objects.aggregate(k=Count('ut_id', distinct=True), n=Count('id'))
    # print(result)

    # v = models.UserInfo.objects.all().first()
    # # models.UserInfo.objects.get(id=1)
    #
    # obj = models.UserType.objects.create(title='xxx')
    # obj = models.UserType.objects.create(**{'title': 'xxx'})
    # print(obj.id)
    #
    # obj = models.UserType(title='xxx')
    # obj.save()


    # objs = [
    #     models.UserInfo(name='r11'),
    # ]
    # models.UserInfo.objects.bulk_create(objs, 10)

    # obj, created = models.UserInfo.objects.get_or_create(
    #     username='root1',
    #     pwd='ff',
    #     defaults={'email': '1111111','u_id': 2, 't_id': 2})

    # models.UserInfo.objects.filter(id__in=[1,2,3])
    # models.UserInfo.objects.in_bulk([1,2,3])
    # name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
    # models.UserInfo.objects.raw('SELECT * FROM app01_usertype', translations=name_map)
    name_map = {'title': 'name'}
    v1 = models.UserInfo.objects.raw('SELECT id,title FROM app01_usertype',translations=name_map)
    for i in v1:
        print(i,type(i))

ORM测试

MySQL 25MySQL 26

#每次跨表取值的时候都要进行一次数据库查询
# q = models.UserInfo.objects.all()
# select * from userinfo
# for row in q:
#     print(row.name,row.ut.title)
# select_related: 查询主动做连表(for循环里面不会再查表了)
# q = models.UserInfo.objects.all().select_related('ut','gp')
# select * from userinfo inner join usertype on ...
# for row in q:
#     print(row.name,row.ut.title)
# prefetch_related: 不做连表,做多次查询(这里是两次单表查询,更快)
# q = models.UserInfo.objects.all().prefetch_related('ut')
# select * from userinfo;
# Django内部:ut_id = [2,4]
# select * from usertype where id in [2,4]
# for row in q:
#     print(row.id,row.ut.title)

连表与操作数据库

   O奥迪Q3M操作多对多

MySQL 27MySQL 28

#数据表操作
class Boy(models.Model):
    name = models.CharField(max_length=32)
    m = models.ManyToManyField('Girl',through="Love",through_fields=('b','g',))


class Girl(models.Model):
    nick = models.CharField(max_length=32)
    # m = models.ManyToManyField('Boy')

class Love(models.Model):
    b = models.ForeignKey('Boy')
    g = models.ForeignKey('Girl')

    class Meta:
        unique_together = [
            ('b','g'),
        ]
#数据行添加
objs = [
    models.Boy(name='方'),
    models.Boy(name='由'),
    models.Boy(name='陈'),
    models.Boy(name='闫'),
    models.Boy(name='吴'),
]
models.Boy.objects.bulk_create(objs,5)

objss = [
    models.Girl(nick='小鱼'),
    models.Girl(nick='小周'),
    models.Girl(nick='小猫'),
    models.Girl(nick='小狗'),
]
models.Girl.objects.bulk_create(objss,5)

models.Love.objects.create(b_id=1,g_id=1)
models.Love.objects.create(b_id=1,g_id=4)
models.Love.objects.create(b_id=2,g_id=4)
models.Love.objects.create(b_id=2,g_id=2)

桑土绸缪数据库操作

MySQL 29MySQL 30

# 和方有关系的姑娘
方法一:
obj = models.Boy.objects.filter(name='方').first()#obj而不是queryset
print(obj)#Boy object
love_list = obj.love_set.all()
print(love_list)#<QuerySet [<Love: Love object>, <Love: Love object>]>
for row in love_list:
    print(row)#Love object
    print(row.g.nick)#在循环里多次跨表
方法二:
love_list = models.Love.objects.filter(b__name='方')
for row in love_list:
    print(row.g.nick)#与第一个方法相似,也是多次跨表
方法三:
love_list = models.Love.objects.filter(b__name='方').values('g__nick')
for item in love_list:
    print(item['g__nick'])#只循环前多查一次数据库
方法四:
love_list = models.Love.objects.filter(b__name='方').select_related('g')
for obj in love_list:
    print(obj.g.nick)#与三类似,只是obj不是字典组成queryset

多对多连表

  在此间要的是,第①张Love表那里是能够写也得以不写的,

m = models.ManyToManyField('Girl',through="Love",through_fields=('b','g',))#这种写法就是指定了第三张表

  这一行代码为大家创立了一张boy与girl的多对多表,不过这张表仅包括boy与girl的附和关系,固然想要扩充别的的音信,那么第3张表就非得要协调写了。

  manytomany创建的第①张表,因为她不存在类创设,所以我们对他开始展览增加和删除改查都只可以在创设者的obj中修改它。

MySQL 31MySQL 32

obj = models.Boy.objects.filter(name='方').first()
print(obj.id,obj.name)
obj.m.add(3)
obj.m.add(2,4)
obj.m.add(*[1,])

obj.m.remove(1)
obj.m.remove(2,3)
obj.m.remove(*[4,])

obj.m.set([1,])
q = obj.m.all()#这里的q取到的其实是[Girl对象]
    # obj = models.Boy.objects.filter(name='方').first()
    # girl_list = obj.m.all()
    # girl_list = obj.m.filter(nick='小鱼')
    # print(girl_list)
    # obj = models.Boy.objects.filter(name='方').first()
    # obj.m.clear()
    # obj = models.Girl.objects.filter(nick='小鱼').first()
    # print(obj.id,obj.nick)
    # v = obj.boy_set.all()#反向找到与小鱼有关的boy的信息
    # print(v)
obj = models.Boy.objects.filter(name='方').first()
v=obj.m.all()#v取到的就是<QuerySet [<Girl: Girl object>, <Girl: Girl object>]>

其三张表操作

   与MySQL操作一样,O君越M也提供了很多的数据库数据类型供大家运用,不过有个别字段类型,大家限制为邮箱类型,但实在用create方法大概可以写成字符串写进去,但是在admin后台却具有分明的限定。具体字段在武sir的博客里有(6216618)。

MySQL 33MySQL 34

color_list = (
    (1,'黑色'),
    (2,'白色'),
    (3,'蓝色'))
color = models.IntegerField(choices=color_list)
在django后台admin里会生成下拉框的选择,但是在MySQL中显示的依然是int类型的数字。

django枚举

  所以我们对字段的操作与admin里的操作并不同,他们都有谈得来的一套字段。

MySQL 35MySQL 36

class UserInfo(models.Model):
        nid = models.AutoField(primary_key=True)
        username = models.CharField(max_length=32)
        class Meta:
            # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
            db_table = "table_name"

            # 联合索引
            index_together = [
                ("pub_date", "deadline"),
            ]

            # 联合唯一索引
            unique_together = (("driver", "restaurant"),)

            # admin中显示的表名称
            verbose_name

            # verbose_name加s
            verbose_name_plural

元信息

 

  django之CBV

  我们事先在工程的urls中写的路由对应在视图中是以函数的样式再次来到的HttpResponse对象,浏览器向服务器发送请求时包涵了url等请求新闻,服务器获得音信后找到url和请求格局,再拿着url在后台进行匹配。除了那种方式以外还能透过类举办return,便是CBV。

from app01 import views
urlpatterns = [
    url(r'^login.html$', views.Login.as_view()),#类名.as_view()是特殊写法
]

class Login(View):#必须继承View类
    """
    ajax可以各种提交(默认是以下意思)
    get     查
    post    创建
    put     更新
    delete  删除
    """
    def dispatch(self, request, *args, **kwargs):#我们自己也可以写dispatch,批量操作可以自己写
        print('before')
        obj = super(Login,self).dispatch(request, *args, **kwargs)
        print('after')
        return obj

    def get(self,request):#request存放请求相关的所有数据,get与post等提交方式分离
        # return HttpResponse('Login.get')
        return render(request,'login.html')

    def post(self,request):
        print(request.POST.get('user'))
        return HttpResponse('Login.post')

  对于提交的种种方法类是怎么辨识出来的啊,反正肯定不是if判断,其实在类里面使用的是反光的办法贯彻的。

  所以在函数执行get或post以前,其实是先进行了类里面包车型大巴dispatch函数。

  django分页

  django本人自带分页作用(局限性使得无法广泛选择)

MySQL 37MySQL 38

from django.core.paginator import Paginator,Page,PageNotAnInteger,EmptyPage
def index(request):
    """
    分页
    :param request:
    :return:
    """
    # for i in range(300):
    #     name = "root" + str(i)
    #     models.UserInfo.objects.create(name=name,age=18,ut_id=1)

    current_page = request.GET.get('page')
    #所以页数要在url中传参
    user_list = models.UserInfo.objects.all()
    paginator = Paginator(user_list,10)
    # per_page: 每页显示条目数量
    # count:    数据总个数
    # num_pages:总页数
    # page_range:总页数的索引范围,如: (1,10),(1,200)
    # page:     page对象
    try:
        posts = paginator.page(current_page)
    except PageNotAnInteger as e:
        posts = paginator.page(1)
    except EmptyPage as e:
        posts = paginator.page(1)
    # has_next              是否有下一页
    # next_page_number      下一页页码
    # has_previous          是否有上一页
    # previous_page_number  上一页页码
    # object_list           分页之后的数据列表posts.object_list
    # number                当前页
    # paginator             paginator对象
    return render(request,'index.html',{'posts':posts})

django自带分页

MySQL 39MySQL 40

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<ul>
    {% for item in posts %}
        <li>{{ item }}</li>
    {% endfor %}
</ul>

<div class="pagination">

        {% if posts.has_previous %}
            <a href="?p={{ posts.previous_page_number }}">Previous</a>
        {% endif %}

            Page {{ posts.number }} of {{ posts.paginator.num_pages }}.

          {% if posts.has_next %}
              <a href="?p={{ posts.next_page_number }}">Next</a>
          {% endif %}


</div>
</body>
</html>

页面.html

MySQL 41MySQL 42

def custom(request):
    current_page = request.GET.get('page')
    current_page = int(current_page)
    per_page = 10

    start=(current_page-1)*per_page
    end=current_page * per_page
    user_list=models.UserInfo.objects.all()[start:end]
    return render(request,'custom.html',{'user_list':user_list})

自定义分页1.0

MySQL 43MySQL 44

class PageInfo(object):

    def __init__(self,current_page,all_count,per_page,base_url,show_page=11):
        """

        :param current_page:
        :param all_count: 数据库总行数
        :param per_page: 每页显示函数
        :return:
        """
        try:
            self.current_page = int(current_page)#非数字操作
        except Exception as e:
            self.current_page = 1
        self.per_page = per_page

        a,b = divmod(all_count,per_page)#all_count/per_page,b!=0则+1
        if b:
            a = a +1
        self.all_pager = a
        self.show_page = show_page
        self.base_url = base_url
    def start(self):
        return (self.current_page-1) * self.per_page

    def end(self):
        return self.current_page * self.per_page


    def pager(self):
        # v = "<a href='/custom.html?page=1'>1</a><a href='/custom.html?page=2'>2</a>"
        # return v
        page_list = []

        half = int((self.show_page-1)/2)

        # 如果数据总页数 < 11
        if self.all_pager < self.show_page:
            begin = 1
            stop = self.all_pager + 1
        # 如果数据总页数 > 11
        else:
            # 如果当前页 <=5,永远显示1,11
            if self.current_page <= half:
                begin = 1
                stop = self.show_page + 1
            else:
                if self.current_page + half > self.all_pager:
                    begin = self.all_pager - self.show_page + 1
                    stop = self.all_pager + 1
                else:
                    begin = self.current_page - half
                    stop = self.current_page + half + 1

        if self.current_page <= 1:
            prev = "<li><a href='#'>上一页</a></li>"
        else:
            prev = "<li><a href='%s?page=%s'>上一页</a></li>" %(self.base_url,self.current_page-1,)
        page_list.append(prev)

        for i in range(begin,stop):
            if i == self.current_page:
                temp = "<li class='active'><a  href='%s?page=%s'>%s</a></li>" %(self.base_url,i,i,)
            else:
                temp = "<li><a href='%s?page=%s'>%s</a></li>" %(self.base_url,i,i,)
            page_list.append(temp)

        if self.current_page >= self.all_pager:
            nex = "<li><a href='#'>下一页</a></li>"
        else:
            nex = "<li><a href='%s?page=%s'>下一页</a></li>" %(self.base_url,self.current_page+1,)
        page_list.append(nex)
        return ''.join(page_list)

自定义分页模块pager.py

MySQL 45MySQL 46

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css" />
</head>
<body>
    <h1>用户列表</h1>
    <ul>
        {% for row in user_list %}
            <li>{{ row.name }}</li>
        {% endfor %}
    </ul>
    <nav aria-label="Page navigation">
        <ul class="pagination">
            {{ page_info.pager|safe }}
        </ul>
    </nav>
</body>
</html>

page.html

   django模板

  模板函数与自定义函数

  {{ name|upper }}自带的函数使用这种艺术就足以应用了。

  自定义函数

  首先要在行使里面新建一个templatetags文件夹,里面写1个xx.py文件用来制造自定义函数。

MySQL 47MySQL 48

from django import template

register = template.Library()#变量名register还不能改

@register.filter#可以放在条件语句后面,但最多能传两个值
def my_upper(value,arg):
    return value + arg
@register.filter
def my_bool(value):
    return False


@register.simple_tag#不能放在条件语句中
def my_lower(value,a1,a2,a3):

    return value + a1 + a2 + a3

xx.py

MySQL 49MySQL 50

{% load xx %}//导入写的xx.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>111</h1>
{% csrf_token %}//csrf值
{{ name|my_upper:"666" }}
{% my_lower "ALEX" "x" "SB" "V" %}
        {% if name|my_bool %}
            <h3>真</h3>
        {% else %}
            <h3>假</h3>
        {% endif %}
</body>
</html>

test.html

  最终所在app一定要登记才能不辱职务。

  在django中程导弹入小组件使用include导入,

MySQL 51MySQL 52

pub.html
<div>
<h3>特别漂亮的组件</h3>
<div class="title">标题:{{ name }}</div>
<div class="content">内容:{{ name }}</div>
</div>

组件的html

MySQL 53MySQL 54

test.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        {% include 'pub.html' %}
        {% include 'pub.html' %}
        {% include 'pub.html' %}
    </body>
    </html>

引用

  Session

  一句话简述Session,正是储存在服务端的数目,cookie则是存在客户端浏览器上的键值对。Session和cookie要做的事务都以同样的,都以为着缓解http的短链接而生的,在账户提交post新闻的时候,给客户端发一个cookie钥匙,那么客户端浏览器下三遍来的时候带着这一个键值对,服务器端就清楚她是何人了。不过自个儿觉得这么倒霉,因为音讯都位居客户端,那样客户端就算篡改了新闻(固然你做了加密也是有高风险的),那么难题就很惨重,而Session做的是如出一辙的事,不过新闻都以放在服务器端的,那样用户提交post音讯给自身,笔者就生成一把钥匙,同时给客户端浏览器一把,本人留一把,并且在数据库保存那把钥匙对应的数据资料,下一次有人来的时候实行表达,那正是Session的规律。

  Session其实照旧依靠于cookie的。

MySQL 55MySQL 56

def login1(request):
    if request.method == 'GET':
        return render(request,'login.html')
    else:
        u = request.POST.get('user')
        p = request.POST.get('pwd')
        if u=='jeff'and p=='123':
            # 1. 生成随机字符串
            # 2. 通过cookie发送给客户端
            # 3. 服务端保存
            # {
            #   随机字符串1: {'username':'jeff','email':x''...}
            # }
            request.session['username'] = 'jeff'
            request.session['email'] = 'jeff@123456'
            return redirect('/index/')
        else:
            return render(request,'login.html',{'msg':'用户名或密码错误'})

def index(request):
    # 1. 获取客户端端cookie中的随机字符串
    # 2. 去session中查找有没有随机字符
    # 3. 去session对应key的value中查看是否有 username
    v = request.session.get('username')
    if v:
        return HttpResponse('登录成功:%s' %v)
    else:
        return redirect('/login1/')

session操作

   Django中暗中认可协理Session,其里面提供了5种档次的Session供开发者使用,分别是db,缓存,file,缓存+db,和加密cookie(那种意义上与cookie加密没什么实质上的界别)。

MySQL 57MySQL 58

 SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)

db

MySQL 59MySQL 60

SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置

缓存

MySQL 61MySQL 62

SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 

文件

MySQL 63MySQL 64

SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎

缓存+数据库Session

MySQL 65MySQL 66

ESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎

加密cookie Session

MySQL 67MySQL 68

def login(func):
    def wrap(request, *args, **kwargs):
        # 如果未登陆,跳转到指定页面
        if request.path == '/test/':
            return redirect('http://www.baidu.com')
        return func(request, *args, **kwargs)
    return wrap

证实session的登陆装饰器

 

  Django默许协理Session,并且私下认可是将Session数据存款和储蓄在数据库中,即:django_session
表中。

MySQL 69MySQL 70

    SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)

    SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
    SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)
    SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
    SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
    SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
    SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
    SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)

setting.py

MySQL 71MySQL 72

def index(request):
        # 获取、设置、删除Session中数据
        request.session['k1']
        request.session.get('k1',None)
        request.session['k1'] = 123
        request.session.setdefault('k1',123) # 存在则不设置
        del request.session['k1']

        # 所有 键、值、键值对
        request.session.keys()
        request.session.values()
        request.session.items()
        request.session.iterkeys()
        request.session.itervalues()
        request.session.iteritems()


        # 用户session的随机字符串
        request.session.session_key

        # 将所有Session失效日期小于当前日期的数据删除
        request.session.clear_expired()

        # 检查 用户session的随机字符串 在数据库中是否
        request.session.exists("session_key")

        # 删除当前用户的所有Session数据
        request.session.delete("session_key")

        request.session.set_expiry(value)
            * 如果value是个整数,session会在些秒数后失效。
            * 如果value是个datatime或timedelta,session就会在这个时间后失效。
            * 如果value是0,用户关闭浏览器session就会失效。
            * 如果value是None,session会依赖全局session失效策略。

操作session里的数量

  Form表单

  form能够帮我们成功很多表单提交的数额表达的难点,将再一次操作简单化。其内部含有了正则表明式匹配。

MySQL 73MySQL 74

from django.forms import Form
from django.forms import fields
class LoginForm(Form):
    # 正则验证: 不能为空,6-18
    username = fields.CharField(
        max_length=18,
        min_length=6,
        required=True,
        error_messages={
            'required': '用户名不能为空',
            'min_length': '太短了',
            'max_length': '太长了',
        }
    )
    # 正则验证: 不能为空,16+
    password = fields.CharField(min_length=16,required=True)
    # email = fields.EmailField()
    # email = fields.GenericIPAddressField()
    # email = fields.IntegerField()


def login(request):
    if request.method == "GET":
        return render(request,'login.html')
    else:
       obj = LoginForm(request.POST)
       if obj.is_valid():
           # 用户输入格式正确
           print(obj.cleaned_data) # 字典类型
           return redirect('http://www.baidu.com')
       else:
           # 用户输入格式错误
           return render(request,'login.html',{'obj':obj})

form表单的接纳

  form表单里定义的class中的字段与前者传递的name一致,这是因为form内部验证is_valid分为五个步骤,第二步在实例化LoginForm时,获取类中所有的字段和与之相应的正则表明式,做成一个字典,

self.fields={
    'user': 正则表达式
    'pwd': 正则表达式}

  第贰步,循环那个字典,

  flag = True
for k,v in self.fields.items():
# 1. user,正则表达式
    input_value = request.POST.get(k)#这个时用户提交过来的信息
    正则表达式和input_value进行匹配
        匹配失败改变flag
    flag = False
  return flag

  所以class定义的字段与前者表单新闻一致。

  django定义了无数字段类型,不过一定是不够我们用的,所以不时大家须求团结定制字段。

MySQL 75MySQL 76

class TestForm(Form):
    t1 = fields.CharField(
        required=True,
        max_length=8,
        min_length=2,
        error_messages={
            'required': '不能为空',
            'max_length': '太长',
            'min_length': '太短',
        }
    )
    t2 = fields.IntegerField(
        min_value=10,
        max_value=1000,
        error_messages={
            'required': 't2不能为空',
            'invalid': 't2格式错误,必须是数字',#格式错误都是
            'min_value': '必须大于10',
            'max_value': '必须小于1000',
        },
    )
    t3 = fields.EmailField(
        error_messages={
            'required': 't3不能为空',
            'invalid': 't3格式错误,必须是邮箱格式',
        }
    )

常用字段

  自定制字段RegexField,继承CharField。

phone = fields.RegexField('139\d+')

   form表单的插件(自动生成input标签)

Field
    required=True,               是否允许为空
    widget=None,                 as_p中指定input生成的类型
    label=None,                  用于生成Label标签或显示内容
    initial=None,                as_p初始值
    help_text='',                帮助信息(在标签旁边显示)
    error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
    show_hidden_initial=False,   是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
    validators=[],               自定义验证规则
    localize=False,              是否支持本地化
    disabled=False,              as_p是否可以编辑
    label_suffix=None            Label内容后缀as_p
    as_p                         给所有的fields生成input标签

MySQL 77MySQL 78

class TestForm(Form):
    t1 = fields.CharField(required=True,max_length=8,min_length=2,label='用户名',
                          help_text='111',initial='333',
        error_messages={
            'required': '不能为空',
            'max_length': '太长',
            'min_length': '太短',
        },

    )
    t2 = fields.EmailField()

def test(request):
    if request.method == "GET":
        obj = TestForm()
        return render(request,'test.html',{'obj': obj})
    else:
        obj = TestForm(request.POST)
        if obj.is_valid():
            print(obj.cleaned_data)
        else:
            print(obj.errors)
        return render(request,'test.html',{'obj':obj})
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <form action="/test/" method="POST" novalidate>
        {% csrf_token %}
        <p>
            {{ obj.t1.label }}{{ obj.as_p }}{{ obj.t1.help_text}}{{ obj.errors.t1.0 }}
        </p>
        <p>
            {{ obj.t2 }}{{ obj.errors.t2.0 }}
        </p>
        <input type="submit" value="提交" />
    </form>
</body>
</html>

表单插件应用

MySQL 79MySQL 80

class RegiterForm(Form):
    user = fields.CharField(min_length=8)
    email = fields.EmailField()
    password = fields.CharField()
    phone = fields.RegexField('139\d+')


def register(request):
    if request.method == 'GET':
        obj = RegiterForm()#此时生成的html没有数据
        return render(request,'register.html',{'obj':obj})
    else:
        obj = RegiterForm(request.POST)#此时生成html里面有post的值
        if obj.is_valid():
            print(obj.cleaned_data)
        else:
            print(obj.errors)
        return render(request,'register.html',{'obj':obj})

    <form action="/register/" method="POST" novalidate>
        {% csrf_token %}
        <p>
            {{ obj.user }} {{ obj.errors.user.0 }}
        </p>
        <p>
            {{ obj.email }} {{ obj.errors.email.0 }}
        </p>
        <p>
            {{ obj.password }} {{ obj.errors.password.0 }}
        </p>
        <p>
            {{ obj.phone }} {{ obj.errors.phone.0 }}
        </p>
        <input type="submit" value="提交"  />
    </form>

form提交保留上次消息

  Ajax表单提交

MySQL 81MySQL 82

def login(request):
    return render(request,'login.html')

def ajax_login(request):
    import json
    ret = {'status': True,'msg': None}
    obj = LoginForm(request.POST)
    if obj.is_valid():
        print(obj.cleaned_data)
    else:
        # print(obj.errors) # obj.errors对象
        ret['status'] = False
        ret['msg'] = obj.errors
    v = json.dumps(ret)
    return HttpResponse(v)

Ajax后端

MySQL 83MySQL 84

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>用户登录</h1>
    <form id="f1" action="/login/" method="POST">
        {% csrf_token %}
        <p>
            <input type="text" name="user" />{{ obj.errors.user.0 }}
        </p>
        <p>
            <input type="password" name="pwd" />{{ obj.errors.pwd.0 }}
        </p>
        <a onclick="submitForm();">提交</a>
    </form>
    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        function submitForm(){
            $('.c1').remove();//每次都清空之前提示
            $.ajax({
                url: '/ajax_login/',
                type: 'POST',
                data: $('#f1').serialize(),// user=alex&pwd=456&csrftoen=dfdf\把整个表单都扔到后台
                dataType:"JSON",
                success:function(arg){
                    console.log(arg);
                    if(arg.status){

                    }else{
                        $.each(arg.msg,function(index,value){//index就是user或pwd
                            console.log(index,value);
                            var tag = document.createElement('span');
                            tag.innerHTML = value[0];
                            tag.className = 'c1';
                            $('#f1').find('input[name="'+ index +'"]').after(tag);
                        })
                    }
                }
            })
        }
    </script>
</body>
</html>

Ajax前端form

   Ajax提交时不会活动刷新页面,所以能够保留上次提交的新闻,所以那种办法是三个科学的选项。

   form表单使用(学生数据表操作)

  obj.cleaned_data取出来的值是字典,所以表单提交成功能够平昔写到数据库中:

models.Classes.objects.create(**obj.cleaned_data)

  ClassForm进行实例化的时候里面传的参数应当为字典类型(request.POST实质上也是字典),所以为了让编辑时能在页面取到编辑的班级,所以率先步要求传进点击的班级的id号,在数据库中取出她的课程名:

方法一:手动取obj中参数
row = models.Classes.objects.filter(id=nid).first()
obj = ClassForm(initial={'title': row.title})#只能传入字典,首次不校验
obj = ClassForm(initial=row)
方法二:直接生成字典传进去
row = models.Classes.objects.filter(id=nid).values('title').first()
obj = ClassForm(initial=row)

  添加学生列表须求将课程呈现为select下拉框,要用插件widgets实现。

cls_id = fields.IntegerField(
# widget=widgets.Select(choices=[(1,'上海'),(2,'北京')])
widget=widgets.Select(choices=models.Classes.objects.values_list('id','title')))

  choice传入的值是列表中套元组的款型,显示title,传递的value是id的值。

   form表单select框

xx=fields.CharField(widget=widgets.Select(choices=models.Classes.objects.values_list('id','title'),attrs={'multiple':'multiple'}))

  此处的select虽然给了multiple的参数,但是接收时相当与get而不是getlist,所以这种方式只适合传单个参数。
  如何满足可以在页面上显示下拉框还可以传递多个参数呢。  

MySQL 85MySQL 86

    cls_id = fields.IntegerField(
        # widget=widgets.Select(choices=[(1,'上海'),(2,'北京')])
        widget=widgets.Select(choices=models.Classes.objects.values_list('id','title'),attrs={'class': 'form-control'})
    )

    cls_id = fields.ChoiceField(
        choices=models.Classes.objects.values_list('id','title'),
        widget=widgets.Select(attrs={'class': 'form-control'})
    )

select单选框

MySQL 87MySQL 88

xx = fields.MultipleChoiceField(
    choices=models.Classes.objects.values_list('id','title'),
    widget=widgets.SelectMultiple
)

obj = FooForm({'cls_id':[1,2,3]})

select多选框

MySQL 89MySQL 90

# class TestForm(Form):
#     t1 = fields.CharField(
#         widget=widgets.Textarea(attrs={})
#     )
#
#
#     t2 = fields.CharField(
#         widget=widgets.CheckboxInput
#     )
#
#     t3 = fields.MultipleChoiceField(
#         choices=[(1,'篮球'),(2,'足球'),(3,'溜溜球')],
#         widget=widgets.CheckboxSelectMultiple
#     )
#
#     t4 = fields.ChoiceField(
#         choices=[(1,'篮球'),(2,'足球'),(3,'溜溜球')],
#         widget=widgets.RadioSelect
#     )

    # t5 = fields.FileField(
    #     widget=widgets.FileInput
    # )

扭转各个input标签

   is_valid进行验证时发生了何等事?

  跟着源码来一探究竟:

    def is_valid(self):
        return self.is_bound and not self.errors

  那里的self是我们实例化的form对象,self.is_bound的true与false决定了数额是不是表明(data与initials)。

MySQL 91MySQL 92

    def full_clean(self):
        self._errors = ErrorDict()
        if not self.is_bound:  
            return
        self.cleaned_data = {}
        if self.empty_permitted and not self.has_changed():
            return

        self._clean_fields()#hasattr(self, 'clean_%s' % name)
#执行循环第一个字段先匹配正则,成功执行clean_字段函数(扩展高级功能)
        self._clean_form()#扩展功能
        self._post_clean()#还是扩展功能

forms.py

MySQL 93MySQL 94

from django.core.exceptions import ValidationError
class TestForm(Form):
    user = fields.CharField(validators=[])
    pwd = fields.CharField()

    def clean_user(self):
        v = self.cleaned_data['user']
        if models.Student.objects.filter(name=v).count():#找一下数据库是否已经有这个值了
            raise ValidationError('用户名已经存在')
        return self.cleaned_data['user']

    def clean_pwd(self):
        return self.cleaned_data['pwd']

    def clean(self):
        # user = self.cleaned_data.get('user')
        # email = self.cleaned_data.get('email')
        # if models.Student.objects.filter(user=user,email=email).count():
        #     raise ValidationError('用户名和邮箱联合已经存在')
        return self.cleaned_data

    # def _post_clean(self):#还是用于扩展
    #     """
    #     An internal hook for performing additional cleaning after form cleaning
    #     is complete. Used for model validation in model forms.
    #     """
    #     pass
def test(request):
    obj = TestForm(initial={'t3':[2,3]})
    obj.is_valid()
    return render(request,'test.html',{'obj':obj})

自定义扩大

MySQL 95MySQL 96

class MyForm(Form):
    user = fields.CharField(
        validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
    )

额外本人写正则匹配

MySQL 97MySQL 98

class testform(Form):
    tes=fields.FileField(
        widget=widgets.FileInput
    )

def test(request):
    if request.method=='GET':
        obj=testform()
        return render(request,'test.html',{'obj':obj})
    else:
        import os
        obj = testform(request.POST)
        print(request.FILES.get('tes'))#文件对象
        print(request.FILES.get('tes').name)#文件对象
        print(request.FILES.get('tes').size)#文件对象
        f=open(os.path.join('static',request.FILES.get('tes').name),'wb')
        all=request.FILES.get('tes').chunks()#拿到整个文件
        for trunk in all:
            f.write(trunk)
        f.close()
        return render(request, 'test.html',{'obj':obj})

上传文件

MySQL 99MySQL 100

def test(request):
    if request.method=='GET':
        obj=testform()
        return render(request,'test.html',{'obj':obj})
    else:
        import os
        obj = testform(data=request.POST,files=request.FILES)
        if obj.is_valid():
            print(obj.cleaned_data.get('tes').name)
            print(obj.cleaned_data.get('tes').size)
        f=open(os.path.join('static',obj.cleaned_data.get('tes').name),'wb')
        all=obj.cleaned_data.get('tes').chunks()#拿到整个文件
        for trunk in all:
            f.write(trunk)
        f.close()
        return render(request, 'test.html',{'obj':obj})

form表单上传文件

   上传文件供给前端form中势必要有三个attr:

<form method="POST" enctype="multipart/form-data">

  没有enctype=”multipart/form-data”,后台不也许接受到前端传回到的文本对象。

MySQL,变化随机验证码

  Python生成随机验证码,要求利用PIL模块。

MySQL 101MySQL 102

pip3 install pillow
#创建图片
from PIL import Image
img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))

# 在图片查看器中打开
# img.show() 

# 保存在本地
with open('code.png','wb') as f:
    img.save(f,format='png')
#创建画笔,用于在图片上画任意内容
img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
draw = ImageDraw.Draw(img, mode='RGB')
#画点
img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
draw = ImageDraw.Draw(img, mode='RGB')
# 第一个参数:表示坐标
# 第二个参数:表示颜色
draw.point([100, 100], fill="red")
draw.point([300, 300], fill=(255, 255, 255))
#画线
img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
draw = ImageDraw.Draw(img, mode='RGB')
# 第一个参数:表示起始坐标和结束坐标
# 第二个参数:表示颜色
draw.line((100,100,100,300), fill='red')
draw.line((100,100,300,100), fill=(255, 255, 255))
#画圆
img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
draw = ImageDraw.Draw(img, mode='RGB')
# 第一个参数:表示起始坐标和结束坐标(圆要画在其中间)
# 第二个参数:表示开始角度
# 第三个参数:表示结束角度
# 第四个参数:表示颜色
draw.arc((100,100,300,300),0,90,fill="red")
#写文本
img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
draw = ImageDraw.Draw(img, mode='RGB')
# 第一个参数:表示起始坐标
# 第二个参数:表示写入内容
# 第三个参数:表示颜色
draw.text([0,0],'python',"red")
#特殊字体文字
img = Image.new(mode='RGB', size=(120, 30), color=(255, 255, 255))
draw = ImageDraw.Draw(img, mode='RGB')
# 第一个参数:表示字体文件路径
# 第二个参数:表示字体大小
font = ImageFont.truetype("kumo.ttf", 28)
# 第一个参数:表示起始坐标
# 第二个参数:表示写入内容
# 第三个参数:表示颜色
# 第四个参数:表示颜色
draw.text([0, 0], 'python', "red", font=font)

PIL的基本操作

MySQL 103MySQL 104

import random

def check_code(width=120, height=30, char_length=5, font_file='kumo.ttf', font_size=28):
    code = []
    img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
    draw = ImageDraw.Draw(img, mode='RGB')

    def rndChar():
        """
        生成随机字母   
        :return:
        """
        return chr(random.randint(65, 90))

    def rndColor():
        """
        生成随机颜色
        :return:
        """
        return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))

    # 写文字
    font = ImageFont.truetype(font_file, font_size)
    for i in range(char_length):
        char = rndChar()
        code.append(char)
        h = random.randint(0, 4)
        draw.text([i * width / char_length, h], char, font=font, fill=rndColor())

    # 写干扰点
    for i in range(40):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())

    # 写干扰圆圈
    for i in range(40):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
        x = random.randint(0, width)
        y = random.randint(0, height)
        draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())

    # 画干扰线
    for i in range(5):
        x1 = random.randint(0, width)
        y1 = random.randint(0, height)
        x2 = random.randint(0, width)
        y2 = random.randint(0, height)

        draw.line((x1, y1, x2, y2), fill=rndColor())

    img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
    return img,''.join(code)


if __name__ == '__main__':
    # 1. 直接打开
    # img,code = check_code()
    # img.show()

    # 2. 写入文件
    # img,code = check_code()
    # with open('code.png','wb') as f:
    #     img.save(f,format='png')

    # 3. 写入内存(Python3)
    # from io import BytesIO
    # stream = BytesIO()
    # img.save(stream, 'png')
    # stream.getvalue()

    # 4. 写入内存(Python2)
    # import StringIO
    # stream = StringIO.StringIO()
    # img.save(stream, 'png')
    # stream.getvalue()
    pass

图片验证码

 

网站地图xml地图