Django---model基础(单表)

ORM

一、映射关系:

          表名<--------------->类名
          字段<-------------->属性
          表记录<----------->类实例对象

创建表(建立表模型)

二、单表

class Book(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    authors = models.CharField(max_length=32)
    publishDate = models.DateField()
    price = models.DecimalField(max_digits=5, decimal_places=2)

1.通过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',
        },
    }
}
 1、models.AutoField  自增列= int(11)
    如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。
 2、models.CharField  字符串字段
    必须 max_length 参数
 3、models.BooleanField  布尔类型=tinyint(1)
    不能为空,Blank=True
 4、models.ComaSeparatedIntegerField  用逗号分割的数字=varchar
    继承CharField,所以必须 max_lenght 参数
 5、models.DateField  日期类型 date
   对于参数,auto_now =True则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
 6、models.DateTimeField  日期类型 datetime
   同DateField的参数
 7、models.Decimal  十进制小数类型= decimal
   必须指定整数位max_digits和小数位decimal_places
 8、models.EmailField  字符串类型(正则表达式邮箱)=varchar
   对字符串进行正则表达式
 9、models.FloatField  浮点类型= double
10、models.IntegerField  整形 11、models.BigIntegerField  长整形   integer_field_ranges ={     'SmallIntegerField':(-32768,32767),      'IntegerField':(-2147483648,2147483647),     'BigIntegerField':(-9223372036854775808,9223372036854775807),     'PositiveSmallIntegerField':(0,32767),     'PositiveIntegerField':(0,2147483647),   } 12、models.IPAddressField  字符串类型(ip4正则表达式) 13、models.GenericIPAddressField  字符串类型(ip4和ip6是可选的)   参数protocol可以是:both、ipv4、ipv6   验证时,会根据设置报错 14、models.NullBooleanField  允许为空的布尔类型 15、models.PositiveIntegerFiel  正Integer 16、models.PositiveSmallIntegerField  正smallInteger 17、models.SlugField  减号、下划线、字母、数字 18、models.SmallIntegerField  数字   数据库中的字段有:tinyint、smallint、int、bigint 19、models.TextField  字符串=longtext 20、models.TimeField  时间 HH:MM[:ss[.uuuuuu]] 21、models.URLField  字符串,地址正则表达式 22、models.BinaryField  二进制 23、models.ImageField图片 24、models.FilePathField文件

添加表记录

三、

1.添加表记录(save和create)

方式一:book_obj=models.Book(title=title)
              book_obj.save() #将数据保存到数据库

方式二:book_obj=models.Book.objects.create(title=title)

2.查询

1.all       查询所有结果            用法:models.表名.objects.all()      结果是QuerySet集合    [model对象]
2.filter             查询所给筛选匹配的对象       用法:models.表名.objects.filter()                 结果是:QuerySet集合     如:ret=models.表名.objects.filter(auther='mqj',price=123)
3.get                查询所给筛选匹配的对象,返回值只有一个,如果筛选的对象超过一个或没有就会报错      用法:models.表名.objects.get()    结果是:model对象         如:ret=models.表名.objects.get(auther="yuan")
4.exclude        包含筛选条件你匹配的对象  用法:ret=models.表名.objects.exclude
(author="yuan")
5.values 方法  返回的是列表中一个一个的可迭代字典  返回的是列表中一个一个的可迭代字典      用法:ret=models.表名.objects.filter(author="yuan").value("title","price")
6.values_list 方法   返回的是列表中一个一个的元组序列         用法:ret=models.表名.objects.filter(author="yuan").value_list("title","price")
7.reverse():对查询的结果反向排序
8.order_by():对查询的结果排序
9.ddistinct(): 返回的结果中剔除重复记录
10.count():    返回数据库匹配查询数量               用法:ret=models.Book.objects.filter(author="yuan").count()
11.first():      返回第一条记录                             用法:ret = models.Book.objects.all().first()
12.last():       返回最后一条记录                          用法:ret = models.Book.objects.all().last()
13.exists():    返回True或False                          用法:ret=models.Book.objects.all().existst()

3、双下划线之单表查询:

models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值

models.Tb1.objects.filter(id__in=[11,22,33]) # 获取id等于11、22、33的数据

models.Tb1.objects.filter(name__contains="ven")

models.Tb1.objects.filter(name__icontains="ven")

models.Tb1.obiects.filter(id__range=[1,2])   #范围bettwen and


startswith,istartswith,endswith,iendswith

4.修改

