Python的WEB框架有Django、Tornado、Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM、模型绑定、模板引擎、缓存、Session等诸多功能。

 

基本配置

 

一、创建django程序

  • 终端命令:django-admin startproject sitename
  • IDE创建Django程序时,本质上都是自动执行上述命令

其他常用命令:

  python manage.py runserver 0.0.0.0  //运行服务
  python manage.py startapp appname  //创建app实例
  python manage.py syncdb      // 会创建在settings 下的INSTALL_APPS所有app,创建其对应的数据表到指定的数据库,但只创建 不存在的表
  python manage.py makemigrations  //在migrations文件夹创建对应的表数据,但没有在数据库中创建相应数据。
  python manage.py migrate      //将migrations文件夹创建的表数据迁移到数据库并创建相应字段等。

  python manage.py createsuperuser  //创建admin用户

 

配置数据库:

 

DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME':'dbname',
    'USER': 'root',
    'PASSWORD': 'xxx',
    'HOST': '',
    'PORT': '',
    }
}
 
模板:
TEMPLATE_DIRS = (
        os.path.join(BASE_DIR,'templates'),
    )
 
静态文件:
STATICFILES_DIRS = (
        os.path.join(BASE_DIR,'static'),
    )

 

路由系统

1、单一路由对应

  url(r'^index$', views.index),

 

2、基于正则的路由

  url(r'^index/(\d*)', views.index),
  url(r'^manage/(?P<name>\w*)/(?P<id>\d*)', views.manage),
 
3、添加额外的参数
  url(r'^manage/(?P<name>\w*)', views.manage,{'id':333}),
 
4、为路由映射设置名称
  url(r'^home', views.home, name='h1'),
  url(r'^index/(\d*)', views.index, name='h2'),
 
5、根据app对路由规则进行分类
  url(r'^web/',include('web.urls')),
 
6、命名空间
  a. project.urls.py    
    from django.conf.urls import url,include
 
    urlpatterns = [
        url(r'^a/', include('app01.urls', namespace='author-polls')),
        url(r'^b/', include('app01.urls', namespace='publisher-polls')),
    ]
b. app01.urls.py
  from django.conf.urls import url
  from app01 import views
 
  app_name = 'app01'
  urlpatterns = [
      url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
  ]
 
c. app01.views.py
  def detail(request, pk):
    print(request.resolver_match)
    return HttpResponse(pk)
 

以上定义带命名空间的url之后,使用name生成URL时候,应该如下:

  • v = reverse('app01:detail', kwargs={'pk':11})
  • {% url 'app01:detail' pk=12 pp=99 %}

django中的路由系统和其他语言的框架有所不同,在django中每一个请求的url都要有一条路由映射,这样才能将请求交给对一个的view中的函数去处理。其他大部分的Web框架则是对一类的url请求做一条路由映射,从而是路由系统变得简洁。

自定义simple_tag

a、在app中创建templatetags模块

b、创建任意 .py 文件,如:xx.py

 1 #!/usr/bin/env python
 2 #coding:utf-8
 3 from django import template
 4 from django.utils.safestring import mark_safe
 5    
 6 register = template.Library()
 7    
 8 @register.simple_tag
 9 def my_simple_time(v1,v2,v3):
10     return  v1 + v2 + v3
11    
12 @register.simple_tag
13 def my_input(id,arg):
14     result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
15     return mark_safe(result)
View Code

c、在使用自定义simple_tag的html文件中导入之前创建的 xx.py 文件名

  {% load xx %}
d、使用simple_tag
  {% my_simple_time 1 2 3%}
  {% my_input 'id_username' 'hide'%}
 
e、在settings中配置当前app,不然django无法找到自定义的simple_tag
 

中间件

django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。

在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下图。

与mange.py在同一目录下的文件夹 wupeiqi/middleware下的auth.py文件中的Authentication类

中间件中可以定义四个方法,分别是:

  • process_request(self,request)
  • process_view(self, request, callback, callback_args, callback_kwargs)
  • process_template_response(self,request,response)
  • process_exception(self, request, exception)
  • process_response(self, request, response)

以上方法的返回值可以是None和HttpResonse对象,如果是None,则继续按照django定义的规则向下执行,如果是HttpResonse对象,则直接将该对象返回给用户。

自定义中间件

1、创建中间件类

class RequestExeute(object):
      
    def process_request(self,request):
        pass
    def process_view(self, request, callback, callback_args, callback_kwargs):
        i =1
        pass
    def process_exception(self, request, exception):
        pass
      
    def process_response(self, request, response):
        return response
2、注册中间件
MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'wupeiqi.middleware.auth.RequestExeute',
)
 

admin

  • 配置url
  • 注册和配置django admin后台管理页面

1、创建后台管理员

1
python manage.py createsuperuser

2、配置后台管理url

1
url(r'^admin/', include(admin.site.urls))

3、注册和配置django admin 后台管理页面

a、在admin中执行如下配置

 

from django.contrib import admin
  
from app01 import  models
  
admin.site.register(models.UserType)
admin.site.register(models.UserInfo)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
 
