Django框架【进阶篇】

第十九章   Django进阶

 

到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞:

  • 创建数据库,设计表结构和字段
  • 使用 MySQLdb 来连接数据库,并编写数据访问层代码
  • 业务逻辑层去调用数据访问层执行数据库操作
import MySQLdb
 
def GetList(sql):
    db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost')
    cursor = db.cursor()
    cursor.execute(sql)
    data = cursor.fetchall()
    db.close()
    return data
 
def GetSingle(sql):
    db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost')
    cursor = db.cursor()
    cursor.execute(sql)
    data = cursor.fetchone()
    db.close()
    return data

django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM)。

  PHP:activerecord

  Java:Hibernate 

    C#:Entity Framework

django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。

一、创建表

1、基本结构

1 from django.db import models
2    
3 class userinfo(models.Model):
4     name = models.CharField(max_length=30)
5     email = models.EmailField()
6     memo = models.TextField()
 1 1、models.AutoField  自增列 = int(11)
 2   如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。
 3 2、models.CharField  字符串字段
 4   必须 max_length 参数
 5 3、models.BooleanField  布尔类型=tinyint(1)
 6   不能为空,Blank=True
 7 4、models.ComaSeparatedIntegerField  用逗号分割的数字=varchar
 8   继承CharField,所以必须 max_lenght 参数
 9 5、models.DateField  日期类型 date
10   对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
11 6、models.DateTimeField  日期类型 datetime
12   同DateField的参数
13 7、models.Decimal  十进制小数类型 = decimal
14   必须指定整数位max_digits和小数位decimal_places
15 8、models.EmailField  字符串类型(正则表达式邮箱) =varchar
16   对字符串进行正则表达式
17 9、models.FloatField  浮点类型 = double
18 10、models.IntegerField  整形
19 11、models.BigIntegerField  长整形
20   integer_field_ranges = {
21     'SmallIntegerField': (-32768, 32767),
22     'IntegerField': (-2147483648, 2147483647),
23     'BigIntegerField': (-9223372036854775808, 9223372036854775807),
24     'PositiveSmallIntegerField': (0, 32767),
25     'PositiveIntegerField': (0, 2147483647),
26   }
27 12、models.IPAddressField  字符串类型(ip4正则表达式)
28 13、models.GenericIPAddressField  字符串类型(ip4和ip6是可选的)
29   参数protocol可以是:both、ipv4、ipv6
30   验证时,会根据设置报错
31 14、models.NullBooleanField  允许为空的布尔类型
32 15、models.PositiveIntegerFiel  正Integer
33 16、models.PositiveSmallIntegerField  正smallInteger
34 17、models.SlugField  减号、下划线、字母、数字
35 18、models.SmallIntegerField  数字
36   数据库中的字段有:tinyint、smallint、int、bigint
37 19、models.TextField  字符串=longtext
38 20、models.TimeField  时间 HH:MM[:ss[.uuuuuu]]
39 21、models.URLField  字符串,地址正则表达式
40 22、models.BinaryField  二进制
41 23、models.ImageField   图片
42 24、models.FilePathField 文件
View Code

2、连表结构

  • 一对多:models.ForeignKey(其他表)
  • 多对多:models.ManyToManyField(其他表)
  • 一对一:models.OneToOneField(其他表)

应用场景:

  • 一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
    例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。
  • 多对多:在某表中创建一行数据是,有一个可以多选的下拉框
    例如:创建用户信息,需要为用户指定多个爱好
  • 一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了
    例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据

二、操作表

1、基本操作

 1  2     #
 3     # models.Tb1.objects.create(c1='xx', c2='oo')  增加一条数据,可以接受字典类型数据 **kwargs
 4 
 5     # obj = models.Tb1(c1='xx', c2='oo')
 6     # obj.save()
 7 
 8     #
 9     #