修改方式1:save(效率低)
如:   book_obj=models.Book.objects.filter(nid=id)[0]
             book_obj.title="金平"
            book_obj.save()
修改方式2:
        title=request.POST.get("title")
        authors=request.POST.get("authors")
        pubDate=request.POST.get("pubDate")
        price=request.POST.get("price")
        models.Book.objects.filter(nid=id).update(title=title,authors=authors,publishDate=pubDate,price=price)

5.删除:

     delect

了不起的双下划线:
                models.表名.objects.filter(id__gt=10)
                models.表名.objects.filter(title__startswith="py")
                models.Tb1.objects.filter(id__range=[1, 2]) 
                models.Tb1.objects.filter(id__in=[11, 22, 33])

 四、表关联操作

实例:我们来假定下面这些概念,字段和关系

作者模型:一个作者有姓名和年龄。

作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)

出版商模型:出版商有名称,所在城市以及email。

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

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)
    publish = models.ForeignKey("Publish", related_name="bookList")
    authorlist = models.ManyToManyField("Author", related_name="bookList")
    def __str__(self):
        return self.title
class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=32) def __str__(self): return self.name
class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() def __str__(self): return self.name
class AuthorDetail(models.Model): tel=models.IntegerField() addr=models.CharField(max_length=32) author=models.OneToOneField("Author",related_name="authorList")

 表关系:

      1.一对多

      2.一对一

      3.多对多

添加记录:
   一对多:
     创建一对多:
                publish=models.ForeignKey("Publish",related_name="bookList")
         添加记录方式1:
                               models.Book.objects.create(publish_id=1)
         添加记录方式2:
                              pubObj=models.Publish.objects.filter(name="人民出版社")[0]
                              models.Book.objects.create(publish=pubObj)  # 关联的出版社对象

 多对多:
         创建多对多关系:
               authorlist=models.ManyToManyField("Author",related_name="bookList")
         多对多添加记录:
               book_obj=models.Book.objects.create(title="追风筝的人", price=100, publishDate="2017-12-12", publish_id=2)
               alex_obj=models.Author.objects.filter(name="alex")[0]
               egon_obj=models.Author.objects.filter(name="egon")[0]
                 
                book_obj.authorlist.add(alex_obj,egon_obj)
查询记录:
         正向查询:
         一对多:
               linux_obj=models.Book.objects.filter(title="linux").first()
               print(linux_obj.publish.name)  # 与这本书对象关联的出版社对象的名字
         多对多:
               linux_obj=models.Book.objects.filter(title="linux").first()
               print(linux_obj.authorlist.all()) # 与这本书关联的所有作者对象集合
         反向查询:
          #一对多的反向查询:
                    eg:人民出版社出版过的书籍的名字
                    publish_obj=models.Publish.objects.filter(name="人民出版社")[0]
                    print(publish_obj.bookList.all()) # 与该年出版社关联的所有书籍对象的集合 
                    #多对多的反向查询:
                    查询yuan出版过的所有书籍的名字和价格:
                    author_yuan=models.Author.objects.get(name="yuan")
                    print(author_yuan.bookList.all())  # 与该作者关联的所有书籍书籍对象的集合

 2.基于对象的查询

基于对象关联查询:    
    
    if 一对多查询(Book--Publish):
          正向查询,按字段:
          book_obj.publish   :  与这本书关联的出版社对象    book_obj.publish.addr: 与这本书关联的出版社的地址
          反向查询,按表名_set
          publish_obj.book_set: 与这个出版社关联的书籍对象集合    publish_obj.book_set.all() :[obj1,obj2,....]    
    
    if 一对一查询(Author---AuthorDetail):
          正向查询,按字段:
          author_obj.ad : 与这个作者关联的作者详细信息对象
          
          反向查询:按表名:
          author_detail_obj.author  : 与这个作者详细对象关联的作者对象
          
    if  多对多(Book----Author):

        正向查询,按字段:  
        
        book_obj.authorList.all(): 与这本书关联的所有这作者对象的集合  [obj1,obj2,....]
        
        反向查询,按表名_set:
        author_obj.book_set.all() : 与这个作者关联的所有书籍对象的集合

3.双下划线的跨表查询 