b、设置数据表名称
class UserType(models.Model):
    name = models.CharField(max_length=50)
  
    class Meta:
        verbose_name = '用户类型'
        verbose_name_plural = '用户类型'
 
c、打开表之后,设定默认显示,需要在model中作如下配置
class UserType(models.Model):
    name = models.CharField(max_length=50)
  
    def __unicode__(self):
        return self.name
 
---------------
from django.contrib import admin
  
from app01 import  models
  
class UserInfoAdmin(admin.ModelAdmin):
    list_display = ('username', 'password', 'email')
  
  
admin.site.register(models.UserType)
admin.site.register(models.UserInfo,UserInfoAdmin)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
 
d、为数据表添加搜索功能  
 1 from django.contrib import admin
 2   
 3 from app01 import  models
 4   
 5 class UserInfoAdmin(admin.ModelAdmin):
 6     list_display = ('username', 'password', 'email')
 7     search_fields = ('username', 'email')
 8   
 9 admin.site.register(models.UserType)
10 admin.site.register(models.UserInfo,UserInfoAdmin)
11 admin.site.register(models.UserGroup)
12 admin.site.register(models.Asset)
View Code

e、添加快速过滤

 1 from django.contrib import admin
 2   
 3 from app01 import  models
 4   
 5 class UserInfoAdmin(admin.ModelAdmin):
 6     list_display = ('username', 'password', 'email')
 7     search_fields = ('username', 'email')
 8     list_filter = ('username', 'email')
 9       
10   
11   
12 admin.site.register(models.UserType)
13 admin.site.register(models.UserInfo,UserInfoAdmin)
14 admin.site.register(models.UserGroup)
15 admin.site.register(models.Asset)
View Code

 

 

Model

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

  • 创建数据库,设计表结构和字段
  • 使用 MySQLdb 来连接数据库,并编写数据访问层代码
  • 业务逻辑层去调用数据访问层执行数据库操作
  •  1 import MySQLdb
     2  
     3 def GetList(sql):
     4     db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost')
     5     cursor = db.cursor()
     6     cursor.execute(sql)
     7     data = cursor.fetchall()
     8     db.close()
     9     return data
    10  
    11 def GetSingle(sql):
    12     db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost')
    13     cursor = db.cursor()
    14     cursor.execute(sql)
    15     data = cursor.fetchone()
    16     db.close()
    17     return data
    View Code

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 AutoField(Field)
  2         - int自增列,必须填入参数 primary_key=True
  3 
  4     BigAutoField(AutoField)
  5         - bigint自增列,必须填入参数 primary_key=True
  6 
  7         注:当model中如果没有自增列,则自动会创建一个列名为id的列
  8         from django.db import models
  9 
 10         class UserInfo(models.Model):
 11             # 自动创建一个列名为id的且为自增的整数列
 12             username = models.CharField(max_length=32)
 13 
 14         class Group(models.Model):
 15             # 自定义自增列
 16             nid = models.AutoField(primary_key=True)
 17             name = models.CharField(max_length=32)
 18 
 19     SmallIntegerField(IntegerField):
 20         - 小整数 -32768 ~ 32767
 21 
 22     PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
 23         - 正小整数 0 ~ 32767
 24     IntegerField(Field)
 25         - 整数列(有符号的) -2147483648 ~ 2147483647
 26 
 27     PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
 28         - 正整数 0 ~ 2147483647
 29 
 30     BigIntegerField(IntegerField):
 31         - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
 32 
 33     自定义无符号整数字段
 34 
 35         class UnsignedIntegerField(models.IntegerField):
 36             def db_type(self, connection):
 37                 return 'integer UNSIGNED'
 38 
 39         PS: 返回值为字段在数据库中的属性,Django字段默认的值为:
 40             'AutoField': 'integer AUTO_INCREMENT',
 41             'BigAutoField': 'bigint AUTO_INCREMENT',
 42             'BinaryField': 'longblob',
 43             'BooleanField': 'bool',
 44             'CharField': 'varchar(%(max_length)s)',
 45             'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
 46             'DateField': 'date',
 47             'DateTimeField': 'datetime',
 48             'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
 49             'DurationField': 'bigint',
 50             'FileField': 'varchar(%(max_length)s)',
 51             'FilePathField': 'varchar(%(max_length)s)',
 52             'FloatField': 'double precision',
 53             'IntegerField': 'integer',
 54             'BigIntegerField': 'bigint',
 55             'IPAddressField': 'char(15)',
 56             'GenericIPAddressField': 'char(39)',
 57             'NullBooleanField': 'bool',
 58             'OneToOneField': 'integer',
 59             'PositiveIntegerField': 'integer UNSIGNED',
 60             'PositiveSmallIntegerField': 'smallint UNSIGNED',
 61             'SlugField': 'varchar(%(max_length)s)',
 62             'SmallIntegerField': 'smallint',
 63             'TextField': 'longtext',
 64             'TimeField': 'time',
 65             'UUIDField': 'char(32)',
 66 
 67     BooleanField(Field)
 68         - 布尔值类型
 69 
 70     NullBooleanField(Field):
 71         - 可以为空的布尔值
 72 
 73     CharField(Field)
 74         - 字符类型
 75         - 必须提供max_length参数, max_length表示字符长度
 76 
 77     TextField(Field)
 78         - 文本类型
 79 
 80     EmailField(CharField):
 81         - 字符串类型,Django Admin以及ModelForm中提供验证机制
 82 
 83     IPAddressField(Field)
 84         - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
 85 
 86     GenericIPAddressField(Field)
 87         - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
 88         - 参数:
 89             protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
 90             unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"
 91 
 92     URLField(CharField)
 93         - 字符串类型,Django Admin以及ModelForm中提供验证 URL
 94 
 95     SlugField(CharField)
 96         - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
 97 
 98     CommaSeparatedIntegerField(CharField)
 99         - 字符串类型,格式必须为逗号分割的数字
