天天看点

Django学习笔记之——Models1. 模型的Fields

django里的模型是对数据库对表的一次封装,是应用业务与数据之间的桥梁。

在上一节,我们在mysite/blog/models.py中创建了blogpost这个model。

blogpost里用了charfield,textfield, textfield域。难道就只有这三种,不可能!

如下,我列出了其它的field,并表明了它们的继承关系:

别问我是怎么知道的。看源码呀~在 django/db/models/fields/__init__.py 中定义。

如果你是去看了这个文件,那么不难知道 field类的__init__(self)函数带了很多参数吧。

field类在构造的时候可以指定以下参数:

verbose_name=none   #显示名

name=none           #域名

primary_key=false   #是否为主键

max_length=none     #在charfiled中用到

unique=false        #是否唯一

blank=false

null=false          #是否允许为空

db_index=false

rel=none

default=not_provided

editable=true       #是否可编辑

serialize=true

unique_for_date=none

unique_for_month=none

unique_for_year=none

choices=none

help_text=''

db_column=none

db_tablespace=none

auto_created=false

validators=[]

error_messages=none

models.foreignkey

~~~~~~~~~~~~~~~~~

可以用models.foreignkey()指定外键,如在models.py中:

_______________________________________________

class author(models.model):

    name = models.charfield(max_length=100)

class book(models.model):

    title = models.charfield(max_length=100)

    author = models.foreignkey(author) #定义外键

-----------------------------------------------

注:author必须在book之前定义。如果不想有这样的限制,那么在foreignkey()中以

"author"字符串对象作为参数传入。

    author = models.foreignkey('author') # 注意,这里用的是类名称,而不是类

                                         # 本身

在外键的支持下,可以实现数据库中多表查询的功能。比如查到与该书作者的所有书:

________________________________________________

book_title = "c++程序设计"

this_book = book.objects.get(title=book_title)  # 找到title为"c++程序设计"

                                                # 的book对象this_book

author = this_book.author   # 由this_book获得作者对象author

books = author.book_set.all()   # 根据author获得所有的书,得到books数组

               ^^^^^^^^

for book in books: # 打印每一本书

    print(book.title)

------------------------------------------------

在book中加入了foreignkey('author')之后,django会在author对象中添加一个属性

叫:book_set。

但是,如果用的是foreignkey('author', related_name="books"),也就是告诉django

在author端对应的属性名叫"books",而不再是django默认的"book_set"了。

models.manytomanyfield

~~~~~~~~~~~~~~~~~~~~~~

顾名思意,就是多对多域。当两个表存在多对多的关系时,这就很有用。

比如:一名作者可能写了多本书,一本书也可能由多名作者共同编写。

    author = models.manytomanyfield(author)

其实,django为我们建了另一个book_book_author的表。

如下为book_book_author的创建明细:

__________________________________________________________________________

sqlite> .schema book_book_author

create table "book_book_author" (

    "id" integer not null primary key,

    "book_id" varchar(50) not null,

    "author_id" integer not null references "book_author" ("id"),

    unique ("book_id", "author_id")

    );

create index "book_book_author_36c249d7" on "book_book_author" ("book_id");

create index "book_book_author_e969df21" on "book_book_author" ("author_id");

--------------------------------------------------------------------------

那么,这种多对多的关系在view中怎么使用呢?

models.onetoonefield一对一关系

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

模型继承关系

~~~~~~~~~~~~

在模型类中定义meta内部类,并指定meta.abstract = true时,表示该模型为抽象模型

,即只用来被子模型类派生而不生成实际的模型。

这时,django在./manage.py syncdb时就不会为该模型创建表。比如:person为人的模

型,里面定义了人的基本属性。student与teacher继承于它。在同步数据库时,我们不

能为person创建一张表吧。如下:

class person(models.model):

    name = models.charfield(max_length=50)

    gender = models.positivesmallintegerfield()

    birthday = models.datefield()

    def __unicode__(self):

        return self.name

    class meta:

        abstract = true

class teacher(person):

    pass

class student(person):

对了,记得给模型定义__unicode__方法。这用利于让admin知道模型对象该怎么显示。

meta嵌套类

~~~~~~~~~~

在前面有两处提到了meta类,一处是在blog排序时,另一处就是上面的虚继承。

meta的用法是嵌套在model类里面,用于说明附加的信息。

数据查询

~~~~~~~~

每个model都有一个objects属性,而这个objects属性具有以下方法:

model.objects.all()       # 获取所有对象的queryset

model.objects.filter()    # 获取满足条件的对象的queryset

model.objects.exclude()   # 获取不满足条件的对象的queryset

model.objects.get()       # 获取单个符合条件的对象的queryset

queryset会将查询条件转换成sql语句,并获得执行结果。

示例:

____________________________________________________________

# 找出john doe

person.objects.filter(last="doe").filter(first="john")

# 找出逾期不还的书

today = datetime.now()

overdue_books = book_queryset.filter(due_date__lt = today)

                                             ^^^^

                                 意恩是:due_date < today

# 注:除了__lt,还有:__gt

# 查询结果排序,并提取前5个

all_sorted_first = person.objects.all().order_by('first')[:5]

# 使用select_related执行简单的join操作

person.objects.all().select_related('address', depth=1)

-------------------------------------------------------------

用q()让条件灵活组合

~~~~~~~~~~~~~~~~~~~

使用q()来封装查询条件,与 & | ~ 配合,形成组合条件。

_______________________________________________________________________

person.objects.filter(

    q(last="doe") |

    (q(last="smith") & q(first="john") & ~q(middle__startswith="w"))

)

first_names = ['john', 'jane', 'jeremy']

first_name_keywords = q()

for name in first_names:

    first_name_keywords = first_name_keywords | q(first=name)

specific_does = person.objects.filter(last="doe").filter(first_name_keywords)

----------------------------------------------------------------------

用extra()提供其它的功能

~~~~~~~~~~~~~~~~~~~~~~~

## select提供简单数据

# select age, (age > 18) as is_adult from myapp_person;

person.objects.all().extra(select={'is_adult': "age > 18"})

## where提供查询条件

# select * from myapp_person where first||last ilike 'jeffrey%';

person.objects.all().extra(where=["first||last ilike 'jeffrey%'"])

## table连接其它表

# select * from myapp_book, myapp_person where last = author_last

book.objects.all().extra(table=['myapp_person'], where=['last = author_last'])

## params添参数

# !! 错误的方式 !!

first_name = 'joe'  # 如果first_name中有sql特定字符就会出现漏洞

person.objects.all().extra(where=["first = '%s'" % first_name])

# 正确方式

person.objects.all().extra(where=["first = '%s'"], params=[first_name])

#                                                ^^^^^^^^^^^^^^^^^^^^^

数据库导入导出

~~~~~~~~~~~~~~

# 将book应用的数据导出到book.json文件中去

./manage.py dumpdata --indent=4 book > book.json

自定义sql查询

~~~~~~~~~~~~~

如果前面的queryset无法满足特殊的查询要求,那就让我们自己来指定select语句吧。

如下:

from django.db import connection

cursor = connection.cursor()

cursor.execute("select first, last from myapp_person where last='doe'")

doe_rows = cursor.fetchall()

for row in doe_rows:

    print("%s %s" % (row[0], row[1]))

-----------------------------------------------------------------------