目录

model 1

model... 2

常用Field types... 5

Relationship fields. 5

Field options... 6

Meta options... 6

重写save()方法:... 7

模型继承:... 7

抽象基类:... 7

多表继承:... 8

代理继承:... 9

多重继承:... 10

 

 

 

model

 

模型的价值在于定义数据模型,使用py代码ORM形式操作数据库;

 

mysite/mysite/settings.py   #只有在settings.py中激活app才能使用models

INSTALLED_APPS = [

    'publish.apps.PublishConfig',

    'bootstrap3',

    'books.apps.BooksConfig',

    'polls.apps.PollsConfig',

    'django.contrib.admin',

    'django.contrib.auth',

    'django.contrib.contenttypes',

    'django.contrib.sessions',

    'django.contrib.messages',

    'django.contrib.staticfiles',

]

 

 

model

支持sqlitemysqlpostgresqloracle

py3.5以上版本,不支持MySQLdb驱动;

可用pymysqlpy写的;

可用mysqlclientc写的,速度快,forkMySQLdb,官方推荐;

 

ORM,用py的方法、数据结构,来访问db,可兼容不同的DB

 

一个class代表一张表,多对多会产生额外一张关系表;

默认pkid,也可自定义pk

表名默认为$APP_NAME$CLASS_NAME.lower(),表名小写(跨平台支持),可重写;

 

models migrations

定义好models.py需应用到dbdjango为了能跟踪表结构的变化,增加了migration版本控制功能,如果没有该功能,需手动编写表结构变化的语句,重新导入数据;

makemigrationsmigrate

 

models CRUD

增:

q = Question(**kwargs)   #方式1,实例化,Model(kwargs).save()

q.save()

 

q = Question.objects.create(**kwargs)   #方式2,用管理器形式,Model.objects.create(**kwargs)

 

删:

q = Question.objects.get(id=1)   #QuerySet.delete()

q.delete()   #object.delete()

 

Question.objects.filter(id=1).delete()

Question.objects.all().delete()

 

改:

q = Question.objects.get(id=1)

q.question_text = 'some text'   #object.attr = value.object.save()

q.save()

 

Question.objects.filter(id=1).update(question_text='why ?')   #QuerySet.update(**kwargs)

 

查:

Question.objects.all()   #Model.objects.all(kwargs)Model.objects.filter(kwargs)Model.objects.get(**kwargs)

Question.objects.filter(question_text="what's up?")   #objectsmodel默认的manager管理器

Question.objects.get(id=1)

latest_question_list = Question.objects.order_by('-pub_date')[:3]   #默认升序,加上-为倒序

 

for p in Person.objects.raw('select * from myapp_person'):   #执行原生sql

         print(p)

 

注:

>>> from django.utils import timezone

>>> import datetime

>>> timezone.now()   #datetime.datetime.now()多了时区,在页面展示时,django内部会转为适合用户所在的时区

datetime.datetime(2019, 1, 2, 7, 2, 18, 244920, tzinfo=)

>>> datetime.datetime.now()

datetime.datetime(2019, 1, 2, 15, 2, 32, 837755)

 

models中方法:

def __str__(self):

         return self.question_text

def was_published_recently(self):

         return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

 

 

mysite/mysite/settings.py

DATABASES = {

    'default': {

        'ENGINE': 'django.db.backends.sqlite3',

        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),

    }

}

 

 

mysite/polls/models.py

from django.db import models

 

class Question(models.Model):   #一个class代表一张表,多对多会产生额外一张关系表;默认pkid,也可自定义pk;表名默认为$APP_NAME$CLASS_NAME.lower(),可重写

    question_text = models.CharField(max_length=200)

    pub_date = models.DateTimeField('date published')

 

class Choice(models.Model):

    question = models.ForeignKey(Question, on_delete=models.CASCADE)

    choice_text = models.CharField(max_length=200)

    votes = models.IntegerField(default=0)

 

(webproject) C:\webproject\mysite>python manage.py makemigrations   #生成迁移记录,先makemigrations才能migrate

(webproject) C:\webproject\mysite>python manage.py migrate   #应用到db

(webproject) C:\webproject\mysite>sqlite3 db.sqlite3

sqlite> .tables

auth_group                  django_admin_log

auth_group_permissions      django_content_type

auth_permission             django_migrations

auth_user                   django_session

auth_user_groups            polls_choice

auth_user_user_permissions  polls_question

sqlite> .quit

 

(webproject) C:\webproject\mysite>dir polls\migrations\

 驱动器 C 中的卷是 OS

 卷的序列号是 000B-5D26