100 
101     UUIDField(Field)
102         - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
103 
104     FilePathField(Field)
105         - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
106         - 参数:
107                 path,                      文件夹路径
108                 match=None,                正则匹配
109                 recursive=False,           递归下面的文件夹
110                 allow_files=True,          允许文件
111                 allow_folders=False,       允许文件夹
112 
113     FileField(Field)
114         - 字符串,路径保存在数据库,文件上传到指定目录
115         - 参数:
116             upload_to = ""      上传文件的保存路径
117             storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
118 
119     ImageField(FileField)
120         - 字符串,路径保存在数据库,文件上传到指定目录
121         - 参数:
122             upload_to = ""      上传文件的保存路径
123             storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
124             width_field=None,   上传图片的高度保存的数据库字段名(字符串)
125             height_field=None   上传图片的宽度保存的数据库字段名(字符串)
126 
127     DateTimeField(DateField)
128         - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
129 
130     DateField(DateTimeCheckMixin, Field)
131         - 日期格式      YYYY-MM-DD
132 
133     TimeField(DateTimeCheckMixin, Field)
134         - 时间格式      HH:MM[:ss[.uuuuuu]]
135 
136     DurationField(Field)
137         - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
138 
139     FloatField(Field)
140         - 浮点型
141 
142     DecimalField(Field)
143         - 10进制小数
144         - 参数:
145             max_digits,小数总长度
146             decimal_places,小数位长度
147 
148     BinaryField(Field)
149         - 二进制类型
150 
151 字段
字段
 1 null                数据库中字段是否可以为空
 2     db_column           数据库中字段的列名
 3     db_tablespace
 4     default             数据库中字段的默认值
 5     primary_key         数据库中字段是否为主键
 6     db_index            数据库中字段是否可以建立索引
 7     unique              数据库中字段是否可以建立唯一索引
 8     unique_for_date     数据库中字段【日期】部分是否可以建立唯一索引
 9     unique_for_month    数据库中字段【月】部分是否可以建立唯一索引
10     unique_for_year     数据库中字段【年】部分是否可以建立唯一索引
11 
12     verbose_name        Admin中显示的字段名称
13     blank               Admin中是否允许用户输入为空
14     editable            Admin中是否可以编辑
15     help_text           Admin中该字段的提示信息
16     choices             Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
17                         如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
18 
19     error_messages      自定义错误信息(字典类型),从而定制想要显示的错误信息;
20                         字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
21                         如:{'null': "不能为空.", 'invalid': '格式错误'}
22 
23     validators          自定义错误验证(列表类型),从而定制想要的验证规则
24                         from django.core.validators import RegexValidator
25                         from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
26                         MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
27                         如:
28                             test = models.CharField(
29                                 max_length=32,
30                                 error_messages={
31                                     'c1': '优先错信息1',
32                                     'c2': '优先错信息2',
33                                     'c3': '优先错信息3',
34                                 },
35                                 validators=[
36                                     RegexValidator(regex='root_\d+', message='错误了', code='c1'),
37                                     RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
38                                     EmailValidator(message='又错误了', code='c3'), ]
39                             )
40 
41 参数
参数
 1 class UserInfo(models.Model):
 2         nid = models.AutoField(primary_key=True)
 3         username = models.CharField(max_length=32)
 4         class Meta:
 5             # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
 6             db_table = "table_name"
 7 
 8             # 联合索引
 9             index_together = [
10                 ("pub_date", "deadline"),
11             ]
12 
13             # 联合唯一索引
14             unique_together = (("driver", "restaurant"),)
15 
16             # admin中显示的表名称
17             verbose_name
18 
19             # verbose_name加s
20             verbose_name_plural
21         
22     更多:https://docs.djangoproject.com/en/1.10/ref/models/options/
23 
24 元信息
元信息
 1 1.触发Model中的验证和错误提示有两种方式:
 2         a. Django Admin中的错误信息会优先根据Admiin内部的ModelForm错误信息提示,如果都成功,才来检查Model的字段并显示指定错误信息
 3         b. 调用Model对象的 clean_fields 方法,如:
 4             # models.py
 5             class UserInfo(models.Model):
 6                 nid = models.AutoField(primary_key=True)
 7                 username = models.CharField(max_length=32)
 8 
 9                 email = models.EmailField(error_messages={'invalid': '格式错了.'})
