Django的Model层之基础学习

Django的Model层的存在是为了避免让我们过多得关注数据库的本身,避免重复得进行数据库建立,修改,关闭等等操作。而且避免了在从一个数据库类型转换为另一个数据库类型所造成的大量工作。当然,这也是ORM最大的特性。

详细学习Model层之前,要学习一下MVC开发模式。

一、MVC、MTV模式

把数据存取逻辑、业务逻辑和表现逻辑组合在一起的概念有时被称为软件架构的 Model-View-Controller (MVC)模式。 在这个模式中, Model 代表数据存取层,View 代表的是系统中选择显示什么和怎么显示的部 分,Controller 指的是系统中根据用户输入并视需要访问模型,以决定使用哪个视图的那部分。
Django 紧紧地遵循这种 MVC 模式,可以称得上是一种 MVC 框架。 以下是 Django 中 M、V 和 C 各自的含 义:

  • M ,数据存取部分,由django数据库层处理,本章要讲述的内容。
  • V ,选择显示哪些数据要显示以及怎样显示的部分,由视图和模板处理。
  • C ,根据用户输入委派视图的部分,由 Django 框架根据 URLconf 设置,对给定 URL 调用适当的Python 函数。

由于在Django中,MVC的C 由框架自行处理,而 Django 里更关注的是模型(Model)、模板(Template)和视图(Views), Django 也被称为 MTV 框架。

  • M 代表模型(Model),即数据存取层。 该层处理与数据相关的所有事务: 如何存取、如何验证有效 性、包含哪些行为以及数据之间的关系等。

  • T 代表模板(Template),即表现层。 该层处理与表现相关的决定: 如何在页面或其他类型文档中进行显示。

  • V 代表视图(View),即业务逻辑层。 该层包含存取模型及调取恰当模板的相关逻辑。 你可以把它看作模型与模板之间的桥梁。

二、Model基础语法

1、字段Field学习

1、Field通用参数
1)null 默认为False,如果设为True,Django将用Null存储空值,否则用False存储空值;
2)blank 如果设为True,那么就允许该字段为空值,否则不允许为空值。这和null的区别是null属于数据存储范畴的,blank 属于验证范畴的,即填写时,这个字段是否可以不填。
3)choices 是一个由二元组组成的可迭代对象(列表或元祖),),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,而且这个选择框的选项就是 choices 中的选项。每个元组中的第一个元素,是存储在数据库中的值;第二个元素是在管理界面或 ModelChoiceField 中用作显示的内容。
4)default 字段的默认值,可以是一个值,也可以是一个可调用对象。
5)help_text 表单部件额外显示的帮助内容
6)unique 如果设为True,则为唯一。
7)verbose_name,一个易于读的字段名字

2、Meta类
在Model中定义一个Meta类,Meta并不是一个字段,模型元数据是“任何不是字段的数据”,比如排序选项( ordering ),数据表名( db_table )或者人类可读的单复数名称( verbose_name 和 verbose_name_plural )。在模型中添加 class Meta 是完全可选的,所有选项都不是必须的。

如: class Meta: ordering = ['rank', '-create_time']

选项有:

  • ordering
  • verbose_name
  • get_latest_by Django有个latest方法,这个就是得到最新一行
  • db_table等等

下面是一个Model类实例(在我的第一个Django项目定义的):

class Category(models.Model):

    name = models.CharField(max_length=150,unique=True,verbose_name=u'类名')
    alias = models.CharField(max_length=150,verbose_name=u'英文名称')
    status = models.IntegerField(default=0,choices=STATUS.items(),verbose_name=u'状态')
    #Automatically set the field to now when the object is first created.
    create_time = models.DateTimeField(auto_now_add=True)
    parent = models.ForeignKey('self',default=None,blank=True,null=True,verbose_name=u'上级分类')


    def __unicode__(self):
         if self.parent:
             return "{0}:{1}".format(self.parent,self.name)
         else:
             return '%s' % self.name

    @classmethod
    def available_categories(cls):
         return cls.objects.filter(status=0)


    class Meta:
         ordering = ['-create_time']
         verbose_name = u'分类'

关于模型有几点说明: 1、自动生成的表名是app名称和模型的小写名称 ( publisher , book , author )的组合。如我的app叫做blog,model叫category,那自动生成的表明就是blog_category。如果想自定义表明,那就在Meta中,定义db_table即可。
2、Django为每个表格自动添加加了一个 id 主键。
3、按约定,Django添加 "_id" 后缀到外键字段名。 即如果有一个外键author,在该表中会有一个author_id外键字段。
4、Django中使用通用的unicode编码,因此在Model中显示也要显示unicode字符,只不过在Python2中,要定义__unicode ,在Python3中,要使用__str ,因为Python3默认的就是unicode字符。

三、数据库操作

增、删、改、查。
ORM大大简化了数据库操作,因此它的操作也特别简单。
1、增:直接定义一个模型类。

p = Category(name='Apress',
... alias='2855 Telegraph Ave.',
)
p.save()

这个插入数据操作根本不需要写复杂的SQL语句,一个SAVE方法帮我们做了所有的事情。

2、改数据
对于已有的数据,比如上面增加的,直接赋值修改

