Django之models
ORM映射关系
class 表名(models.Model): """ 模型 """ 字段名 = models.DateField() ----> 字段约束
映射关系:
表名 <-------> 类名 字段 <-------> 属性 表记录 <------->类实例对象
验证模型语法是否正确的命令:
python manage.py validate
python manage.py check
check
命令运行Django系统检查框架 - 一组用于验证Django项目的静态检查。如果一切正常,你会看到消息System check identified no issues (0 silenced)
validate 命令检查你的模型的语法和逻辑是否正确。 如果一切正常,你会看到 0 errors found 消息。如果出错,请检查你输入的模型代码。 错误输出会给出非常有用的错误信息来帮助你修正你的模型。
通过logging可以查看翻译成的sql语句:
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
字段
Django模型字段参考
Django模型字段参考 领域 默认的小部件 描述 AutoField N / A 一个IntegerField根据可用的ID自动递增。 BigIntegerField NumberInput 一个64位整数,很像一个IntegerField不同之处在于它是保证从适合数字-9223372036854775808到9223372036854775807 BinaryField N / A 用于存储原始二进制数据的字段。它只支持bytes分配。请注意,此字段的功能有限。 BooleanField CheckboxInput 真实/虚假的领域。如果您需要接受null值,则改为使用NullBooleanField。 CharField TextInput 一个字符串字段,用于从小到大的字符串。对于大量的文本,使用TextField。CharField有一个额外的必要论证:max_length。字段的最大长度(以字符为单位)。 DateField DateInput 一个日期,用Python代表一个datetime.date实例。有两个额外的可选参数:auto_now,每次保存对象时auto_now_add自动将字段设置为现在,当对象第一次创建时自动将字段设置为now。 DateTimeField DateTimeInput 日期和时间,用Python表示的一个datetime.datetime实例。采取相同的额外论据DateField。 DecimalField TextInput 一个固定精度的十进制数,由Python在Decimal实例中表示。有两个必需的参数:max_digits和decimal_places。 DurationField TextInput 一个存储时间的字段 - 用Python在Python中建模timedelta。 EmailField TextInput 甲CharField使用EmailValidator验证输入。max_length默认为254。 FileField ClearableFileInput 一个文件上传字段。有关更多信息FileField,请参阅下一节。 FilePathField Select A CharField的选择仅限于文件系统上某个目录中的文件名。 FloatField NumberInput 一个由Python float实例表示的浮点数。注意当field.localize是False,默认的小部件TextInput ImageField ClearableFileInput 继承所有的属性和方法FileField,但也验证上传的对象是一个有效的图像。其他height和width属性。需要枕头[70]库。 IntegerField NumberInput 一个整数。在-2147483648之间的值2147483647在Django支持的所有数据库中都是安全的。 GenericIPAddressField TextInput 字符串格式的IPv4或IPv6地址(如192.0.2.302a02:42fe :: 4)。 NullBooleanField NullBooleanSelect 像一个BooleanField,但允许NULL作为其中一个选项。 PositiveIntegerField NumberInput 一个整数。2147483647在Django支持的所有数据库中,从0到数值是安全的。 SlugField TextInput S is是一个报纸术语。一个slu is是一个短的标签的东西,只包含字母,数字,下划线或连字符。 SmallIntegerField NumberInput 像一个IntegerField,但只允许某个点下的值。32767在Django支持的所有数据库中,-32768的值是安全的。 TextField Textarea 一个大的文本字段。如果您指定了一个max_length属性,它将反映在自动生成的表单字段的Textarea小部件中。 TimeField TextInput 一段时间,用Python表示一个datetime.time实例。 URLField URLInput A CharField为URL。可选max_length参数。 UUIDField TextInput 用于存储通用唯一标识符的字段。使用Python的UUID类。 关系字段: ForeignKey 多对一的关系。需要一个位置参数:与模型相关的类。要创建一个递归关系 - 一个与自身有多对一关系的对象 - 使用models.ForeignKey('self')。 ManyToManyField 多对多的关系。需要一个位置参数:与模型相关的类,其工作原理与ForeignKey递归和惰性关系完全相同。相关的对象可以添加,删除,或与字段的创建RelatedManager。 OneToOneField 一对一的关系。概念上,这类似于ForeignKey用unique=True,但关系的相反侧将直接返回单个对象。作为以某种方式扩展另一个模型的模型的主键, 需要一个位置参数:与模型相关的
Django通用字段选项
选项 描述 null 如果True,Django将存储NULL数据库中的空值。默认是False。避免使用null诸如CharField和TextField之类的基于字符串的字段,因为空字符串值将始终以空字符串形式存储,而不是以字符串形式存储NULL。对于基于字符串的字段和基于非字符串的字段,如果您希望允许表单中的空值,则还需要设置blank = True。如果您想null使用BooleanField 接受值,请改为使用NullBooleanField。 blank 如果True,该字段被允许为空白。默认是False。请注意,这是不同于null。null纯粹与数据库相关,而空白则与验证相关。 choices 一个可迭代的(例如,一个列表或元组),其自身包含两个项目(例如[(A,B),(A,B)...])的可迭代项目,以用作该字段的选项。如果这是给定的,默认的表单小部件将是一个选择框与这些选择,而不是标准的文本字段。每个元组中的第一个元素是要在模型上设置的实际值,第二个元素是人类可读的名称。 db_column 用于此字段的数据库列的名称。如果没有给出,Django将使用该字段的名称。 db_index 如果True,将为此字段创建一个数据库索引。 db_tablespace 如果此字段已编入索引,则用于此字段索引的数据库表空间的名称。默认值是项目的DEFAULT_INDEX_TABLESPACE设置(如果已设置)或db_tablespace模型(如果有)。如果后端不支持索引的表空间,则忽略此选项。 default 字段的默认值。这可以是一个值或一个可调用的对象。如果可调用,则每次创建新对象时都会调用它。缺省值不能是可变对象(模型实例,列表,集合等),因为对该对象的同一实例的引用将用作所有新模型实例中的默认值。 editable 如果False,该字段将不会显示在管理员或任何其他ModelForm中。在模型验证期间,它们也被跳过。默认值是True。 error_messages 该error_messages参数让您覆盖该字段将引发的默认消息。传入一个与您要覆盖的错误消息匹配的密钥的字典。错误消息键包括null,blank,invalid,invalid_choice,unique和unique_for_date。 help_text 额外的帮助文本与窗体小部件一起显示。即使您的字段没有在表单上使用,对于文档也是有用的。请注意,此值在自动生成的表单中不是 HTML转义的。如果您愿意,可以在help_text中包含HTML。 primary_key 如果True这个字段是模型的主键。如果你没有为模型中的任何字段指定primary_key = True,Django会自动添加一个AutoField来保存主键,所以你不需要在任何字段上设置primary_key = True,除非你想覆盖默认的主键行为。主键字段是只读的。 unique 如果True,这个字段在整个表中必须是唯一的。这是在数据库级和模型验证实施的。此选项在所有字段类型ManyToManyField(OneToOneField和除外)均有效FileField。 unique_for_date 将其设置为DateField的名称或DateTimeField要求此字段对于日期字段的值是唯一的。举例来说,如果你有一个字段title有unique_for_date =” PUB_DATE”,那么Django的不允许的两个记录具有相同的入口title和pub_date。这是Model.validate_unique()在模型验证期间强制执行的,而不是在数据库级。 unique_for_month 喜欢unique_for_date,但要求该领域是相对于本月独一无二的。 unique_for_year 喜欢unique_for_date,但要求该领域是唯一的一年。 verbose_name 该字段的人类可读名称。如果没有给出详细名称,Django将使用字段的属性名称自动创建它,将下划线转换为空格。 validators 要为此字段运行的验证程序列表。
建立模型
作者模型:一个作者有姓名和年龄。
作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)
出版商模型:出版商有名称,所在城市以及email。
书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。
# models.py class Author(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) age=models.IntegerField() # 与AuthorDetail建立一对一的关系 authorDetail=models.OneToOneField(to="AuthorDetail") class AuthorDetail(models.Model): nid = models.AutoField(primary_key=True) birthday=models.DateField() telephone=models.BigIntegerField() addr=models.CharField( max_length=64) class Publish(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) city=models.CharField( max_length=32) email=models.EmailField() class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField( max_length=32) publishDate=models.DateField() price=models.DecimalField(max_digits=5,decimal_places=2) keepNum=models.IntegerField()
commentNum=models.IntegerField() # 与Publish建立一对多的关系,外键字段建立在多的一方 publish=models.ForeignKey(to="Publish",to_field="nid") # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表 authors=models.ManyToManyField(to='Author')
注意事项:
1、 表的名称myapp_modelName
,是根据 模型中的元数据自动生成的,也可以覆写为别的名称
2、id
字段是自动添加的
3、对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名
4、这个例子中的CREATE TABLE
SQL 语句使用PostgreSQL 语法格式,要注意的是Django 会根据settings 中指定的数据库类型来使用相应的SQL 语句。
5、定义好模型之后,你需要告诉Django _使用_这些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py
所在应用的名称。
6、外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。
数据化迁移
注意: 上面的命令告诉Django你已经对你的模型进行了一些改变(在这种情况下,你创建了一个新模型)
python manage.py sqlmigrate books 0001
G:\myObject\blog>python3 manage.py sqlmigrate app01 0001 BEGIN; -- -- Create model Author -- CREATE TABLE "app01_author" ("nid" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(32) NOT NULL, "age" integer NOT NULL); -- -- Create model AuthorDetail -- CREATE TABLE "app01_authordetail" ("nid" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "birthday" date NOT NULL, "telephone" bigint NOT NULL, "addr" varchar(64 ) NOT NULL); -- -- Create model Book -- CREATE TABLE "app01_book" ("nid" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(32) NOT NULL, "publishDate" date NOT NULL, "price" decimal NOT N ULL, "keepNum" integer NOT NULL); CREATE TABLE "app01_book_authors" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "book_id" integer NOT NULL REFERENCES "app01_book" ("nid"), "author_id" i nteger NOT NULL REFERENCES "app01_author" ("nid")); -- -- Create model Publish -- CREATE TABLE "app01_publish" ("nid" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(32) NOT NULL, "city" varchar(32) NOT NULL, "email" varchar(254) NOT NULL); -- -- Add field publish to book -- ALTER TABLE "app01_book" RENAME TO "app01_book__old"; CREATE TABLE "app01_book" ("nid" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(32) NOT NULL, "publishDate" date NOT NULL, "price" decimal NOT NUL L, "keepNum" integer NOT NULL, "publish_id" integer NOT NULL REFERENCES "app01_publish" ("nid")); INSERT INTO "app01_book" ("nid", "title", "publishDate", "price", "keepNum", "publish_id") SELECT "nid", "title", "publishDate", "price", "keepNum", NULL FROM "app01_book__old"; DROP TABLE "app01_book__old"; CREATE INDEX "app01_book_publish_id_d96d3535" ON "app01_book" ("publish_id"); -- -- Add field authorDetail to author -- ALTER TABLE "app01_author" RENAME TO "app01_author__old"; CREATE TABLE "app01_author" ("nid" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(32) NOT NULL, "age" integer NOT NULL, "authorDetail_id" integer N OT NULL UNIQUE REFERENCES "app01_authordetail" ("nid")); INSERT INTO "app01_author" ("nid", "name", "age", "authorDetail_id") SELECT "nid", "name", "age", NULL FROM "app01_author__old"; DROP TABLE "app01_author__old"; COMMIT;
qlmigrate
命令实际上只会显示要进行操作的语句。不会创建表或以其他方式触摸数据库 - 它只是将输出显示在屏幕上,以便您可以查看SQL Django在执行时会执行哪些操作 。
提交数据库
迁移是Django将您对模型进行的更改(添加字段,删除模型等)传播到数据库模式的方式
增删改
添加表记录
普通字段
方式1 publish_obj=Publish(name="人民出版社",city="北京",email="renMin@163.com") publish_obj.save() # 将数据保存到数据库
方式2 返回值publish_obj是添加的记录对象 publish_obj=Publish.objects.create(name="人民出版社",city="北京",email="renMin@163.com")
方式3 以字典传参的方式
Publish.objects.create(**request.POST.dict())
外键字段
方式1: 传入对象 publish_obj=Publish.objects.get(nid=1) Book.objects.create(title="金瓶眉",publishDate="2012-12-12",price=665,pageNum=334,publish=publish_obj) 方式2: 传入对象下的属性 Book.objects.create(title="金瓶眉",publishDate="2012-12-12",price=665,pageNum=334,publish_id=1)
>>> models.Book.objects.create(title="金瓶眉",publishDate="2012-12-12",price=665,keepNum=334, publish=publish_obj) <Book: Book object> >>> publish_obj=models.Publish.objects.get(nid=1) >>> publish_obj <Publish: Publish object> >>> models.Book.objects.create(title="金瓶mei",publishDate="2012-12-12",price=665,keepNum=334, publish=publish_obj) <Book: Book object> >>> models.Book.objects.filter(title='金瓶mei').values() <QuerySet [{'nid': 2, 'title': '金瓶mei', 'publishDate': datetime.date(2012, 12, 12), 'price': Decimal('665.00'), 'keepNum': 334, 'publish_id': 1}]>
既然models模型是以python中的类来建立的。 那么类常用的逻辑,models都应该支持, 比如上面, pulish就是一个类实例化而来 ,那就能调用它的属性。
多对多字段
book_obj=Book.objects.create(title="追风筝的人",publishDate="2012-11-12",price=69,keepNum=314,publish_id=1) author_yuan=Author.objects.create(name="yuan",age=23,authorDetail_id=1) author_egon=Author.objects.create(name="egon",age=32,authorDetail_id=2) book_obj.authors.add(author_egon,author_yuan) # 将某个特定的 model 对象添加到被关联对象集合中。 ======= book_obj.authors.add(*[]) book_obj.authors.create() #创建并保存一个新对象,然后将这个对象加被关联对象的集合中,然后返回这个新对象。
解除关系:
book_obj.authors.remove() # 将某个特定的对象从被关联对象集合中去除。 ====== book_obj.authors.remove(*[]) book_obj.authors.clear() #清空被关联对象集合。
add(obj1[, obj2, ...])
把指定的模型对象添加到关联对象集中。 例如: >>> b = Blog.objects.get(id=1) >>> e = Entry.objects.get(id=234) >>> b.entry_set.add(e) # Associates Entry e with Blog b. 在上面的例子中,对于ForeignKey关系,e.save()由关联管理器调用,执行更新操作。然而,在多对多关系中使用add()并不会调用任何 save()方法,而是由QuerySet.bulk_create()创建关系。 延伸: # 1 *[]的使用 >>> book_obj = Book.objects.get(id=1) >>> author_list = Author.objects.filter(id__gt=2) >>> book_obj.authors.add(*author_list) # 2 直接绑定主键 book_obj.authors.add(*[1,3]) # 将id=1和id=3的作者对象添加到这本书的作者集合中 # 应用: 添加或者编辑时,提交作者信息时可以用到.
create(**kwargs)
创建一个新的对象,保存对象,并将它添加到关联对象集之中。返回新创建的对象: >>> b = Blog.objects.get(id=1) >>> e = b.entry_set.create( ... headline='Hello', ... body_text='Hi', ... pub_date=datetime.date(2005, 1, 1) ... ) # No need to call e.save() at this point -- it's already been saved. 这完全等价于(不过更加简洁于): >>> b = Blog.objects.get(id=1) >>> e = Entry( ... blog=b, ... headline='Hello', ... body_text='Hi', ... pub_date=datetime.date(2005, 1, 1) ... ) >>> e.save(force_insert=True) 要注意我们并不需要指定模型中用于定义关系的关键词参数。在上面的例子中,我们并没有传入blog参数给create()。Django会明白新的 Entry对象blog 应该添加到b中。
remove(obj1[, obj2, ...])
从关联对象集中移除执行的模型对象: >>> b = Blog.objects.get(id=1) >>> e = Entry.objects.get(id=234) >>> b.entry_set.remove(e) # Disassociates Entry e from Blog b. 对于ForeignKey对象,这个方法仅在null=True时存在。
clear()
从关联对象集中移除一切对象。 >>> b = Blog.objects.get(id=1) >>> b.entry_set.clear() 注意这样不会删除对象 —— 只会删除他们之间的关联。 就像 remove() 方法一样,clear()只能在 null=True的ForeignKey上被调用。
set()方法
先清空,在设置,编辑书籍时即可用到
注意 : 对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法。
直接赋值:
通过赋值一个新的可迭代的对象,关联对象集可以被整体替换掉。
>>> new_list = [obj1, obj2, obj3]
>>> e.related_set = new_list
如果外键关系满足null=True,关联管理器会在添加new_list中的内容之前,首先调用clear()方法来解除关联集中一切已存在对象的关联。否则, new_list中的对象会在已存在的关联的基础上被添加
删除表记录
删除方法就是 delete()。它运行时立即删除对象而不返回任何值。例如:
e.delete()
你也可以一次性删除多个对象。每个 QuerySet 都有一个 delete() 方法,它一次性删除 QuerySet 中所有的对象。
例如,下面的代码将删除 pub_date 是2005年的 Entry 对象:
Entry.objects.filter(pub_date__year=2005).delete()
要牢记这一点:无论在什么情况下,QuerySet 中的 delete() 方法都只使用一条 SQL 语句一次性删除所有对象,而并不是分别删除每个对象。如果你想使用在 model 中自定义的 delete() 方法,就要自行调用每个对象的delete 方法。(例如,遍历 QuerySet,在每个对象上调用 delete()方法),而不是使用 QuerySet 中的 delete()方法。
在 Django 删除对象时,会模仿 SQL 约束 ON DELETE CASCADE 的行为,换句话说,删除一个对象时也会删除与它相关联的外键对象。例如:
b = Blog.objects.get(pk=1) # This will delete the Blog and all of its Entry objects. b.delete()
要注意的是: delete() 方法是 QuerySet 上的方法,但并不适用于 Manager 本身。这是一种保护机制,是为了避免意外地调用 Entry.objects.delete() 方法导致 所有的 记录被误删除。如果你确认要删除所有的对象,那么你必须显式地调用:
Entry.objects.all().delete()
如果不想级联删除,可以设置为:
pubHouse = models.ForeignKey(to='Publisher', on_delete=models.SET_NULL, blank=True, null=True)
修改表记录
注意:
<1> 第二种方式修改不能用get的原因是:update是QuerySet对象的方法,get返回的是一个model对象,它没有update方法,而filter返回的是一个QuerySet对象(filter里面的条件可能有多个条件符合,比如name='alvin',可能有两个name='alvin'的行数据)。
<2>在“插入和更新数据”小节中,我们有提到模型的save()方法,这个方法会更新一行里的所有列。 而某些情况下,我们只需要更新行里的某几列。
此外,update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录update()方法会返回一个整型数值,表示受影响的记录条数。
注意,这里因为update返回的是一个整形,所以没法用query属性;对于每次创建一个对象,想显示对应的raw sql,需要在settings加上日志记录部分