10 
11             # views.py
12             def index(request):
13                 obj = models.UserInfo(username='11234', email='uu')
14                 try:
15                     print(obj.clean_fields())
16                 except Exception as e:
17                     print(e)
18                 return HttpResponse('ok')
19 
20            # Model的clean方法是一个钩子,可用于定制操作,如:上述的异常处理。
21 
22     2.Admin中修改错误提示
23         # admin.py
24         from django.contrib import admin
25         from model_club import models
26         from django import forms
27 
28 
29         class UserInfoForm(forms.ModelForm):
30             username = forms.CharField(error_messages={'required': '用户名不能为空.'})
31             email = forms.EmailField(error_messages={'invalid': '邮箱格式错误.'})
32             age = forms.IntegerField(initial=1, error_messages={'required': '请输入数值.', 'invalid': '年龄必须为数值.'})
33 
34             class Meta:
35                 model = models.UserInfo
36                 # fields = ('username',)
37                 fields = "__all__"
38 
39 
40         class UserInfoAdmin(admin.ModelAdmin):
41             form = UserInfoForm
42 
43 
44         admin.site.register(models.UserInfo, UserInfoAdmin)
45 
46 拓展知识
拓展

 

表操作:

 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()                                                 # 修改单条数据
23 
24 基本操作
View Code

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

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

# 获取个数
        #
        # models.Tb1.objects.filter(name='seven').count()

        # 大于,小于
        #
        # models.Tb1.objects.filter(id__gt=1)              # 获取id大于1的值
        # models.Tb1.objects.filter(id__gte=1)              # 获取id大于等于1的值
        # models.Tb1.objects.filter(id__lt=10)             # 获取id小于10的值
        # models.Tb1.objects.filter(id__lte=10)             # 获取id小于10的值
        # models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值

        # in
        #
        # models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
        # models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in

        # isnull
        # Entry.objects.filter(pub_date__isnull=True)

        # contains
        #
        # models.Tb1.objects.filter(name__contains="ven")
        # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
        # models.Tb1.objects.exclude(name__icontains="ven")

        # range
        #
        # models.Tb1.objects.filter(id__range=[1, 2])   # 范围bettwen and

        # 其他类似
        #
        # startswith,istartswith, endswith, iendswith,

        # order by
        #
        # models.Tb1.objects.filter(name='seven').order_by('id')    # asc
        # models.Tb1.objects.filter(name='seven').order_by('-id')   # desc

        # group by
        #
        # from django.db.models import Count, Min, Max, Sum
        # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
        # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"

        # limit 、offset
        #
        # models.Tb1.objects.all()[10:20]

        # regex正则匹配,iregex 不区分大小写
        #
        # Entry.objects.get(title__regex=r'^(An?|The) +')
        # Entry.objects.get(title__iregex=r'^(an?|the) +')

        # date
        #
        # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
        # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

        # year
        #
        # Entry.objects.filter(pub_date__year=2005)
        # Entry.objects.filter(pub_date__year__gte=2005)

        # month
        #
        # Entry.objects.filter(pub_date__month=12)
        # Entry.objects.filter(pub_date__month__gte=6)

        # day
        #
        # Entry.objects.filter(pub_date__day=3)
        # Entry.objects.filter(pub_date__day__gte=3)

        # week_day
        #
        # Entry.objects.filter(pub_date__week_day=2)
        # Entry.objects.filter(pub_date__week_day__gte=2)

        # hour
        #
        # Event.objects.filter(timestamp__hour=23)
        # Event.objects.filter(time__hour=5)
        # Event.objects.filter(timestamp__hour__gte=12)

        # minute
        #
        # Event.objects.filter(timestamp__minute=29)
        # Event.objects.filter(time__minute=46)
        # Event.objects.filter(timestamp__minute__gte=29)

        # second
        #
        # Event.objects.filter(timestamp__second=31)
        # Event.objects.filter(time__second=2)
        # Event.objects.filter(timestamp__second__gte=31)

进阶操作
View Code

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

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

 1 class UserProfile(models.Model):
 2     user_info = models.OneToOneField('UserInfo')
 3     username = models.CharField(max_length=64)
 4     password = models.CharField(max_length=64)
 5 
 6     def __unicode__(self):
 7         return self.username
 8 
 9 
10 class UserInfo(models.Model):
11     user_type_choice = (
12         (0, u'普通用户'),
13         (1, u'高级用户'),
14     )
15     user_type = models.IntegerField(choices=user_type_choice)
16     name = models.CharField(max_length=32)
17     email = models.CharField(max_length=32)
18     address = models.CharField(max_length=128)
19 
20     def __unicode__(self):
21         return self.name
22 
23 
24 class UserGroup(models.Model):
25 
26     caption = models.CharField(max_length=64)
27 
28     user_info = models.ManyToManyField('UserInfo')
29 
30     def __unicode__(self):
31         return self.caption
32 
33 
34 class Host(models.Model):
35     hostname = models.CharField(max_length=64)
36     ip = models.GenericIPAddressField()
37     user_group = models.ForeignKey('UserGroup')
38 
39     def __unicode__(self):
40         return self.hostname
41 
42 表结构实例
View Code

 

