模型

简介模型是你的数据的唯一的、权威的信息源。它包含你所储存数据的必要字段和行为。通常,每个模型对应数据库中唯一的一张。

每个模型都是django.db.models.Model 的一个Python 子类。

字段类型

1、models.AutoField  自增列 = int(11)

  如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。

2、models.CharField  字符串字段

  必须 max_length 参数

3、models.BooleanField  布尔类型=tinyint(1)

  不能为空,Blank=True

4、models.ComaSeparatedIntegerField  用逗号分割的数字=varchar

  继承CharField,所以必须 max_lenght 参数

5、models.DateField  日期类型 date

  对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。

6、models.DateTimeField  日期类型 datetime

  同DateField的参数

7、models.Decimal  十进制小数类型 = decimal

  必须指定整数位max_digits和小数位decimal_places

8、models.EmailField  字符串类型(正则表达式邮箱) =varchar

  对字符串进行正则表达式

9、models.FloatField  浮点类型 = double

10、models.IntegerField  ×××

11、models.BigIntegerField  长×××

  integer_field_ranges = {

    'SmallIntegerField': (-32768, 32767),

    'IntegerField': (-2147483648, 2147483647),

    'BigIntegerField': (-9223372036854775808, 9223372036854775807),

    'PositiveSmallIntegerField': (0, 32767),

    'PositiveIntegerField': (0, 2147483647),

  }

12、models.IPAddressField  字符串类型(ip4正则表达式)

13、models.GenericIPAddressField  字符串类型(ip4和ip6是可选的)

  参数protocol可以是:both、ipv4、ipv6

  验证时,会根据设置报错

14、models.NullBooleanField  允许为空的布尔类型

15、models.PositiveIntegerFiel  正Integer

16、models.PositiveSmallIntegerField  正smallInteger

17、models.SlugField  减号、下划线、字母、数字

18、models.SmallIntegerField  数字

  数据库中的字段有:tinyint、smallint、int、bigint

19、models.TextField  字符串=longtext

20、models.TimeField  时间 HH:MM[:ss[.uuuuuu]]

21、models.URLField  字符串,地址正则表达式

22、models.BinaryField  二进制

23、models.ImageField   图片

24、models.FilePathField 文件

foreignkey字段类型

25、related_name这个名称用于让关联的对象反查到源对象。

26、related_query_name这个名称用于目标模型的反向过滤。如果设置了related_name,则默认为它的值,否则默认值为模型的名称

字段选项

1、null=True

  数据库中字段是否可以为空

2、blank=True

  django的 Admin 中添加数据时是否可允许空值

3、primary_key = False

  主键,对AutoField设置主键后,就会代替原来的自增 id 列

4、auto_now 和 auto_now_add

 auto_now   自动创建---无论添加或修改,都是当前操作的时间

  auto_now_add  自动创建---永远是创建时的时间

5、choices

GENDER_CHOICE = (

(u'M', u'Male'),

(u'F', u'Female'),

)默认的表单将是一个选择框而不是标准的文本框,而且这个选择框的选项就是choices 中的选项。

gender = models.CharField(max_length=2,choices = GENDER_CHOICE)

6、max_length

7、default  默认值

8、verbose_name  Admin中字段的显示名称

9、name|db_column  数据库中的字段名称

10、unique=True  不允许重复

11、db_index = True  数据库索引

12、editable=True  在Admin里是否可编辑

13、e rror_messages=None  错误提示

14、auto_created=False  自动创建

15、help_text  在Admin中提示帮助信息

16、validators=[]

17、upload-to



    创建对象:

        Person.objects.create(name=name,age=age)

        p = Person(name="WZ", age=23)

        p.save()

        p = Person(name="TWZ")

        p.age = 23

        p.save()

        Person.objects.get_or_create(name="WZT", age=23)

        这种方法是防止重复很好的方法,但是速度要相对慢些,返回一个元组,第一个为Person对象,第二个为True或False, 新建时返回的是True, 已经存在时返回False.


    获取对象:

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

        Person.objects.all()

        Person.objects.all()[:10] 切片操作,获取10个人,不支持负索引,切片可以节约内存

        Person.objects.get(name=name)

        Person.objects.filter(name="abc") # 等于Person.objects.filter(name__exact="abc") 名称严格等于 "abc" 的人

        models.Tb1.objects.filter(id__gt=1)              # 获取id大于1的值

        models.Tb1.objects.filter(id__lt=10)             # 获取id小于10的值

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

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

        models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in

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