p.alias='haibo'
p.save()

注意,这里的save方法是更改数据的所有列。也就是它相当于执行:

UPDATE blog_category SET
name ='Apress',
alias = 'haibo.'
where id=1,

但实际上,有时别的字段可能被其他程序改动,但我们只希望更新alias字段,那么就可以用update方法: Category.objects.filter(id=52).update(alias='haibo')只更新alias这一个字段。

3、删除数据 p.delete()

4、查
在说查询之前,要说一个概念,那就是模型类objects.。 每个非抽象的 Model 类必须给自己添加一个 Manager 实例。Django 确保在你的模型类中至少 有一个默认的 Manager 。如果你没有添加自己的 Manager ,Django 将添加一个属 性 objects ,它包含默认的 Manager 实例。如果你添加自己的 Manager 实例的属性,默认值 则不会出现 。
通过模型中的Manager构造一个QuertSet,来从你的数据库中获取对象。 QuerySet表示你数据库中取出来的一个对象的集合。它可以含有零个、一个或者多个过滤 器,过滤器根据所给的参数限制查询结果的范围。在sql的角度,QuerySet和SELECT命令等 价,过滤器是像WHERE和LIMIT一样的限制子句。
Queryset可以进行缓存。当第一次执行时会缓存查询数据。

1、获取所有对象 Entry.objects.all()

2、过滤对象

1)基本筛选

Publisher.objects.filter(name='Apress')

也可以通过多个值,多小范围

Publisher.objects.filter(country="U.S.A.", state_province="CA"),相当于一个and语句。

2)字段筛选条件

Django中的字段筛选还是比较特别的,字段筛选条件就是SQL中的WHERE语句,是Django中filter或者exclude带的参数。 筛选条件的形式是 field__lookuptype=value 。 (注意:这里是双下划线)。例如:

>>> Entry.objects.filter(pub_date__lte='2006-01-01')

大体可以翻译为如下的 SQL 语句:

SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01'; 
Poll.objects.get(
Q(question__startswith='Who'),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
... 大体可以翻译为下面的 SQL:
SELECT * from polls WHERE question LIKE 'Who%'
AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

Django数据库一共支持24中Lookup 类型。
1、iextract,忽略大小写的匹配
2、gt,大于
3、lt小于
4、lte小于等于
5、_startswith 以...开头
6、__istartswith 以...开头 忽略大小写
7、__endswith 以...结尾
8、__iendswith 以...结尾,忽略大小写
9、__range 在...范围内
10、__year 日期字段的年份
11、__month 日期字段的月份
12、__day 日期字段的日
13、__isnull=True/False

3、values,values_list
values返回一个带有字典元素的列表,values_list返回带有二元组的列表。values返回的不能再进行Lookup查询。

Entry.objects.values_list('id', 'headline')  
[(1, 'First entry'), ...]
 Blog.objects.values('id', 'name') 
[{'id': 1, 'name': 'Beatles Blog'}]

4、限制返回的数据个数

使用Python列表的分片技术。如:

Publisher.objects.order_by('name')[0:2]

但不能用Python的负索引,Publisher.objects.order_by('name')[‐1]是错误的。

5、F、Q
F用来两个不同字段的比较;

Entry.objects.filter(n_pingbacks__lt=F('n_comments'))

Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。例如,要找到 广播数等于评论数两倍的博文,可以这样修改查询语句:

>>> Entry.objects.filter(n_pingbacks__lt=F('n_comments') * 2)
要查找阅读数量小于评论数与广播数之和的博文,查询如下:
>>> Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks'))

Q用来执行复杂的查询

Q 对象(django.db.models.Q)是用来封装一组查询关键字的对象。这里提到的查询关键字请查 看上面的 "Field lookups"。
例如,下面这个 Q 对象封装了一个单独的 LIKE 查询:

Q(question__startswith='What')

Q 对象可以用 & 和 | 运算符进行连接。当某个操作连接两个 Q 对象时,就会产生一个新的等 价的 Q 对象。

6、获取单个对象
上面的例子中 filter() 函数返回一个记录集,这个记录集是一个列表。 相对列表来说,有些时候我们更需要 获取单个的对象, get() 方法就是在此时使用的:

>>> Publisher.objects.get(name="Apress")

7、多表连接查询,也叫跨关系查询。

  class A(models.Model):
    name = models.CharField(u'名称')
  class B(models.Model):
    aa = models.ForeignKey(A)
B.objects.filter(aa__name__contains='searchtitle')

当然也可以反向查询,

Django的查询集有很多的用法,具体还要参考Django官方文档。

8、查询集是延迟的,即你定义一个查询表达式,它不会立即执行。

>>> q = Entry.objects.filter(headline__startswith="What")
>>> q = q.filter(pub_date__lte=datetime.now())
>>> q = q.exclude(body_text__icontains="food")
>>> print q

虽然上面的代码看上去象是三个数据库操作,但实际上只在最后一行 (print q) 执行了一次数 据库操作

我上面介绍的都是最基本的,其实相关知识还有很多,必须得看官方文档,也要在不断的实践过程中不断积累。

--------EOF---------
微信分享/微信扫码阅读