模型的常用字段类型以及参数:

  1 # AutoField
  2 # 一个 IntegerField, 添加记录时它会自动增长. 你通常不需要直接使用这个字段; 如果你不指定主键的话,系统会自动添加一个主键字段到你的 model.(参阅 _自动主键字段)
  3 # BooleanField
  4 # A true/false field. admin 用 checkbox 来表示此类字段.
  5 # CharField
  6 # 字符串字段, 用于较短的字符串.
  7 # 
  8 # 如果要保存大量文本, 使用 TextField.
  9 # 
 10 # admin 用一个 <input type="text"> 来表示此类字段 (单行输入).
 11 # 
 12 # CharField 要求必须有一个参数 maxlength, 用于从数据库层和Django校验层限制该字段所允许的最大字符数.
 13 # 
 14 # CommaSeparatedIntegerField
 15 # 用于存放逗号分隔的整数值. 类似 CharField, 必须要有 maxlength 参数.
 16 # DateField
 17 # 一个日期字段. 共有下列额外的可选参数:
 18 # 
 19 # Argument    描述
 20 # auto_now    当对象被保存时,自动将该字段的值设置为当前时间.通常用于表示 "last-modified" 时间戳.
 21 # auto_now_add    当对象首次被创建时,自动将该字段的值设置为当前时间.通常用于表示对象创建时间.
 22 # admin 用一个文本框 <input type="text"> 来表示该字段数据(附带一个 JavaScript 日历和一个"Today"快键.
 23 # 
 24 # DateTimeField
 25 #  一个日期时间字段. 类似 DateField 支持同样的附加选项.
 26 # admin 用两上文本框 <input type="text"> 表示该字段顺序(附带JavaScript shortcuts). 
 27 # 
 28 # EmailField
 29 # 一个带有检查 Email 合法性的 CharField,不接受 maxlength 参数.
 30 # FileField
 31 # 一个文件上传字段.
 32 # 
 33 # 要求一个必须有的参数: upload_to, 一个用于保存上载文件的本地文件系统路径. 这个路径必须包含 strftime formatting, 该格式将被上载文件的 date/time 替换(so that uploaded files don't fill up the given directory).
 34 # 
 35 # admin 用一个``<input type="file">``部件表示该字段保存的数据(一个文件上传部件) .
 36 # 
 37 # 在一个 model 中使用 FileField 或 ImageField 需要以下步骤:
 38 # 
 39 # 在你的 settings 文件中, 定义一个完整路径给 MEDIA_ROOT 以便让 Django在此处保存上传文件. (出于性能考虑,这些文件并不保存到数据库.) 定义 MEDIA_URL 作为该目录的公共 URL. 要确保该目录对 WEB 服务器用户帐号是可写的.
 40 # 在你的 model 中添加 FileField 或 ImageField, 并确保定义了 upload_to 选项,以告诉 Django 使用 MEDIA_ROOT 的哪个子目录保存上传文件.
 41 # 你的数据库中要保存的只是文件的路径(相对于 MEDIA_ROOT). 出于习惯你一定很想使用 Django 提供的 get_<fieldname>_url 函数.举例来说,如果你的 ImageField 叫作 mug_shot, 你就可以在模板中以 {{ object.get_mug_shot_url }} 这样的方式得到图像的绝对路径.
 42 # FilePathField
 43 # 可选项目为某个特定目录下的文件名. 支持三个特殊的参数, 其中第一个是必须提供的.
 44 # 
 45 # 参数    描述
 46 # path    必需参数. 一个目录的绝对文件系统路径. FilePathField 据此得到可选项目. Example: "/home/images".
 47 # match    可选参数. 一个正则表达式, 作为一个字符串, FilePathField 将使用它过滤文件名. 注意这个正则表达式只会应用到 base filename 而不是路径全名. Example: "foo.*\.txt^", 将匹配文件 foo23.txt 却不匹配 bar.txt 或 foo23.gif.
 48 # recursive    可选参数.要么 True 要么 False. 默认值是 False. 是否包括 path 下面的全部子目录.
 49 # 这三个参数可以同时使用.
 50 # 
 51 # 我已经告诉过你 match 仅应用于 base filename, 而不是路径全名. 那么,这个例子:
 52 # 
 53 # FilePathField(path="/home/images", match="foo.*", recursive=True)
 54 # ...会匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif
 55 # 
 56 # FloatField
 57 # 一个浮点数. 必须 提供两个 参数:
 58 # 
 59 # 参数    描述
 60 # max_digits    总位数(不包括小数点和符号)
 61 # decimal_places    小数位数
 62 # 举例来说, 要保存最大值为 999 (小数点后保存2位),你要这样定义字段:
 63 # 
 64 # models.FloatField(..., max_digits=5, decimal_places=2)
 65 # 要保存最大值一百万(小数点后保存10位)的话,你要这样定义:
 66 # 
 67 # models.FloatField(..., max_digits=19, decimal_places=10)
 68 # admin 用一个文本框(<input type="text">)表示该字段保存的数据.
 69 # 
 70 # ImageField
 71 # 类似 FileField, 不过要校验上传对象是否是一个合法图片.它有两个可选参数:height_field 和 width_field,如果提供这两个参数,则图片将按提供的高度和宽度规格保存.
 72 # 
 73 # 该字段要求 Python Imaging Library.
 74 # 
 75 # IntegerField
 76 # 用于保存一个整数.
 77 # 
 78 # admin 用一个``<input type="text">``表示该字段保存的数据(一个单行编辑框)
 79 # 
 80 # IPAddressField
 81 # 一个字符串形式的 IP 地址, (i.e. "24.124.1.30").
 82 # 
 83 # admin 用一个``<input type="text">``表示该字段保存的数据(一个单行编辑框)
 84 # 
 85 # NullBooleanField
 86 # 类似 BooleanField, 不过允许 NULL 作为其中一个选项. 推荐使用这个字段而不要用 BooleanField 加 null=True 选项.
 87 # 
 88 # admin 用一个选择框 <select> (三个可选择的值: "Unknown", "Yes" 和 "No" ) 来表示这种字段数据.
 89 # 
 90 # PhoneNumberField
 91 # 一个带有合法美国风格电话号码校验的 CharField``(格式: ``XXX-XXX-XXXX).
 92 # PositiveIntegerField
 93 # 类似 IntegerField, 但取值范围为非负整数(这个字段应该是允许0值的....所以字段名字取得不太好,无符号整数就对了嘛).
 94 # PositiveSmallIntegerField
 95 # 类似 PositiveIntegerField, 取值范围较小(数据库相关)
 96 # SlugField
 97 # "Slug" 是一个报纸术语. slug 是某个东西的小小标记(短签), 只包含字母,数字,下划线和连字符.它们通常用于URLs.
 98 # 
 99 # 若你使用 Django 开发版本,你可以指定 maxlength. 若 maxlength 未指定, Django 会使用默认长度: 50. 在以前的 Django 版本,没有任何办法改变 50 这个长度.