Person.objects.filter(name__exact="abc") # 名称为 abc区分大小写,

        Person.objects.filter(name__iexact="abc") # 名称为 abc 但是不区分大小写,可以找到 ABC, Abc, aBC,这些都符合条件

        Person.objects.filter(name__contains="abc") # 名称中包含 "abc"的人

        Person.objects.filter(name__icontains="abc") #名称中包含 "abc",且abc不区分大小写

        Person.objects.exclude(name__contains="WZ") # 排除包含 WZ 的Person对象

        Person.objects.filter(name__contains="abc").exclude(age=23) # 找出名称含有abc, 但是排除年龄是23岁的

        Person.objects.filter(name__regex="^abc") # 正则表达式查询

        Person.objects.filter(name__iregex="^abc")# 正则表达式不区分大小写


    删除对象:

            Person.objects.filter().delete()

            Person.objects.all().delete()


    更新对象

        models.Tb1.objects.filter(name='seven').update(gender='0')  # 将指定条件的数据更新,均支持 **kwargs

        obj = models.Tb1.objects.get(id=1)#修改单条数据

        obj.c1 = '111'

        obj.save()                                                 



表关系

显然,关系数据库的威力体现在表之间的相互关联。 Django 提供了三种最常见的数据库关系:多对一(many-to-one),多对多(many-to-many),一对一(one-to-one)。

这个一对多、多对多一直困扰着我,自学的时候都没搞明白,这次专门听课,又不怎么太明白,闲着无聊就问女朋友,啥叫一对多,啥叫多对多,她很自然的说:一对多,就是一个打多个,多对多就是,两帮人乱打。草泥马,瞬间我明白了。

多对一(外键)ForeignKey

在django的模型中,可以简单的理解为,一个表的外键关联另一个表的主键。

若要创建一个递归的关联 —— 对象与自己具有多对一的关系 —— 请使用models.ForeignKey('self')。

class Blog(models.Model):

name = models.CharField(max_length=100)

tagline = models.TextField()

def __str__(self): 

return self.name

class Entry(models.Model):

blog = models.ForeignKey(Blog)

headline = models.CharField(max_length=255)

body_text = models.TextField()

pub_date = models.DateField()

mod_date = models.DateField()

authors = models.ManyToManyField(Author)

n_comments = models.IntegerField()

n_pingbacks = models.IntegerField()

rating = models.IntegerField()

def __str__(self): 

return self.headline

正向查询

如果一个模型具有ForeignKey,那么该模型的实例将可以通过属性访问关联的(外部)对象。

e = Entry.objects.get(id=2)

e.blog

更新ForeignKey 字段的方式和保存普通字段相同 只要把一个正确类型的对象赋值给该字段。下面的例子更新了Entry 类的实例entry 的blog 属性

entry = Entry.objects.get(pk=1)

cheese_blog = Blog.objects.get(name="Cheddar Talk")

entry.blog = cheese_blog

entry.save()

反向查询

b = Blog.objects.get(id=1)

b.entry_set.all() 

b.entry_set.filter(headline__contains='Lennon')

b.entry_set.count()

你可以在ForeignKey 定义时设置related_name 参数来覆盖foo_set的名称。如果Entry模型改成blog = ForeignKey(Blog, related_name='entries')。

b = Blog.objects.get(id=1)

b.entries.all()





多对多 Many-to-Many

django会自动创建另一张表存,存在两张表id字段的对应关系,简单理解为,存着两张表的主键之间的对应关系。

class Author(models.Model):

name = models.CharField(max_length=50)

email = models.EmailField()

def __str__(self): 

return self.name

class Entry(models.Model):

blog = models.ForeignKey(Blog)

headline = models.CharField(max_length=255)

body_text = models.TextField()

pub_date = models.DateField()

mod_date = models.DateField()

authors = models.ManyToManyField(Author)

n_comments = models.IntegerField()

n_pingbacks = models.IntegerField()

rating = models.IntegerField()

def __str__(self): 

return self.headline

更新ManyToManyField,需要使用字段的add()方法来增加关联关系的一条记录。

joe = Author.objects.create(name="Joe")

entry.authors.add(joe)

向ManyToManyField添加多条记录,可以在调用add()方法时传入多个参数。

john = Author.objects.create(name="John")

paul = Author.objects.create(name="Paul")

entry.authors.add(john, paul,)

自定义多对多关系表

可以直接操作第三张表,不必通过关联表查询

class Host(models.Model):

hostname = models.CharField(max_length=32)

port = models.IntegerField()


class HostAdmin(models.Model):

username = models.CharField(max_length=32)

email = models.CharField(max_length=32)

host = models.ManyToManyField(Host1, through='HostRelation')  #在表里加参数through用来定义多对多关系表名。


class HostRelation(models.Model):

c1 = models.ForeignKey(Host1)

c2 = models.ForeignKey(HostAdmin1)

relation_list = models.HostRelation.objects.all()

一对一 OneToOneField

当某个对象想扩展自另一个对象时,最常用的方式就是在这个对象的主键上添加一对一关系。