10     # models.Tb1.objects.get(id=123)         # 获取单条数据,不存在则报错(不建议)
11     # models.Tb1.objects.all()               # 获取全部
12     # models.Tb1.objects.filter(name='seven') # 获取指定条件的数据
13 
14     #
15     #
16     # models.Tb1.objects.filter(name='seven').delete() # 删除指定条件的数据
17 
18     #
19     # models.Tb1.objects.filter(name='seven').update(gender='0')  # 将指定条件的数据更新,均支持 **kwargs
20     # obj = models.Tb1.objects.get(id=1)
21     # obj.c1 = '111'
22     # obj.save()                                                 # 修改单条数据
View Code

2、进阶操作(了不起的双下划线)

利用双下划线将字段和对应的操作连接起来

 1 # 获取个数
 2     #
 3     # models.Tb1.objects.filter(name='seven').count()
 4 
 5     # 大于,小于
 6     #
 7     # models.Tb1.objects.filter(id__gt=1)              # 获取id大于1的值
 8     # models.Tb1.objects.filter(id__lt=10)             # 获取id小于10的值
 9     # models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值
10 
11     # in
12     #
13     # models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
14     # models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
15 
16     # contains
17     #
18     # models.Tb1.objects.filter(name__contains="ven")
19     # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
20     # models.Tb1.objects.exclude(name__icontains="ven")
21 
22     # range
23     #
24     # models.Tb1.objects.filter(id__range=[1, 2])   # 范围bettwen and
25 
26     # 其他类似
27     #
28     # startswith,istartswith, endswith, iendswith,
29 
30     # order by
31     #
32     # models.Tb1.objects.filter(name='seven').order_by('id')    # asc
33     # models.Tb1.objects.filter(name='seven').order_by('-id')   # desc
34 
35     # limit 、offset
36     #
37     # models.Tb1.objects.all()[10:20]
38 
39     # group by
40     from django.db.models import Count, Min, Max, Sum
41     # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
42     # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
43 
44 进阶操作

3、连表操作(了不起的双下划线)

利用双下划线和 _set 将表之间的操作连接起来

class UserProfile(models.Model):
    user_info = models.OneToOneField('UserInfo')
    username = models.CharField(max_length=64)
    password = models.CharField(max_length=64)

    def __unicode__(self):
        return self.username


class UserInfo(models.Model):
    user_type_choice = (
        (0, u'普通用户'),
        (1, u'高级用户'),
    )
    user_type = models.IntegerField(choices=user_type_choice)
    name = models.CharField(max_length=32)
    email = models.CharField(max_length=32)
    address = models.CharField(max_length=128)

    def __unicode__(self):
        return self.name


class UserGroup(models.Model):

    caption = models.CharField(max_length=64)

    user_info = models.ManyToManyField('UserInfo')

    def __unicode__(self):
        return self.caption


class Host(models.Model):
    hostname = models.CharField(max_length=64)
    ip = models.GenericIPAddressField()
    user_group = models.ForeignKey('UserGroup')

    def __unicode__(self):
        return self.hostname

表结构实例
 1 user_info_obj = models.UserInfo.objects.filter(id=1).first()
 2 print user_info_obj.user_type
 3 print user_info_obj.get_user_type_display()
 4 print user_info_obj.userprofile.password
 5  
 6 user_info_obj = models.UserInfo.objects.filter(id=1).values('email', 'userprofile__username').first()
 7 print user_info_obj.keys()
 8 print user_info_obj.values()
 9 
10 一对一操作
一对一操作
一对多类似一对一
1、搜索条件使用 __ 连接
2、获取值时使用 .    连接
 1 user_info_obj = models.UserInfo.objects.get(name=u'武沛齐')
 2 user_info_objs = models.UserInfo.objects.all()
 3  
 4 group_obj = models.UserGroup.objects.get(caption='CEO')
 5 group_objs = models.UserGroup.objects.all()
 6  
 7 # 添加数据
 8 #group_obj.user_info.add(user_info_obj)
 9 #group_obj.user_info.add(*user_info_objs)