查询python这本书出版社的地址
    # 方式一:
    # book_obj=models.Book.objects.filter(title="python").first()
    # print(book_obj.publish.name)

    # 方式二(双下划线):
    # book_obj=models.Book.objects.filter(title="python").values("publish__addr")
    # print(book_obj)

    # 方式三(双下划线):
    # book_obj=models.Publish.objects.filter(bookList__title="python").values("addr")
    # print(book_obj)
    
 查询老男孩出版社出版过的所有书籍的名字与价格
    # 方式一:
    # book_obj=models.Publish.objects.filter(name="老男孩出版社").first()
    # print(book_obj.bookList.all().values("title","price"))


    # 方式二:(双下划线)
    # book_obj=models.Publish.objects.filter(name="老男孩出版社").values("bookList__title","bookList__price")
    # print(book_obj)

    # 方式三(双下划线):
    # book_obj=models.Book.objects.filter(publish__name="老男孩出版社").values("title","price")
    # print(book_obj)

    # egon出版过的所有书籍名称以及出版社名称
    # book_obj=models.Author.objects.filter(name="egon").values("bookList__title","bookList__authorlist__name")
    # print("book_obj",book_obj)

查询egon出过的所有书籍的名字(多对多)
    book_obj=models.Author.objects.filter(name="egon").values("bookList__title")
    print(book_obj)

    book_obj=models.Book.objects.filter(authorlist__name="egon").values("title")
    print(book_obj)

手机号以151开头的作者出版过的所有书籍名称以及出版社名称

    # book_obj=models.AuthorDetail.objects.filter(tel__startswith="151").first()
    # print(book_obj.author.bookList.all().values("title","publish__name"))

    # 方法2
    # models.Book.objects.filter(authorlist__author_detail__tel__startswith="151").values("title", "publish__name")