创建账户信息的时候

class UserProfile(models.Model):

'''

账户信息表

'''

username = models.OneToOneField(User)

user = models.CharField(max_length=32)

friends = models.ManyToManyField('self', related_name='my_friends')


处理关联对象的其它方法


除了在上面”获取对象“一节中定义的查询集 方法之外,ForeignKey 管理器 还有其它方法用于处理关联的对象集合。下面是每个方法的大概,完整的细节可以在关联对象参考 中找到。


add(obj1, obj2, ...)

添加一指定的模型对象到关联的对象集中。

create(**kwargs)

创建一个新的对象,将它保存并放在关联的对象集中。返回新创建的对象。

remove(obj1, obj2, ...)

从关联的对象集中删除指定的模型对象。

clear()

从关联的对象集中删除所有的对象。若要一次性给关联的对象集赋值,只需要给它赋值一个可迭代的对象。这个可迭代的对象可以包含对象的实例,或者一个主键值的列表。例如:

b = Blog.objects.get(id=1)

b.entry_set = [e1, e2]

跨关联关系的查询

Django 提供一种强大而又直观的方式来“处理”查询中的关联关系,它在后台自动帮你处理JOIN。 若要跨越关联关系,只需使用关联的模型字段的名称,并使用双下划线分隔,直至你想要的字段:

它还可以反向工作。若要引用一个“反向”的关系,只需要使用该模型的小写的名称。

下面这个例子获取所有Blog 的name 为'Beatles Blog' 的Entry 对象:

Entry.objects.filter(blog__name='Beatles Blog')

下面的示例获取所有的Blog 对象,它们至少有一个Entry 的headline 包含'Lennon':

Blog.objects.filter(entry__headline__contains='Lennon')

如果你在多个关联关系直接过滤而且其中某个中介模型没有满过滤条件的值,Django 将把它当做一个空的(所有的值都为NULL)但是合法的对象。这意味着不会有错误引发。例如,在下面的过滤器中:

Blog.objects.filter(entry__authors__name='Lennon')

跨越多值的关联关系

选择headline 包含Lennon 并且发表时间是2008 的所有blog(同一个entry 满足两个条件)。

Blog.objects.filter(entry__headline__contains='Lennon',

        entry__pub_date__year=2008)

从所有的blog模型实例中选择满足以下条件的blog实例:blog的enrty满足:headline属性值是“Lennon”并且发表时间是2008(可以不是同一个entry)。

Blog.objects.filter(entry__headline__contains='Lennon').filter(

entry__pub_date__year=2008)

F表达式

F() 返回的实例用作查询内部对模型字段的引用。

例如,为了查找comments 数目多于pingbacks 的Entry,我们将构造一个F() 对象来引用pingback 数目,并在查询中使用该F() 对象:

from django.db.models import F

Entry.objects.filter(n_comments__gt=F('n_pingbacks'))


为了查询rating 比pingback 和comment 数目总和要小的Entry,我们将这样查询:

Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks'))


你还可以在F() 对象中使用双下划线标记来跨越关联关系。带有双下划线的F() 对象将引入任何需要的join 操作以访问关联的对象。例如,如要获取author 的名字与blog 名字相同的Entry,我们可以这样查询:

Entry.objects.filter(authors__name=F('blog__name'))


对于date 和date/time 字段,你可以给它们加上或减去一个timedelta 对象。下面的例子将返回发布超过3天后被修改的所有Entry:

from datetime import timedelta

Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))

Q查询

filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q 对象。Q 对象可以使用& 和| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。例如,下面的语句产生一个Q 对象,表示两个"question__startswith" 查询的“OR” :

Q(question__startswith='Who') | Q(question__startswith='What')

它等同于下面的SQL WHERE 子句:

WHERE question LIKE 'Who%' OR question LIKE 'What%'


查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:

Poll.objects.get(

Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),

question__startswith='Who')


动态构建查询条件

比如你定义了一个包含一些 Q 对象的列表,如何使用这个列表构建 AND 或 OR 查询呢? 可以使用 operator 和 reduce:


>>> lst = [Q(question_text__contains='you'), Q(question_text__contains='who')]

>>> Question.objects.filter(reduce(operator.or_, lst))

[, , , ]

>>> Question.objects.filter(reduce(operator.and_, lst))

[]

这个列表也可能是根据用户的输入来构建的,比如简单的搜索功能(搜索一个文章的标题或内容或作者名称包含某个关键字):

q = request.GET.get('q', '').strip()

lst = []

if q:

    for key in ['title__contains', 'content__contains',

                'author__name__contains']:

        q_obj = Q(**{key: q})

        lst.append(q_obj)

queryset = Entry.objects.filter(reduce(operator.or_, lst))