10  
11 # 删除数据
12 #group_obj.user_info.remove(user_info_obj)
13 #group_obj.user_info.remove(*user_info_objs)
14  
15 # 添加数据
16 #user_info_obj.usergroup_set.add(group_obj)
17 #user_info_obj.usergroup_set.add(*group_objs)
18  
19 # 删除数据
20 #user_info_obj.usergroup_set.remove(group_obj)
21 #user_info_obj.usergroup_set.remove(*group_objs)
22  
23 # 获取数据
24 #print group_obj.user_info.all()
25 #print group_obj.user_info.all().filter(id=1)
26  
27 # 获取数据
28 #print user_info_obj.usergroup_set.all()
29 #print user_info_obj.usergroup_set.all().filter(caption='CEO')
30 #print user_info_obj.usergroup_set.all().filter(caption='DBA')
31 
32 多对多操作
多对多操作

 1 # F 使用查询条件的值
 2     #
 3     # from django.db.models import F
 4     # models.Tb1.objects.update(num=F('num')+1)
 5 
 6     # Q 构建搜索条件
 7     from django.db.models import Q
 8     # con = Q()
 9     #
10     # q1 = Q()
11     # q1.connector = 'OR'
12     # q1.children.append(('id', 1))
13     # q1.children.append(('id', 10))
14     # q1.children.append(('id', 9))
15     #
16     # q2 = Q()
17     # q2.connector = 'OR'
18     # q2.children.append(('c1', 1))
19     # q2.children.append(('c1', 10))
20     # q2.children.append(('c1', 9))
21     #
22     # con.add(q1, 'AND')
23     # con.add(q2, 'AND')
24     #
25     # models.Tb1.objects.filter(con)
26 
27     #
28     # from django.db import connection
29     # cursor = connection.cursor()
30     # cursor.execute("""SELECT * from tb where name = %s""", ['Lennon'])
31     # row = cursor.fetchone()
32 
33 其他操作
其他操作

注意:xx_set中的【_set】是多对多中的固定搭配

扩展:

a、自定义上传

1 def upload_file(request):
2     if request.method == "POST":
3         obj = request.FILES.get('fafafa')
4         f = open(obj.name, 'wb')
5         for chunk in obj.chunks():
6             f.write(chunk)
7         f.close()
8     return render(request, 'file.html')

b、Form上传文件实例

class FileForm(forms.Form):
    ExcelFile = forms.FileField()

from django.db import models class UploadFile(models.Model): userid = models.CharField(max_length = 30) file = models.FileField(upload_to = './upload/') date = models.DateTimeField(auto_now_add=True)

复制代码
def UploadFile(request):
    uf = AssetForm.FileForm(request.POST,request.FILES)
    if uf.is_valid():
            upload = models.UploadFile()
            upload.userid = 1
            upload.file = uf.cleaned_data['ExcelFile']
            upload.save()
            
            print upload.file

django中的Form一般有两种功能:


  • 输入html
  • 验证用户输入
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import re
 4 from django import forms
 5 from django.core.exceptions import ValidationError
 6 
 7 
 8 def mobile_validate(value):
 9     mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
10     if not mobile_re.match(value):
11         raise ValidationError('手机号码格式错误')
12 
13 
14 class PublishForm(forms.Form):
15 
16     user_type_choice = (
17         (0, u'普通用户'),
18         (1, u'高级用户'),
19     )
20 
21     user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
22                                                                   attrs={'class': "form-control"}))
23 
24     title = forms.CharField(max_length=20,
25                             min_length=5,
26                             error_messages={'required': u'标题不能为空',
27                                             'min_length': u'标题最少为5个字符',
28                                             'max_length': u'标题最多为20个字符'},
29                             widget=forms.TextInput(attrs={'class': "form-control",
30                                                           'placeholder': u'标题5-20个字符'}))
31 
32     memo = forms.CharField(required=False,
33                            max_length=256,
34                            widget=forms.widgets.Textarea(attrs={'class': "form-control no-radius", 'placeholder': u'详细描述', 'rows': 3}))
35 
36     phone = forms.CharField(validators=[mobile_validate, ],
37                             error_messages={'required': u'手机不能为空'},
38                             widget=forms.TextInput(attrs={'class': "form-control",
39                                                           'placeholder': u'手机号码'}))
40 
41     email = forms.EmailField(required=False,
42                             error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
43                             widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))
44 
45 Form
View Code
def publish(request):
    ret = {'status': False, 'data': '', 'error': '', 'summary': ''}
    if request.method == 'POST':
        request_form = PublishForm(request.POST)
        if request_form.is_valid():
            request_dict = request_form.clean()
            print request_dict
            ret['status'] = True
        else:
            error_msg = request_form.errors.as_json()
            ret['error'] = json.loads(error_msg)
    return HttpResponse(json.dumps(ret))

