zoukankan      html  css  js  c++  java
  • Django(四):model

    一、创建model

      django.db.models是django自带的创建数据库的ORM。

      在models.py中以继承models.Model创建表后,需要在setttngs中确保添加了当前应用,并执行

        python3 manage.py makemigrations app[应用名称]

        python3 manage.py migrate app[应用名称]

      来生成迁移文件并提交到数据库执行建表操作。

      一、创建单张表

    # models.py
    from django.db import models
    class Person(models.Model): name = models.CharField(max_length=30) age = models.CharField(max_length=30)
    from app02.models import Person
    p1 = Person(name="Jan", age=20)   # 声明一个实例,也就是一条记录
    p1.save() # 必须保存
    p2 = Person()
    p2.name = "Li"   
    p2.age = 18    # 可以声明一个实例,也可以修改一个字段,同样需要提交
    p2.save()

      二、创建一对一表

      当一张既有的表需要扩充字段时,为了保持原有的表字段和结构不变,可以创建另一张表存储扩充的字段;第二张表的主键和第一张表的主键一一对应。

    # models.py
    from django.db import models
    
    class Place(models.Model):
        name = models.CharField(max_length=50)
        address = models.CharField(max_length=80)

    class Restaurant(models.Model): place = models.OneToOneField(Place,on_delete=models.CASCADE,primary_key=True) serves_hot_dogs = models.BooleanField(default=False) serves_pizza = models.BooleanField(default=False)
    >>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
    >>> p1.save()
    >>> p2 = Place(name='Ace Hardware', address='1013 N. Ashland')
    >>> p2.save()
    >>> r1 = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False) # 插入记录时,如果需要同时插入扩充的字段,就在后面继续添加扩充表 >>> r1.save()
    >>> p1.restaurant
    >>> r2.place
    >>> hasattr(p2, 'restaurant') # 可以用hasattr检查是否已插入扩充字段

      三、创建多对一表

    # models.py
    from django.db import models
    
    class Reporter(models.Model):
        first_name = models.CharField(max_length=30)
        last_name = models.CharField(max_length=30)
        email = models.EmailField()
    class Article(models.Model):
        headline = models.CharField(max_length=100)
        pub_date = models.DateField()
        reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
    >>> r1 = Reporter(first_name='John', last_name='Smith',
    email='john@example.com')
    >>> r1.save()    # 一定要save,否则下面的Article外键无法绑定需要的reporter字段
    >>> r2 = Reporter(first_name='Paul', last_name='Jones', email='paul@example.com')
    >>> r2.save()
    >>> from datetime import date
    >>> a1 = Article(id=None, headline="This is a test", pub_date=date(2005, 7, 27), reporter=r1)      # 正向添加-添加记录时需要指定reporter
    >>> a1.save()
    >>> a2 = Article.objects.create(headline="Paul's story", pub_date=date(2006, 1, 17), reporter=r2) # 正向添加-用管理器的方式添加,不需要save()
    >>> r2.article_set.create(headline="John's second story", pub_date=date(2005, 7, 29)) # 反向添加-注意r2.article_set的方式
    >>> r3 = Reporter(first_name="Jan", last_name="--", email="jan@example.com")
    >>> r3.save()
    >>> r3.article_set.add(a2) # 反向添加一个对象
    >>> r3.artilce_set.remove(a2) # 反向删除

      add()和remove()是django默认的用于处理一对多或者多对多的增删操作。对于ForeignKey,只有“一”的那张表可以使用add和remove来一次性添加一个或者多个“多”的记录。对于ManyToManyField,两张表都可以使用add和remove添加或者删除一个或者多个记录。

      四、创建多对多表

    # models.py
    from django.db import models
    
    class Publication(models.Model):
        title = models.CharField(max_length=30)
        def __str__(self):
            return self.title
        class Meta:
            ordering = ('title',)
    
    class Article(models.Model):
        headline = models.CharField(max_length=100)
        publications = models.ManyToManyField(Publication)
        def __str__(self):
            return self.headline
        class Meta:
            ordering = ('headline',)
    >>> p1 = Publication(title='The Python Journal')
    >>> p1.save()
    >>> p2 = Publication(title='Science News')
    >>> p2.save()
    >>> p3 = Publication(title='Science Weekly')
    >>> p3.save()
    >>> a1 = Article(headline='Django lets you build Web apps easily')
    >>> a1.save()
    >>> a1.publications.add(p1,p2,p3) # 直接用add添加一个或多个记录
    >>> a2 = Article(headline='NASA uses Python') >>> a2.save()
    >>>
    new_publication = a2.publications.create(title='Highlights for Children') # 或者直接用管理器(models.objects.create)创建一条记录并添加进去
    >>> p2.article_set.all() # 可以通过article_set访问
    >>> a4 = Article(headline='NASA finds intelligent life on Earth') # 反向添加记录:可以先写好记录,再添加给另一张表 >>> a4.save() >>> p2.article_set.add(a4)
    >>> new_article = p2.article_set.create(headline='Oxygen-free diet works wonders') # 或者也用管理器的方式添加

    二、Field和字段

     名称  解释
    AutoField 一个根据实际ID自动增长的IntegerField,通常不指定;如果不指定,一个主键字段将自动添加到模型中
    BooleanField true/false 字段,此字段的默认表单控制是CheckboxInput 
    NullBooleanField 支持null、true、false三种值
    CharField(max_length=字符长度) 字符串,默认的表单样式是 TextInput
    TextField 大文本字段,一般超过4000使用,默认的表单控件是Textarea
    IntegerField 整数
    DecimalField(max_digits=None, decimal_places=None) 使用python的Decimal实例表示的十进制浮点数;DecimalField.max_digits=位数总数,DecimalField.decimal_places=小数点后的数字位数
    FloatField 用Python的float实例来表示的浮点数
    DateField[auto_now=False, auto_now_add=False])

    使用Python的datetime.date实例表示的日期;

    参数DateField.auto_now:每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false;

    参数DateField.auto_now_add:当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false

    该字段默认对应的表单控件是一个TextInput. 在管理员站点添加了一个JavaScript写的日历控件,和一个“Today"的快捷按钮,包含了一个额外的invalid_date错误消息键

    auto_now_add, auto_now, and default 这些设置是相互排斥的,他们之间的任何组合将会发生错误的结果

    TimeField 使用Python的datetime.time实例表示的时间,参数同DateField
    DateTimeField 使用Python的datetime.datetime实例表示的日期和时间,参数同DateField
    FileField 一个上传文件的字段
    ImageField 继承了FileField的所有属性和方法,但对上传的对象进行校验,确保它是个有效的image

       通过字段选项,可以实现对字段的约束;在字段对象时通过关键字参数指定。

     名称 解释
    null 如果为True,Django 将空值以NULL 存储到数据库中,默认值是 False
    blank 如果为True,则该字段允许为空白,默认值是 False;对比:null是数据库范畴的概念,blank是表单验证证范畴的
    db_column 字段的名称,如果未指定,则使用属性的名称
    db_index 若值为 True, 则在表中会为此字段创建索引
    default 默认值
    primary_key:若为 True 则该字段会成为模型的主键字段
    unique 如果为 True, 这个字段在表中必须有唯一值;唯一索引
    auto_now 创建时生成创建时间
    auto_now_add 更新时自动更新当前时间
    choices admin: 默认元组列表,user_type=[(1, "普通用户"), (2, "VIP用户"), (3, "超级用户")];modesl.IntegerField(choices=user_type);在admin中会自动显示这几个分类,但是对表无影响,可以是任意整数
    verbose_name admin: 别名,支持中文
    editable admin: 是否可以被编辑
    error_message admin: 自定义错误信息
    help_text admin: 帮助信息

    三、自定义管理器

      objects是Manager类型的对象,用于与数据库进行交互。当定义模型类时没有指定管理器,则Django会为模型类提供一个名为objects的管理器,当为模型类指定管理器后,django不再为模型类生成名为objects的默认管理器。

      管理器是Django的模型进行数据库的查询操作的接口,Django应用的每个模型都拥有至少一个管理器。

      自定义管理器类主要用于两种情况:向管理器类中添加额外的方法,或者修改管理器返回的原始查询集:重写get_queryset()方法。

    from django.db import models
    
    class BookInfoManager(models.Model):
        """
        可以重写Model中的方法
        """
        def get_queryset(self):
            return super(BookInfo, self.get_queryset().filter(isdelete=False))
    
        # 创建BookInfo
        def create(self, name, pub_date):
            b = BookInfo()
            b.name = name
            b.headline = pub_date
            b.isdelete = False
            return b
    
    class BookInfo(models.Model):
        name = models.CharField(max_length=20)
        headline = models.CharField(default="this's a python book")
        isdelete = models.BooleanField(default=False)
        # 自定义管理器被定义时,继承了默认管理器
        manager = BookInfoManager()
    
    # BookInfo.manager.create(name="Jan")

    四、数据库操作

      1、多对一操作

      1.批量添加

    # models.py
    from django.db import models
    
    class Province(models.Model):
        name = models.CharField(max_length=32)
    
    class City(models.Model):
        name = models.CharField(max_length=32)
        pro = models.ForeignKey("Province", to_field="id", on_delete=models.CASCADE)
    # app01/insert_records.py
    
    import os, django
    # 添加django的环境配置
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
    django.setup()
    
    from app01.models import Province, City
    
    city_dict = {"东莞": 2, "深圳": 2, "惠州": 2, "河源": 2, "泰安": 3, "青岛": 3, "济南": 3, "张家口": 1,"邢台": 1}
    province_dict = {"河北": 1, "山东": 3, "广东": 2,}
    province_records_dict
    = {id: Province(id=id, name=name) for name, id in province_dict.items()} print(province_records_dict) # 先创建Province Province.objects.bulk_create(province_records_dict.values()) # 再创建City city_records_list = [City(pro=province_records_dict[id], name=name) for name, id in city_dict.items()] print(city_records_list) City.objects.bulk_create(city_records_list) print("ok")

      2.正向查询与反向查询

    # 1.all - 查找全city表中的全部记录,返回所有的querySet
    City.objects.all()
    # 正向查询:指定获取的字段,外表需要用外键+双下划线的形式访问外键表中的字段;如果有两个表中的字段,相当于对两个表同时进行操作
    City.objects.all().values("id", "name", "pro__id", "pro_name")
    # 反向查询:默认会将外键表的模型类小写当做id,相当于city__id,它同样支持表名+双下划线+字段的形式查询
    Province.objects.all().values("id", "name", "city", "city__name", "city__id")
    # 2.filter - 过滤器
    # 正向过滤: 根据某个外键表或者外表中的字段对外表记录进行过滤查询
    City.objects.all().filter(pro__name="河北") # 过滤字段
    # 反向过滤: 根据某个外键表或者外表中的字段对外键表进行过滤查询
    Province.objects.all().filter(name="河北")[0].city_set.all()

      3、多对多操作

      1.批量添加

    # models.py
    from django.db import models
    
    class Book(models.Model):
        name = models.CharField(max_length=32)
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        book = models.ManyToManyField(Book, related_name="book")
    import os, django
    # 添加django的环境配置
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "app.settings")
    django.setup()
    
    from app01.models import *
    
    Book.objects.all().delete()
    Author.objects.all().delete()
    
    book_dict = {1: "Python", 2: "Go", 3: "Linux", 4: "PHP"}
    author_dict = {1: "Jan", 2: "Li", 3: "wise"}
    together_dict = {
        "Jan": ["Python", "Go"],
        "Li": ["Linux", "Go"],
        "wise": ["PHP", "Go", "Python"]
    }
    # 根据以上信息创建ManyToMany
    # 先创建两个表的记录
    book_records_list = {name: Book(id=id, name=name) for id, name in book_dict.items()}
    Book.objects.bulk_create(book_records_list.values())
    author_records_list = {name: Author(id=id, name=name) for id, name in author_dict.items()}
    Author.objects.bulk_create(author_records_list.values())
    # 再根据关系写入数据库
    for key, vlist in together_dict.items():
        # 获取书名对应的querySet
        for i in vlist:
            author_records_list[key].book.add(book_records_list[i])

      2、正向查询与反向查询

    # 正向查找 
    Author.objects.get(id=1).book.all()
    # 反向查找
    Book.objects.get(id=1).book.all() # 这里写.book.all()是因为在Author模型类中声明了related_name,默认的话是author_set.all()
    Book.objects.get(id=1).book.all().values("id", "name", "book__name")
    # 遍历
    for item in Author.objects.values("id", "name", "book"):
      print(item["id"], item["name"], item["book"])

      3、基本查询

      1.返回querySet集合的方法

     名称  解释
    filter 过滤器
    exclude 排除满足条件的对象
    order_by 查询结果排序
    annotate 分组函数,在分组后的数据集上进行操作
    distinct 去重
    values 将querySet以字典形式返回到一个查询集里
    raw 处理一个原始的sql语句
    aggregate 聚合函数,在每个记录上进行操作

      2.返回单个对象

     名称  函数
    get() 返回单个满足条件的对象
    first() 返回第一个对象
    last() 返回最后一个对象
    exists() 判断查询集中是否有数据,如果有则返回True
    count() 返回当前查询的总条数
    select_related() 返回当前querySet的前一条和后一条数据

      3.字段查询

      实现where子名,作为方法filter()、exclude()、get()的参数。语法:属性名称__比较运算符=值。

    1.exact:表示判等,大小写敏感;如果没有写“ 比较运算符”,表示判等
      filter(isDelete=False)
    2.contains:是否包含,大小写敏感
      exclude(btitle__contains='传')
    3.startswith、endswith:以value开头或结尾,大小写敏感
      exclude(btitle__endswith='传')
    4.isnull、isnotnull:是否为null
      filter(btitle__isnull=False)
    5.在前面加个i表示不区分大小写,如iexact、icontains、istarswith、iendswith
    6.in:是否包含在范围内
      filter(pk__in=[1, 2, 3, 4, 5])
    7.gt、gte、lt、lte:大于、大于等于、小于、小于等于
      filter(id__gt=3)
    8.对year、month、day、week_day、hour、minute、second:对日期间类型的属性进行运算
      filter(bpub_date__year=1980)   filter(bpub_date__gt=date(1980, 12, 31))
    9.查询的快捷方式:pk,pk表示primary key,默认的主键是id
      filter(pk__lt=6)

      4、跨表查询

      多对一或者多对多都可以使用模型类+双下划线+字段名的形式进行跨表操作。

    Author.objects.filter(book__name="Go")
    Book.objects.filter(book__name="Jan"

      5、聚合函数

      使用aggregate()函数返回聚合函数的值,函数包括(Avg,Count,Max,Min,Sum)。

    from django.db.models import Max
    maxDate = list.aggregate(Max('bpub_date'))

      6、其它相关

        # 1. Cast,用于做类型转换
        # v = models.UserInfo.objects.annotate(c=Cast('pwd', FloatField()))
    
        # 2. Coalesce,从前向后,查询第一个不为空的值
        # v = models.UserInfo.objects.annotate(c=Coalesce('name', 'pwd'))
        # v = models.UserInfo.objects.annotate(c=Coalesce(Value('666'),'name', 'pwd'))
    
        # 3. Concat,拼接
        # models.UserInfo.objects.update(name=Concat('name', 'pwd'))
        # models.UserInfo.objects.update(name=Concat('name', Value('666')))
        # models.UserInfo.objects.update(name=Concat('name', Value('666'),Value('999')))
    
        # 4.ConcatPair,拼接(仅两个参数)
        # v = models.UserInfo.objects.annotate(c=ConcatPair('name', 'pwd'))
        # v = models.UserInfo.objects.annotate(c=ConcatPair('name', Value('666')))
    
        # 5.Greatest,获取比较大的值;least 获取比较小的值;
        # v = models.UserInfo.objects.annotate(c=Greatest('id', 'pwd',output_field=FloatField()))
    
        # 6.Length,获取长度
        # v = models.UserInfo.objects.annotate(c=Length('name'))
    
        # 7. Lower,Upper,变大小写
        # v = models.UserInfo.objects.annotate(c=Lower('name'))
        # v = models.UserInfo.objects.annotate(c=Upper('name'))
    
        # 8. Now,获取当前时间
        # v = models.UserInfo.objects.annotate(c=Now())
    
        # 9. substr,子序列
        # v = models.UserInfo.objects.annotate(c=Substr('name',1,2))
    
        # ########### 时间类函数 ###########
        # 1. 时间截取,不保留其他:Extract, ExtractDay, ExtractHour, ExtractMinute, ExtractMonth,ExtractSecond, ExtractWeekDay, ExtractYear,
        # v = models.UserInfo.objects.annotate(c=functions.ExtractYear('ctime'))
        # v = models.UserInfo.objects.annotate(c=functions.ExtractMonth('ctime'))
        # v = models.UserInfo.objects.annotate(c=functions.ExtractDay('ctime'))
        #
        # v = models.UserInfo.objects.annotate(c=functions.Extract('ctime', 'year'))
        # v = models.UserInfo.objects.annotate(c=functions.Extract('ctime', 'month'))
        # v = models.UserInfo.objects.annotate(c=functions.Extract('ctime', 'year_month'))
        """
        MICROSECOND
        SECOND
        MINUTE
        HOUR
        DAY
        WEEK
        MONTH
        QUARTER
        YEAR
        SECOND_MICROSECOND
        MINUTE_MICROSECOND
        MINUTE_SECOND
        HOUR_MICROSECOND
        HOUR_SECOND
        HOUR_MINUTE
        DAY_MICROSECOND
        DAY_SECOND
        DAY_MINUTE
        DAY_HOUR
        YEAR_MONTH
        """
        # 2. 时间截图,保留其他:Trunc, TruncDate, TruncDay,TruncHour, TruncMinute, TruncMonth, TruncSecond, TruncYear
        # v = models.UserInfo.objects.annotate(c=functions.TruncHour('ctime'))
        # v = models.UserInfo.objects.annotate(c=functions.TruncDate('ctime'))
        # v = models.UserInfo.objects.annotate(c=functions.Trunc('ctime','year'))

      4、F对象和Q对象

      1.F对象

      如果需要在等号右侧需要使用当前querySet中的字段,就需要用到F对象。

    from django.db.models import F
    1.右侧需要用到本表字段,用F对象

      Book.objects.all().update(price=F('price') + 20) 2.
    django支持对F()对象使用算数运算   list.filter(bread__gte=F('bcommet') * 2) 3.F()对象中还可以写作“模型类__列名”进行关联查询   list.filter(isDelete=F('heroinfo__isDelete')) 4.对于date/time字段,可与timedelta()进行运算   list.filter(bpub_date__lt=F('bpub_date') + timedelta(days=1))

      2.Q对象

      过滤器的方法中关键字参数查询,会合并为And进行;需要进行or查询,使用Q()对象。Q对象(django.db.models.Q)用于封装一组关键字参数,这些关键字参数与“比较运算符”中的相同。

    from django.db.models import Q
    1.基本操作:
       Author.objects.filter(Q(name="Jan")) # 等价于Author.objects.filter(name="Jan")
    2.Q对象可以使用&(and)、|(or)操作符组合起来:
      Author.objects.filter(Q(name="Jan") | Q(name="Wise")) # 等价于Author.objects.filter(name__in=["Jan", "Wise"])
    3.支持联表查询
      Author.objects.filter(Q(book__name="Go") & Q(id__lt=2))
    3.当操作符应用在两个Q对象时,会产生一个新的Q对象
      list.filter(pk_ _lt
    =6).filter(bcommet_ _gt=10)
      list.filter(Q(pk_ _lt
    =6) | Q(bcommet_ _gt=10))
  • 相关阅读:
    nginx1配置文件
    div中添加滚动条
    django错误笔记——1242 Subquery returns more than 1 row
    Django中合并同一个model的多个QuerySet
    js正则匹配数字字母汉字
    django错误笔记——URL
    python发送邮件
    SMTP——MIME
    Python读取Excel中的数据并导入到MySQL
    css3选择器
  • 原文地址:https://www.cnblogs.com/kuaizifeng/p/9521560.html
Copyright © 2011-2022 走看看