目录
model 1
model:... 2
常用Field types:... 5
Relationship fields. 5
Field options:... 6
Meta options:... 6
重写save()方法:... 7
模型继承:... 7
抽象基类:... 7
多表继承:... 8
代理继承:... 9
多重继承:... 10
模型的价值在于定义数据模型,使用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',
]
支持sqlite、mysql、postgresql、oracle;
py3.5以上版本,不支持MySQLdb驱动;
可用pymysql,py写的;
可用mysqlclient,c写的,速度快,fork的MySQLdb,官方推荐;
ORM,用py的方法、数据结构,来访问db,可兼容不同的DB;
一个class代表一张表,多对多会产生额外一张关系表;
默认pk为id,也可自定义pk;
表名默认为$APP_NAME$CLASS_NAME.lower(),表名小写(跨平台支持),可重写;
models migrations:
定义好models.py需应用到db,django为了能跟踪表结构的变化,增加了migration版本控制功能,如果没有该功能,需手动编写表结构变化的语句,重新导入数据;
先makemigrations再migrate;
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?") #objects,model默认的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=<UTC>)
>>> 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代表一张表,多对多会产生额外一张关系表;默认pk为id,也可自定义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 <DIR> .
2019/01/02 14:24 <DIR> ..
2019/01/02 14:24 1,266 0001_initial.py
2019/01/02 11:29 0 __init__.py
2019/01/02 14:25 <DIR> __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默认会增加id为pk
1
>>> q.question_text
"what's new"
>>> q.pub_date
datetime.datetime(2019, 1, 2, 6, 49, 16, 612213, tzinfo=<UTC>)
>>> 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
<Question: fuck you!>
>>> q.was_published_recently()
True
>>> d = timezone.now() - timezone.timedelta(days=2)
>>> q.pub_date = d
>>> q.save()
>>> q.was_published_recently()
False
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() #定义AI或PK时用
models.BooleanField()
models.TextField()
models.DateField() #接收py中datetime对象,自动转为sql中的数据结构
models.PositiveIntegerField() #正数
关系:
authors = models.ManyToManyField(Author) #many-to-many,如用户和组,博客项目中文章和标签;
publisher = models.ForeignKey(Publisher) #many-to-one,如外键,1个问题有多个选项,1个选项只能属1个问题;如汽车-工厂;
moodels.OneToOneField(<field-name>) #one-to-one,如Restaurant餐馆和place地点,如丈夫-妻子;
field参数:
null #default is False,mysql中空值用null表示,不能用''(''表示字符串的空串)
blank
choices #同sqlalchemy中enum,展示在前端为不能让用户自己定义,而是在下拉列表中选择
default
help_text #sql中的comment;form中的备注信息
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)
元编程,改变之前表中定义的元数据信息;
abstract #abstract = True,this 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 #对象的默认顺序,获取对象列表,默认升序,前缀-降序,前缀?随机randomly,ordering = ['pub_date'],ordering = ['-pub_date', 'author']
unique_together #联合唯一键,unique_together('driver','restaurant')
indexes #联合索引
managed
verbose_name #admin后台中显示的名字
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 option,abstract = 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在查看表结构时,不会继承父类的name和address,而是主键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')
<Place: Place object>
>>> Restaurant.objects.create(name='jia',address='bj',servers_hot_dogs=True,servers_pizza=False)
<Restaurant: Restaurant object>
>>> 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
<Restaurant: Restaurant object>
使用多表继承时,model的每个子类都会创建一张新数据表,因为子类需要一个空间来存储不包含在基类中的字段数据(如servers_hot_dogs、servers_pizza),有时只想更改model在py层的行为实现,如改默认的manager,或添加一个新方法,这时用代理继承;
为原始模型创建一个代理,可创建、删除、更新代理model的实例,而且所有的数据都可象使用原始model一样被保存;
不同之处在于,可在代理model中改变默认的排序设置和默认的manager,更不会对原始model产生影响;
使用Meta option,proxy = 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')
<MyPerson: MyPerson object>
同多表继承,会自动添加2个OneToOneField,注意,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
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。