View

扩展:ModelForm

在使用Model和Form时,都需要对字段进行定义并指定类型,通过ModelForm则可以省去From中字段的定义

 1 class AdminModelForm(forms.ModelForm):
 2       
 3     class Meta:
 4         model = models.Admin
 5         #fields = '__all__'
 6         fields = ('username', 'email')
 7           
 8         widgets = {
 9             'email' : forms.PasswordInput(attrs={'class':"alex"}),
10         }

 

笔记:
1、Django请求生命周期
        -> URL对应关系(匹配) -> 视图函数 -> 返回用户字符串
        -> URL对应关系(匹配) -> 视图函数 -> 打开一个HTML文件,读取内容
        
    2、创建django projcet

        django-admin startproject mysite
        

        ..
        
        mysite
            mysite
                - 配置文件
                - url.py
                - settings.py
            
        cd mysite
        python manage.py startapp cmdb
        
        mysite
            mysite
                - 配置文件
                - url.py
                - settings.py
            cmdb
                - views.py
                - admin.py
                - models.py # 创建数据库表

    3、配置
        
        模板路径
        静态文件路径
        # CSRF
        
    4、编写程序

        a. url.py
            
            /index/    ->   func
            
        b. views.py
            
            def func(request):
                # 包含所有的请求数据
                ...
                return HttpResponse('字符串')
                return render(request, 'index.html', {''})
                retrun redirect('URL')
                
        c. 模板语言
            return render(request, 'index.html', {'li': [11,22,33]})
            
            {% for item in li %}
                <h1>{{item}}</h1>
            {% endfor %}
            
            
            ***********  索引用点 **********
            <h2> {{item.0 }} </h2>

一、路由系统,URL
    1、url(r'^index/', views.index),    
       url(r'^home/', views.Home.as_view()),
    2、url(r'^detail-(\d+).html', views.detail),  
    3、url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail)
       
       PS:
            def detail(request, *args,**kwargs):
                pass
    
       实战:
            a.
                url(r'^detail-(\d+)-(\d+).html', views.detail),
                
                def func(request, nid, uid):
                    
                    pass
            
                def func(request, *args):
                    args = (2,9)
                    
                    
                def func(request, *args, **kwargs):
                    args = (2,9)
       
            b.
                url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail)
                
                def func(request, nid, uid):
                    pass
                    
                def funct(request, **kwargs):
                    kwargs = {'nid': 1, 'uid': 3}
                    
                def func(request, *args, **kwargs):
                    args = (2,9)
    4、 name
        
        对URL路由关系进行命名, ***** 以后可以根据此名称生成自己想要的URL *****
        
        url(r'^asdfasdfasdf/', views.index, name='i1'),
        url(r'^yug/(\d+)/(\d+)/', views.index, name='i2'),
        url(r'^buy/(?P<pid>\d+)/(?P<nid>\d+)/', views.index, name='i3'),
        
        
        
        def func(request, *args, **kwargs):
            from django.urls import reverse
            
            url1 = reverse('i1')                              # asdfasdfasdf/
            url2 = reverse('i2', args=(1,2,))                 # yug/1/2/
            url3 = reverse('i3', kwargs={'pid': 1, "nid": 9}) # buy/1/9/
        
        
        xxx.html
            
            {% url "i1" %}               # asdfasdfasdf/
            {% url "i2" 1 2 %}           # yug/1/2/
            {% url "i3" pid=1 nid=9 %}   # buy/1/9/
        
        注:
            # 当前的URL
            request.path_info
    5、多级路由
        
        project/urls.py
            from django.conf.urls import url,include
            from django.contrib import admin

            urlpatterns = [
                url(r'^cmdb/', include("app01.urls")),
                url(r'^monitor/', include("app02.urls")),
            ]
            
        app01/urls.py
            from django.conf.urls import url,include
            from django.contrib import admin
            from app01 import views

            urlpatterns = [
                url(r'^login/', views.login),
            ]
            
        app02/urls.py
            from django.conf.urls import url,include
            from django.contrib import admin
            from app02 import views

            urlpatterns = [
                url(r'^login/', views.login),
            ]
    
    6、默认值(欠)
    
    7、命名空间(欠)
    
    