C:\webproject\mysite\polls\migrations 的目录

2019/01/02  14:24   

          .

2019/01/02  14:24   

          ..

2019/01/02  14:24             1,266 0001_initial.py

2019/01/02  11:29                 0 __init__.py

2019/01/02  14:25   

          __pycache__

               2 个文件          1,266 字节

               3 个目录 77,168,365,568 可用字节

(webproject) C:\webproject\mysite>python manage.py sqlmigrate polls 0001_initial   #查看sql语句是否是指定要求的

 

(webproject) C:\webproject\mysite>python manage.py shell   #进入交互式命令行

>>> from django.utils import timezone

>>> from polls.models import Question,Choice

>>> q = Question(question_text="what's new", pub_date=timezone.now())

>>> q.save()

>>> q.id

1

>>> q.pk   #django默认会增加idpk

1

>>> q.question_text

"what's new"

>>> q.pub_date

datetime.datetime(2019, 1, 2, 6, 49, 16, 612213, tzinfo=)

 

>>> from polls.models import Question,Choice

>>> from django.utils import timezone

>>> q = Question.objects.create(question_text="how are you?", pub_date=timezone.now())

>>> q = Question.objects.create(question_text="what's the weather?", pub_date=timezone.now())

>>> q = Question.objects.create(question_text="fuck you!", pub_date=timezone.now())

>>> q

>>> q.was_published_recently()

True

>>> d = timezone.now() - timezone.timedelta(days=2)

>>> q.pub_date = d

>>> q.save()

>>> q.was_published_recently()

False

 

 

常用Field types

 

https://docs.djangoproject.com/en/2.1/ref/models/fields/#choices

 

name = models.CharField(max_length=30)   #实例化时是py中的数据类型

num = models.IntegerField()

website = models.URLField()

email = models.EmailField()

models.AutoField()   #定义AIPK时用

models.BooleanField()

models.TextField()

models.DateField()   #接收pydatetime对象,自动转为sql中的数据结构

models.PositiveIntegerField()   #正数

 

 

Relationship fields

关系:

authors = models.ManyToManyField(Author)   #many-to-many,如用户和组,博客项目中文章和标签;

publisher = models.ForeignKey(Publisher)   #many-to-one,如外键,1个问题有多个选项,1个选项只能属1个问题;如汽车-工厂;

moodels.OneToOneField()   #one-to-one,如Restaurant餐馆和place地点,如丈夫-妻子;

 

 

Field options

field参数:

null   #default is Falsemysql中空值用null表示,不能用''''表示字符串的空串)

blank

choices   #sqlalchemyenum,展示在前端为不能让用户自己定义,而是在下拉列表中选择

default

help_text   #sql中的commentform中的备注信息

primary_key   #默认自动加id作为主键,若显式指定将不会有默认id主键

unique

verbose_name   #若有定义,在form中将把此处定义的值大写,中间的_改为空格,显示为form中的label

 

例:

class Group(models.Model):

    pass

 

class User(models.Model):

    groups = models.ManyToManyField(Group)

 

例:

class Place(models.Model):

    name = models.CharField(max_length=50)

    address = models.CharField(max_length=80)

 

class Restaurant(models.Model):

    place = models.OneToOneField(Place, primary_key=True)

    servers_hot_dogs = models.BooleanField(default=False)

    servers_pizza = models.BooleanField(default=False)

 

例:

class Manufacturer(models.Model):

    pass

 

class Car(models.Model):

    manufacturer = models.ForeignKey(Manufacturer)

 

 

Meta options

 

元编程,改变之前表中定义的元数据信息;

 

abstract   #abstract = Truethis model will be an abstract base class,声明是基类,数据库将不会建此表

db_table   #db_table = 'music_album'指定表名

get_latest_by   #get_latest_by = 'order_date'指定此字段按升序,get_latest_by = ['-priority','order_date']指定priority按降序,order_date按升序;查询时Question.objects.latest()要先定义get_latest_by根据哪个字段走

ordering   #对象的默认顺序,获取对象列表,默认升序,前缀-降序,前缀?随机randomlyordering = ['pub_date']ordering = ['-pub_date', 'author']

unique_together   #联合唯一键,unique_together('driver','restaurant')

indexes   #联合索引

managed

verbose_name   #admin后台中显示的名字

 

 

重写save()方法:

 

from django.db import models

 

class Blog(models.Model):

         name = models.CharField(max_length=100)

         tagline = models.TextField()

 

         def save(self, *args, **kwargs):

                   do_something()

                   super(Blog, self).save(*args, **kwargs)   #import,call the real save() method,一定要调用父类的save(),否则不会保存到数据库

                   do_something()

 

 