100 # 
101 # 这暗示了 db_index=True.
102 # 
103 # 它接受一个额外的参数: prepopulate_from, which is a list of fields from which to auto-populate the slug, via JavaScript, in the object's admin form:
104 # 
105 # models.SlugField(prepopulate_from=("pre_name", "name"))
106 # prepopulate_from 不接受 DateTimeFields.
107 # 
108 # admin 用一个``<input type="text">``表示 SlugField 字段数据(一个单行编辑框) 
109 # 
110 # SmallIntegerField
111 # 类似 IntegerField, 不过只允许某个取值范围内的整数.(依赖数据库)
112 #  
113 # TextField
114 # 一个容量很大的文本字段.
115 # 
116 # admin 用一个 <textarea> (文本区域)表示该字段数据.(一个多行编辑框).
117 # 
118 # TimeField
119 # A time. Accepts the same auto-population options as DateField 和 DateTimeField.
120 # 
121 # admin 用一个 <input type="text"> 文本框表示该字段保存的数据(附加一些JavaScript shortcuts).
122 # 
123 # URLField
124 # 用于保存 URL. 若 verify_exists 参数为 True (默认), 给定的 URL 会预先检查是否存在(即URL是否被有效装入且没有返回404响应).
125 # 
126 # admin 用一个 <input type="text"> 文本框表示该字段保存的数据(一个单行编辑框)
127 # 
128 # USStateField
129 # 一个两字母的美国州名缩写.
130 # 
131 # admin 用一个 <input type="text"> 文本框表示该字段保存的数据(一个单行编辑框)
132 # 
133 # XMLField
134 # 一个校验值是否为合法XML的 TextField,必须提供参数: schema_path, 它是一个用来校验文本的 RelaxNG schema 的文件系统路径.
View Code

模型类的定义(二)    

一  定义数据模型的扩展属性

     通过内部类Meta给数据模型类增加扩展属性:

     class Meta:

             verbose_name='名称'      #表名由英文转换成中文了

             verbose_name_plural='名称复数形式'

             ordering='排序字段'  

 

二  定义模型方法

    定义模型方法和定义普通python类方法没有太大的差别,定义模型方法可以将当前对应的数据组装成具体的业务逻辑。

     示例:定义__str__()让对象有一个名字

     def __str__(self):

           return self.name

 

4.3 ORM常用操作

4.3.1 增加

    create和save方法

实例:

 

 1 >>> from app01.models import *
 2 >>> Author.objects.create(name='Alvin')
 3 <Author: Alvin>
 4 >>> AuthorDetail.objects.create(sex=False,email='916852314@qq.com',address='bejing',birthday='1995-3-16',author_id=1)
 5 <AuthorDetail: AuthorDetail object>
 6 >>> pub=Publisher()
 7 >>> pub.name='河大出版社'
 8 >>> pub.address='保定'
 9 >>> pub.city='保定'