if 一对多查询(Book--Publish):
        正向查询,按字段:        
        # 查询linux这本书的出版社的名字:
        models.Book.objects.all().filter(title="linux").values("publish__name")
        反向查询:按表名:
        # 查询人民出版社出版过的所有书籍的名字
        models.Publish.objects.filter(name="人民出版社出版").values("book__title")
        
    if 一对一查询(Author---AuthorDetail):
         正向查询,按字段:
        models.Author.objects.filter(name="egon).values("ad__tel")
        反向查询:按表名:
        models.AuthorDetail.objects.filter(tel="151").values("author__name")
        
    if  多对多(Book----Author):
        正向查询,按字段:
        models.Book.objects.filter(title="python").values("authorList__name")     [{},{},{},{}]
        
        正向查询,按表名:
        models.Author.objects.filter(name="alex").values("book__price")
    

注意:

 publish=models.ForeignKey("Publish",related_name="bookList")
 authorlist=models.ManyToManyField("Author",related_name="bookList") 
 ad=models.models.OneToOneField("AuthorDetail",related_name="authorInfo")
 
 反向查询的时候都用:related_name

 4.查询

一对多的查询
    # 查询linux这本书的出版社的地址?

    #linux_obj=models.Book.objects.filter(title="linux").first()
    #
    # print(linux_obj.title)
    # print(linux_obj.price)
    # print(linux_obj.publishDate)
    #
    # print(linux_obj.publish.name)  # 与这本书对象关联的出版社对象
    #print(linux_obj.publish.addr)  # 与这本书对象关联的出版社对象

    # 人民出版社出版过的书籍的名字
    # publish_obj=models.Publish.objects.filter(name="人民出版社")[0]
    # print(publish_obj.bookList.all())  # 与这个出版社对象关联的所有书籍对象


多对多的查询

    # 查询追风筝的人的所有作者的姓名和年龄

    # book_obj=models.Book.objects.filter(title="追风筝的人")[0]
    # print("=====",book_obj.authorlist.all()  )         #  与这本书关联的所有作者对象,集合对象
    # authorlist=book_obj.authorlist.all()
    # print(authorlist.values("name","age"))

    # 查询yuan出版过的所有书籍的名字和价格

    #author_yuan=models.Author.objects.get(name="yuan")

    #print(author_yuan.book_set.all())  # 与这个作者关联的所有书籍对象
    #print(author_yuan.bookList.all().values("title","price"))

一对一关系查询

  正向查询

    #查询手机号为456的作者的姓名

    # ad=models.AuthorDetail.objects.filter(tel="456").first()
    # print(ad.author.name)


    #detail_obj=models.AuthorDetail.objects.filter(tel="456").first()
    # print(detail_obj.author.name)#  与tel="456"的Author2Detail关联的作者对象
    #
    反向查询
    #  查询景丽洋的手机号
    # author_obj=models.AuthorA.objects.filter(name="景丽洋").first()
    # print(author_obj.author2detail.tel) # 789
    # print(author_obj.abc.tel) # 789    

5.添加

一对多的添加
    # 方式1
    #models.Book.objects.create(title="python",price=100,publishDate="2017-12-12",publish_id=1)

    # 方式2
    # pubObj=models.Publish.objects.filter(name="人民出版社")[0]
    # models.Book.objects.create(title="python2",price=120,publishDate="2017-10-12",publish=pubObj)  # 关联的出版社对象

多对多的添加
    #book_obj=models.Book.objects.create(title="红楼梦", price=100, publishDate="2017-12-12", publish_id=2)

    # alex_obj=models.Author.objects.filter(name="alex")[0]
    # egon_obj=models.Author.objects.filter(name="egon")[0]
    # egon_obj=models.Author.objects.filter(name="yuan")[0]
    # print("======",book_obj.authorlist) # []
    # authorList=models.Author.objects.all()
    绑定多对多的关系
       # #book_obj.authorlist.add(alex_obj,egon_obj)  # [alex_obj,egon_obj]
    # book_obj.authorlist.add(*authorList)  # [alex_obj,egon_obj]


解除多对多的关系

    # book_obj=models.Book.objects.filter(title="红楼梦").first()
    # authorList=models.Author.objects.filter(id__lt=3)
    # print(book_obj.authorlist.remove(*authorList))


清除关系方法
    # book_obj = models.Book.objects.filter(title="红楼梦").first()
    # book_obj.authorlist.clear()

五、聚合函数

from django.db.models import Avg,Sum,Count,Max,Min

聚合函数:aggregate
    # 查询所有图书的价格和

    ret=models.Book.objects.all().aggregate(priceSum=Sum("price"))
    ret=models.Book.objects.all().aggregate(priceAvg=Avg("price"),priceSum=Sum("price"))
    print(ret) # {'price__sum': Decimal('166.00')}

分组函数 annote函数

    # 查询每一本书的作者个数

    book_list=models.Book.objects.all().annotate(c=Count("authorlist__name"))
    for book_obj in book_list:
        print(book_obj.c)


    # 查询每一个出版社出版过的最便宜的书籍
            ret=models.Book.objects.all().annotate(Min("price"))
        print(ret)
统计不止一个作者的图书:
             queryResult=Book.objects
          .annotate(num_authors=Count('authors'))
          .filter(num_authors__gt=1) 
查询各个作者出的书的总价格:
# 按author表的所有字段 group by
    queryResult=Author.objects
              .annotate(SumPrice=Sum("book__price"))
              .values_list("name","SumPrice") print(queryResult) #按authors__name group by queryResult2=Book.objects.values("authors__name")
              .annotate(SumPrice=Sum("price"))
              .values_list("authors__name","SumPrice") print(queryResult2)

分组查询:
    querySet().annotate() --- 返回的是querySet
    
    #统计每一个出版社中最便宜的书籍的价格
    
    sql:
       select Min(price) from book group by publish_id;
    
    ORM:
    
    models.Book.objects.values("publish__name").annotate(Min("price"))

六、F查询与Q查询

F查询

1.查询评论数大于收藏数的书籍:

 from django.db.models import F
   Book.objects.filter(commnetNum__lt=F('keepNum'))

2. 查询评论数大于收藏数2倍的书籍

 Book.objects.filter(commnetNum__lt=F('keepNum')*2)

3.修改操作也可以使用F函数,比如将每一本书的价格提高30元:

Book.objects.all().update(price=F("price")+30) 

Q查询

filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 Q

 from django.db.models import Q

Q(title__startswith='Py')
bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))

你可以组合& 和|  操作符以及使用括号进行分组来编写任意复杂的Q 对象。NOT) 查询:

bookList=Book.objects.filter(Q(authors__name="yuan") & ~Q(publishDate__year=2017)).values_list("title")

查询函数可以混合使用Q 对象和关键字参数。例如:

bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017),
                                  title__icontains="python"
                                 )

 补充:

有关Django中的命令:

下载Django:pip3 install Django
          创建一个djang project:django-admin.py startptoject 项目名称;
          在目录下创建应用:python manage.py startapp blog;
          启动Django项目:python manage.py runserver 端口;

         python manage.py syncdb
注意:Django 1.7.1 及以上的版本需要用以下命令
        python manage.py makemigrations
        python manage.py migrate

'''
    python manage.py createsuperuser
     
    # 按照提示输入用户名和对应的密码就好了邮箱可以留空,用户名和密码必填
     
    # 修改 用户密码可以用:
    python manage.py changepassword username
    
'''
注意:
       对象可以调用自己的属性