模型继承:

 

抽象基类:

若只使用父类中的信息,用继承,而不用在子类模型中重复输入与父类相同的那些字段;

抽象出的基类不会单独使用;

使用Meta optionabstract = True,声明是基类,数据库将不会建此表;.

若子类不实现Meta,默认会继承;

例:

class CommonInfo(models.Model):

    name = models.CharField(max_length=100)

    age = models.PositiveIntegerField()

 

    class Meta:

        abstract = True

        ordering = ['name']

 

class Student(CommonInfo):

    home_group = models.CharField(max_length=5)

 

    class Meta:   #若子类不实现Meta,默认会继承

        db_table = 'student_info'

 

 

多表继承:

若继承一个已存在的模型且想让每个模型都有它自己的数据库表,应使用多表继承;

每一个层级下的每个model都是一个真正意义上完整的model,每个model都有专属的数据库表,都可查询和创建数据库表;

继承关系在子model和它的每个父类之间都添加一个链接,自动创建OneToOneField

父类Place中未在Meta中定义abstract=True,子类Restaurant在查看表结构时,不会继承父类的nameaddress,而是主键place_str_id上有指针指向父类中的字段;

子类继承父类,子类创建的记录,父类中会自动有;

例:

class Place(models.Model):

    name = models.CharField(max_length=50)

    address = models.CharField(max_length=80)

 

class Restaurant(Place):

    servers_hot_dogs = models.BooleanField(default=False)

    servers_pizza = models.BooleanField(default=False)

 

sqlite> .schema publish_place

CREATE TABLE IF NOT EXISTS "publish_place" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(50) NOT NULL, "address" varchar(80) NOT NULL);

sqlite> .schema publish_restaurant

CREATE TABLE IF NOT EXISTS "publish_restaurant" ("place_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "publish_place" ("id"), "servers_hot_dogs" bool NOT NU

LL, "servers_pizza" bool NOT NULL);

 

>>> from publish.models import Place,Restaurant

>>> Place.objects.create(name='tsinghua', address='zhongguancun')

>>> Restaurant.objects.create(name='jia',address='bj',servers_hot_dogs=True,servers_pizza=False)

>>> p0 = Place.objects.get(name='tsinghua')

>>> p1 = Place.objects.get(name='jia')

>>> p2 = Restaurant.objects.get(name='tsinghua')   #X

……"C:\Users\Administrator\py_env\webproject\lib\site-packages\django\db\models\query.py", line 379, in get

    self.model._meta.object_name

publish.models.DoesNotExist: Restaurant matching query does not exist.

>>> p3 = Restaurant.objects.get(name='jia')

>>> p0.restaurant   #X

……"C:\Users\Administrator\py_env\webproject\lib\site-packages\django\db\models\fields\related_descriptors.py", line 404, in __get__

    self.related.get_accessor_name()

django.db.models.fields.related_descriptors.RelatedObjectDoesNotExist: Place has no restaurant.

>>> p1.restaurant

 

 

代理继承:

使用多表继承时,model的每个子类都会创建一张新数据表,因为子类需要一个空间来存储不包含在基类中的字段数据(如servers_hot_dogsservers_pizza),有时只想更改modelpy层的行为实现,如改默认的manager,或添加一个新方法,这时用代理继承;

为原始模型创建一个代理,可创建、删除、更新代理model的实例,而且所有的数据都可象使用原始model一样被保存;

不同之处在于,可在代理model中改变默认的排序设置和默认的manager,更不会对原始model产生影响;

使用Meta optionproxy = True,对代理model的声明;

MyPerson只是一个代理,数据库中不会创建该表,MyPerson类和其父类Person操作同一个数据表,特别之处,Person的实例也可通过MyPerson访问;

例:

class Person(models.Model):

    first_name = models.CharField(max_length=30)

    last_name = models.CharField(max_length=30)

 

class MyPerson(Person):

    class Meta:

        proxy = True

 

    def do_something(self):

        pass

 

>>> from publish.models import Person,MyPerson

>>> p = Person.objects.create(first_name='foobar')

>>> MyPerson.objects.get(first_name='foobar')

 

 

多重继承:

同多表继承,会自动添加2OneToOneField,注意,2个基类的默认id要重新命名,否则添加OneToOneField会有问题,也不允许子类重写父类字段;

例:

class Article(models.Model):

    article_id = models.AutoField(primary_key=True)

 

class Book2(models.Model):

    book_id = models.AutoField(primary_key=True)

 

class Book2Review(Book, Article):

    pass