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 命令检查你的模型的语法和逻辑是否正确。 如果一切正常,你会看到 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',
        },
    }
}  
settings文件里设置

字段

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;
View Code

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加上日志记录部分

posted @ 2017-12-07 22:22  总有问题刁难朕  阅读(1247)  评论(0编辑  收藏  举报