10 >>> pub.state_province='河北'
11 >>> pub.country='China'
12 >>> pub.website='http://www.beida.com'
13 >>> pub.save()
View Code

 

注意:如果每次创建一个对象,想显示对应的raw sql,需要在settings加上日志记录部分:

 1 LOGGING = {
 2 #     'version': 1,
 3 #     'disable_existing_loggers': False,
 4 #     'handlers': {
 5 #         'console':{
 6 #             'level':'DEBUG',
 7 #             'class':'logging.StreamHandler',
 8 #         },
 9 #     },
10 #     'loggers': {
11 #         'django.db.backends': {
12 #             'handlers': ['console'],
13 #             'propagate': True,
14 #             'level':'DEBUG',
15 #         },
16 #     }
17 # }
View Code

那么如何插入存在外键和多对多关系的一本书的信息呢?

1 >>> Book.objects.create(title='php',publisher=pub,publication_date='2017-7-7')
2 <Book: php>
3 >>> author1=Author.objects.get(id=1)
4 >>> author2=Author.objects.get(name='alvin')
5 >>> book=Book.objects.get(id=1)
6 >>> book.authors.add(author1,author1)
7 >>> book.authors.add(author1,author2)
8 
9  对应代码
View Code

        

     

     

     

 总结:

      1   objects:   model默认管理器。

      2   插入主外键关系的时候,可以用对象的方式,也可以用关联id的方式。

      3   插入多对多关系的时候要分步操作。

      4   create是管理器objects的方法

           save是model对象的方法

 

4.3.2 修改

    update和save方法

实例:

>>> author=Author.objects.get(id=2)
>>> author.name='tenglan'
>>> author.save()
>>> Publisher.objects.filter(id=2).update(name='American publisher')

注意:<1>不能用get的原因是:update是QuerySet对象的方法,get返回的是一个model对象,它没有update方法,而filter返回的是一个QuerySet对象。

         <2>  filter:

1
2
>>> Publisher.objects.filter(name__contains="press")
[   <Publisher: Apress>]

 在 name 和 contains 之间有双下划线。和Python一样,Django也使用双下划线来表明会进行一些魔术般的操作。这里,contains部分会被Django翻译成LIKE语句:

1
2
3
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name LIKE '%press%';

其他的一些查找类型有:icontains(大小写不敏感的LIKE),startswithendswith, 还有range     

     <3> 在“插入和更新数据”小节中,我们有提到模型的save()方法,这个方法会更新一行里的所有列。 而某些情况下,我们只需要更新行里的某几列。例如说我们现在想要将Apress Publisher的名称由原来的”Apress”更改为”Apress Publishing”。若使用save()方法,如:

1
2
3
>>> p = Publisher.objects.get(name='Apress')
>>> p.name = 'Apress Publishing'
>>> p.save()

  这等同于如下SQL语句:

1
2
3
4
5
6
7
8
9
10
11
12
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name = 'Apress';
  
UPDATE books_publisher SET
    name = 'Apress Publishing',
    address = '2855 Telegraph Ave.',
    city = 'Berkeley',
    state_province = 'CA',
    country = 'U.S.A.',
    website = 'http://www.apress.com'
WHERE id = 52;

  注意在这里我们假设Apress的ID为52)

在这个例子里我们可以看到Django的save()方法更新了不仅仅是name列的值,还有更新了所有的列。 若name以外的列有可能会被其他的进程所改动的情况下,只更改name列显然是更加明智的。 更改某一指定的列,我们可以调用结果集(QuerySet)对象的update()方法: 示例如下:

1
>>> Publisher.objects.filter(id=52).update(name='Apress Publishing')

  与之等同的SQL语句变得更高效,并且不会引起竞态条件。

1
2
3
UPDATE books_publisher
SET name = 'Apress Publishing'
WHERE id = 52;

  update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录。 以下示例演示如何将所有Publisher的country字段值由’U.S.A’更改为’USA’:

1
2
>>> Publisher.objects.all().update(country='USA')
2

  update()方法会返回一个整型数值,表示受影响的记录条数。 在上面的例子中,这个值是2。

 

4.3.3  查询 

>>> Publisher.objects.all()
[<Publisher: 中国机械出版社>, <Publisher: American publisher>]

注意:

这相当于这个SQL语句:

1
2
SELECT id, name, address, city, state_province, country, website
FROM books_publisher;

注意到Django在选择所有数据时并没有使用 SELECT* ,而是显式列出了所有字段。

惰性机制:

所谓惰性机制:Publisher.objects.all()只是返回了一个QuerySet(查询结果集对象),并不会马上执行sql,而是当调用QuerySet的时候才执行。

QuerySet特点:

       1   可迭代的

       2   可切片