二、视图
    1、获取用户请求数据
        request.GET
        request.POST
        request.FILES
        PS:
            GET:获取数据                
            POST:提交数据
            
    2、checkbox等多选的内容
        request.POST.getlist()
    3、上传文件
        # 上传文件,form标签做特殊设置
        obj = request.FILES.get('fafafa')
        obj.name
        f = open(obj.name, mode='wb')
        for item in obj.chunks():
            f.write(item)
        f.close()
    
    4、FBV & CBV
       function base view
       
        url.py
            index -> 函数名
            
        view.py
            def 函数(request):
                ...
        ====》
        /index/ -> 函数名
            
        /index/ -> 类
        
        ====》
        
        建议:两者都用
        
    5、装饰器
        欠

    
三、模板
    
    

四、ORM操作
    select * from tb where id > 1
    # 对应关系
    models.tb.objects.filter(id__gt=1)
    models.tb.objects.filter(id=1)
    models.tb.objects.filter(id__lt=1)
    
    创建类
    
    a. 先写类
        from django.db import models

        # app01_userinfo
        class UserInfo(models.Model):
            # id列,自增,主键
            # 用户名列,字符串类型,指定长度
            username = models.CharField(max_length=32)
            password = models.CharField(max_length=64)
        
    b. 注册APP

        INSTALLED_APPS = [
            'django.contrib.admin',
            'django.contrib.auth',
            'django.contrib.contenttypes',
            'django.contrib.sessions',
            'django.contrib.messages',
            'django.contrib.staticfiles',
            'app01',
        ]
    c. 执行命令
        python manage.py  makemigrations
        python manage.py  migrate
        
    d. ********** 注意 ***********
        Django默认使用MySQLdb模块链接MySQL
        主动修改为pymysql,在project同名文件夹下的__init__文件中添加如下代码即可:
            import pymysql
            pymysql.install_as_MySQLdb()
    
    1. 根据类自动创建数据库表
        # app下的models.py
    
        python manage.py  makemigrations
        python manage.py  migrate
        
        
        字段:
            字符串类型
            
            
            数字
            
            
            时间
            
            
            二进制
            
            自增(primary_key=True)
            
        字段的参数:
            null               -> db是否可以为空
            default            -> 默认值
            primary_key        -> 主键
            db_column          -> 列名
            db_index           -> 索引
            unique               -> 唯一索引
            unique_for_date    ->
            unique_for_month
            unique_for_year
            auto_now           -> 创建时,自动生成时间
            auto_now_add       -> 更新时,自动更新为当前时间
            
                # obj = UserGroup.objects.filter(id=1).update(caption='CEO')
                # obj = UserGroup.objects.filter(id=1).first()
                # obj.caption = "CEO"
                # obj.save()
                
            choices              -> django admin中显示下拉框,避免连表查询
            blank             -> django admin是否可以为空
            verbose_name      -> django admin显示字段中文
            editable          -> django admin是否可以被编辑
            error_messages    -> 错误信息欠
            help_text         -> django admin提示
            validators          -> django form ,自定义错误信息(欠)
            
            
            创建 Django 用户:python manage.py createsuperuser
            
            
            
            
    2. 根据类对数据库表中的数据进行各种操作
    
        一对多:
        
            a. 外检
            b.
                外键字段_id
            c.
                models.tb.object.create(name='root', user_group_id=1)
                
            d.
                
                userlist = models.tb.object.all()
                for row in userlist:
                    row.id
                    row.user_group_id
                    row.user_group.caption

 
posted @ 2016-12-15 21:34  太傅  阅读(165)  评论(0编辑  收藏  举报