Django基础之数据库与ORM

一.数据库配置

1.django默认支持sqlite,mysql, oracle,postgresql数据库。

  • django默认使用sqlite的数据库,默认自带sqlite的数据库驱动 , 引擎名称:django.db.backends.sqlite3
  • 引擎名称:django.db.backends.mysql

2.在django的项目中会默认使用sqlite数据库,在settings里有如下设置:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

 如果我们想要更改为MySQL数据库,需要修改如下:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', 
        'NAME': 'books',    #你的数据库名称
        'USER': 'root',   #你的数据库用户名
        'PASSWORD': '', #你的数据库密码
        'HOST': '', #你的数据库主机,留空默认为localhost
        'PORT': '3306', #你的数据库端口
    }
}

 注意:

  NAME即数据库的名字,在mysql连接前该数据库必须已经创建,而上面的sqlite数据库下的db.sqlite3则是项目自动创建
  USER和PASSWORD分别是数据库的用户名和密码。
  设置完后,再启动我们的Django项目前,我们需要激活我们的mysql。
  然后,启动项目,会报错:no module named MySQLdb
  这是因为django默认你导入的驱动是MySQLdb,可是MySQLdb对于py3有很大问题,所以我们需要的驱动是PyMySQL
  所以,我们只需要找到项目名文件下的__init__,在里面写入:
    import pymysql
    pymysql.install_as_MySQLdb()

 二.ORM表模型

  作者模型:一个作者有姓名。

  作者详细模型:把作者的详情放到详情表,包含姓名,email地址,作者详情模型和作者模型之间是一对一的关系(one-to-one)(类似于每个人和他的身份证之间的关系),在大多数情况下我们没有必要将他们拆分成两张表,这里只是引出一对一的概念。

  出版商模型:出版商有名称,地址。

  书籍模型:书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many),一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many),也被称作外键。

  代码如下:

  

from django.db import models

# 作者表
class Author(models.Model):
    name = models.CharField(max_length=30)
    email = models.EmailField()
    def __str__(self):
        return self.name

# 出版社
class Publisher(models.Model):
    press = models.CharField(max_length=30)
    press_address = models.CharField(max_length=30)

# book
class Book(models.Model):
    title = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=5, decimal_places=2, default=10)
    publication_date = models.DateField()
    author = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)  # 数据库存的是publish_id
    def __str__(self):
        return self.title

 分析代码:

  <1>  每个数据模型都是django.db.models.Model的子类,它的父类Model包含了所有必要的和数据库交互的方法。并提供了一个简介漂亮的定义数据库字段的语法。

       <2>  每个模型相当于单个数据库表(多对多关系例外,会多生成一张关系表),每个属性也是这个表中的字段。属性名就是字段名,它的类型(例如CharField)相当于数据库的字段类型(例如varchar)。大家可以留意下其它的类型都和数据库里的什么字段对应。

       <3>  模型之间的三种关系:一对一,一对多,多对多。

             一对一:实质就是在主外键(author_id就是foreign key)的关系基础上,给外键加了一个UNIQUE=True的属性;

             一对多:就是主外键关系;(foreign key)

             多对多:(ManyToManyField) 自动创建第三张表(当然我们也可以自己创建第三张表:两个foreign key)

2.1ORM之增加

from app01.models import *

    #create方式一:   Author.objects.create(name='Alvin')

    #create方式二:   Author.objects.create(**{"name":"alex"})

    #save方式一:     author=Author(name="alvin")
                            author.save()

    #save方式二:     author=Author()
                            author.name="alvin"
                            author.save()

 重点来了------->那么如何创建存在一对多或多对多关系的一本书的信息呢?(如何处理外键关系的字段如一对多的publisher和多对多的authors)

#一对多(ForeignKey):

    #方式一: 由于绑定一对多的字段,比如publish,存到数据库中的字段名叫publish_id,所以我们可以直接给这个
    #       字段设定对应值:
           Book.objects.create(title='php',
                               publisher_id=2,   #这里的2是指为该book对象绑定了Publisher表中id=2的行对象
                               publication_date='2017-7-7',
                               price=99)


    #方式二:
    #       <1> 先获取要绑定的Publisher对象:
        pub_obj=Publisher(name='河大出版社',address='保定',city='保定',
                state_province='河北',country='China',website='http://www.hbu.com')
    OR  pub_obj=Publisher.objects.get(id=1)

    #       <2>将 publisher_id=2 改为  publisher=pub_obj

#多对多(ManyToManyField()):

    author1=Author.objects.get(id=1)
    author2=Author.objects.filter(name='alvin')[0]
    book=Book.objects.get(id=1)
    book.authors.add(author1,author2)
    #等同于:
    book.authors.add(*[author1,author2])
    book.authors.remove(*[author1,author2])
    #-------------------
    book=models.Book.objects.filter(id__gt=1)
    authors=models.Author.objects.filter(id=1)[0]
    authors.book_set.add(*book)
    authors.book_set.remove(*book)
    #-------------------
    book.authors.add(1)
    book.authors.remove(1)
    authors.book_set.add(1)
    authors.book_set.remove(1)

#注意: 如果第三张表是通过models.ManyToManyField()自动创建的,那么绑定关系只有上面一种方式
#     如果第三张表是自己创建的:
     class Book2Author(models.Model):
            author=models.ForeignKey("Author")
            Book=  models.ForeignKey("Book")
#     那么就还有一种方式:
            author_obj=models.Author.objects.filter(id=2)[0]
            book_obj  =models.Book.objects.filter(id=3)[0]

            s=models.Book2Author.objects.create(author_id=1,Book_id=2)
            s.save()
            s=models.Book2Author(author=author_obj,Book_id=1)
            s.save()

 2.2ORM之删除(delete)

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

 我们表面上删除了一条信息,实际却删除了三条,因为我们删除的这本书在Book_authors表中有两条相关信息,这种删除方式就是django默认的级联删除。

2.3ORM之改(update和save)

 实例:

注意:

 <1> 第二种方式修改不能用get的原因是:update是QuerySet对象的方法,get返回的是一个model对象,它没有update方法,而filter返回的是一个QuerySet对象(filter里面的条件可能有多个条件符合,比如name='alvin',可能有两个name='alvin'的行数据)。

 <2>在“插入和更新数据”小节中,我们有提到模型的save()方法,这个方法会更新一行里的所有列。 而某些情况下,我们只需要更新行里的某几列。

#---------------- update方法直接设定对应属性----------------
    models.Book.objects.filter(id=3).update(title="PHP")
    ##sql:
    ##UPDATE "app01_book" SET "title" = 'PHP' WHERE "app01_book"."id" = 3; args=('PHP', 3)


#--------------- save方法会将所有属性重新设定一遍,效率低-----------
    obj=models.Book.objects.filter(id=3)[0]
    obj.title="Python"
    obj.save()
# SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price", 
# "app01_book"."color", "app01_book"."page_num", 
# "app01_book"."publisher_id" FROM "app01_book" WHERE "app01_book"."id" = 3 LIMIT 1; 
# 
# UPDATE "app01_book" SET "title" = 'Python', "price" = 3333, "color" = 'red', "page_num" = 556,
# "publisher_id" = 1 WHERE "app01_book"."id" = 3;

此外,update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录update()方法会返回一个整型数值,表示受影响的记录条数。

注意,这里因为update返回的是一个整形,所以没法用query属性;对于每次创建一个对象,想显示对应的raw sql,需要在settings加上日志记录部分:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}
原文地址:https://www.cnblogs.com/Crazy-lyl/p/7450831.html