一  查询相关API:

 <1>get(**kwargs):        返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。

 <2>all():                       查询所有结果

 <3>filter(**kwargs):      它包含了与所给筛选条件相匹配的对象

 <4>exclude(**kwargs):  它包含了与所给筛选条件不匹配的对象

 <5>order_by(*field):      对查询结果排序

 <6>reverse():                对查询结果反向排序

 <7>distinct():                从返回结果中剔除重复纪录

 <8>values(*field):         返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一

                                     系列 model的实例化对象,而是一个可迭代的字典序列

 <9>values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列

 <10>count():                返回数据库中匹配查询(QuerySet)的对象数量。

<11>first():                   返回第一条记录,等价于[:1][0]

<12>last():                   返回最后一条记录,等价于[::1][0]

 <13>exists():               如果QuerySet包含数据,就返回True,否则返回False。

实例:

      1   查询id为2的书籍信息,并只显示书籍名称和出版日期          

>>> Book.objects.filter(id=2).values("title","publication_date")
        [{'title': 'python Gone', 'publication_date': datetime.date(2019, 5, 24)}]

 

       2   查询所有的出版信息,并按id降序排列,并尝试使用reverse方法进行反向排序。     

>>> Publisher.objects.all().order_by("id")
        [<Publisher: 中国机械出版社>, <Publisher: Boo>, <Publisher: 人民出版社>]
>>> Publisher.objects.all().order_by("id").reverse()
        [<Publisher: 人民出版社>, <Publisher: Boo>, <Publisher: 中国机械出版社>]                 

>>> Publisher.objects.all().order_by("-id")
        [<Publisher: 人民出版社>, <Publisher: Boo>, <Publisher: 中国机械出版社>]

  3    查询出版社所在的城市信息,城市信息不要重复      

>>> Publisher.objects.all().values("city").distinct()
        [{'city': '北京'}, {'city': 'beijing'}]

4    查询城市是北京的出版社,尝试使用exclude方法  

>>> Publisher.objects.all().filter(city='beijing')
        [<Publisher: Boo>]

  5    查询男作者的数量       

>>> AuthorDetail.objects.filter(sex=0).count()
       1

二 多表关联查询

           1   外键关联查询

                  >>> AuthorDetail.objects.all().values("author")

        [{'author': 1}]
>>> AuthorDetail.objects.all().values("author__name")
        [{'author__name': 'alex'}]

2  多对多关联查询

      >>> Book.objects.all().filter(title='python Gone').values("authors")

        [{'authors': 1}, {'authors': 2}]
>>> Book.objects.all().filter(title='python Gone').values("authors__name")
        [{'authors__name': 'alex'}, {'authors__name': 'alvin'}]

>>> Book.objects.all().filter(authors__name='alex').values('title')
        [{'title': 'python Gone'}]

多表查询技巧:

       __:两个下划线可以生成连接查询,查询关联的字段信息

      _set:提供了对象访问相关联表数据的方法。但是这种方法只能是相关类访问定义了关系的类(主键类访问外键类)

三 聚合查询和分组查询

    1  annotate(*args,**kwargs):可以为QuerySet每一个对象添加注解。可以通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),用于分组查询

    2  aggregate(*args,**kwargs):通过对QuerySet进行计算,返回一个聚合值的字典。

aggregate()中每一个参数都指定一个包含在字典中的返回值。用于聚合查询。

聚合函数(Aggregation Functions)

所在位置:django.db.models

1 Avg:  返回所给字段的平均值

2 Count: 根据所给的关联字段返回被关联的model的数量

3 Max:返回所给字段的最大值

4 Sum:计算所给字段的总和

  为了演示实例,在这里我们给Book增加一个新的price字段:

 

  然后同步数据库:makemigrations, migrate就可以了,这也是django牛逼之处。

 

  另外,创建一些新的书:

 

        

 

  注意,在pycharm的database下创建新的对象,有个bug:

 

        

 

   我现在添入了第六条数据,可是,左上角的row仍然显示5,如果refresh:

 

       

 

   点击yes,添加的数据则会消失。

 

    解决方法:当你创建完一条数据后,点击+按钮,row变成6了,数据自动就提交了,然后再把新创建的空行删除(-)就可以了!

 

    Book对象添加完,还差一个字段:authors,绑定多对多的关系:

 

      

 

    插曲结束,转入正题:

 

           python manage.py shell(重新打开),因为添加了新的字段

 

      

 

           实例:

 

            1   查询中国邮电大学出版社出版了多少本书?           

 

       

 

            2   查询alex出的书总价格                   

 

       

 

            3   查询各个作者出的书的总价格

 

                         这里就涉及到分组了,分组条件是authors__name,

 

            

 

            4   查询各个出版社最便宜的书价是多少

 

       

 

4.3.4  删除

 

      >>> Book.objects.filter(id=1).delete()

 

       (3, {'app01.Book_authors': 2, 'app01.Book': 1})

 

       我们表面上删除了一条信息,实际却删除了三条,因为我们删除的这本书在Book_authors表中有两条相关信息,这种删除方式就是django默认的级联删除。

 

 

参考:

https://www.cnblogs.com/wupeiqi/articles/5237704.html

https://www.cnblogs.com/yuanchenqi/articles/5786089.html

 

4.3.2 修改

    update和save方法

实例: