django models

---恢复内容开始---

一:Models

  ORM(对象关系映射):

  1.   优点:使用ORM,与数据库交互变得更简单,不用考虑麻烦的SQL语句。从而实现快速开发
  2.   缺点:    

        性能有所牺牲。但能通过缓存 或 延迟加载等来减轻这个问题,效果不错

        复杂查询不擅长,但ORM支持 raw sql(自己写原生数据库语句)

  

 表创建(模型):

  1. 学校模型
  2. 教师模型
  3. 教师详细信息模型
  4. 班级模型
一个学校有多个班级,多个班级对应一个学校  :一对多关系(foreign key)
一个老师对应一个教师详细信息 :一对一关系(OneToOneField)
多个教师对应多个班级,多个班级对应多个老师 : 多对多关系(ManyToManyField)
from django.db import models

# Create your models here.


class School(models.Model):
    """ 学校表 """
    name = models.CharField(max_length=30, verbose_name='名称')
    site = models.CharField(max_length=30, verbose_name='地址')
    city = models.CharField(max_length=30, verbose_name='城市')
    province = models.CharField(max_length=30, verbose_name='省份')
    Grade_Class = models.ForeignKey('Grade')  # 学校和班级的关系:一对多,一个学校有多个班级

    class Meta:
        verbose_name = '学校'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Teacher(models.Model):
    """ 教师表 """
    name = models.CharField(max_length=30)

    def __str__(self):
        return self.name


class TeacherInfo(models.Model):
    """教师信息表"""
    choices = ((0, ''), (1, ''))
    sex = models.BooleanField(max_length=1, choices=choices)
    email = models.EmailField()
    site = models.CharField(max_length=30)
    teacher = models.OneToOneField('Teacher')  # 教师与教师详细信息的关联关系:一对一


class Grade(models.Model):
    """ 班级表 """
    name = models.CharField(max_length=30)
    number = models.IntegerField()
    # 教师和班级的关系:多对多,多个老师对应多个班级,多个班级对应多个老师
    teacher = models.ManyToManyField('Teacher')

    def __str__(self):
        return self.name
模型表
1.CharField
字符串字段,用于较短的字符串
CharField 要求必须有一个参数 max_length ,用于从数据库和Django校验层限制该字段所允许的最大字符数

2.IntegerField
保存一个整数

3.FloatField
一个浮点数,必须提供两个参数:
1.参数max_digits   总位数()       
 2.描述(decimal_places 小数位数)
 举例来说, 要保存最大值为 999 (小数点后保存2位),你要这样定义字段:
                #
                # models.FloatField(..., max_digits=5, decimal_places=2)
                # 要保存最大值一百万(小数点后保存10位)的话,你要这样定义:
                #
                # models.FloatField(..., max_digits=19, decimal_places=10)
                # admin 用一个文本框(<input type="text">)表示该字段保存的数据.

4.AutoField
# 一个 IntegerField, 添加记录时它会自动增长. 你通常不需要直接使用这个字段; 
        # 自定义一个主键:my_id=models.AutoField(primary_key=True)
        # 如果你不指定主键的话,系统会自动添加一个主键字段到你的 model.

5.BooleanField
# A true/false field. admin 用 checkbox 来表示此类字段.

6.TextField
 # 一个容量很大的文本字段.
     # admin 用一个 <textarea> (文本区域)表示该字段数据.(一个多行编辑框).

7.EmailField
     # 一个带有检查Email合法性的 CharField,不接受 maxlength 参数.

8.DateField
        # 一个日期字段. 共有下列额外的可选参数:
        # Argument    描述
        # auto_now    当对象被保存时,自动将该字段的值设置为当前时间.通常用于表示 "last-modified" 时间戳.
        # auto_now_add    当对象首次被创建时,自动将该字段的值设置为当前时间.通常用于表示对象创建时间.
        #(仅仅在admin中有意义...)

9.DateTimeField
        #  一个日期时间字段. 类似 DateField 支持同样的附加选项.

10.ImageField
        # 类似 FileField, 不过要校验上传对象是否是一个合法图片.#它有两个可选参数:height_field和width_field,
        # 如果提供这两个参数,则图片将按提供的高度和宽度规格保存.    

11.FieldField
# 一个文件上传字段.
     #要求一个必须有的参数: upload_to, 一个用于保存上载文件的本地文件系统路径. 这个路径必须包含 strftime #formatting, 
     #该格式将被上载文件的 date/time 
     #替换(so that uploaded files don't fill up the given directory).
     # admin 用一个<input type="file">部件表示该字段保存的数据(一个文件上传部件) .

     #注意:在一个 model 中使用 FileField 或 ImageField 需要以下步骤:
            #(1)在你的 settings 文件中, 定义一个完整路径给 MEDIA_ROOT 以便让 Django在此处保存上传文件. 
            # (出于性能考虑,这些文件并不保存到数据库.) 定义MEDIA_URL 作为该目录的公共 URL. 要确保该目录对 
            #  WEB服务器用户帐号是可写的.
            #(2) 在你的 model 中添加 FileField 或 ImageField, 并确保定义了 upload_to 选项,以告诉 Django
            # 使用 MEDIA_ROOT 的哪个子目录保存上传文件.你的数据库中要保存的只是文件的路径(相对于 MEDIA_ROOT). 
            # 出于习惯你一定很想使用 Django 提供的 get_<#fieldname>_url 函数.举例来说,如果你的 ImageField 
            # 叫作 mug_shot, 你就可以在模板中以 {{ object.#get_mug_shot_url }} 这样的方式得到图像的绝对路径.


12.URLField
 # 用于保存 URL. 若 verify_exists 参数为 True (默认), 给定的 URL 会预先检查是否存在( 即URL是否被有效装入且
     # 没有返回404响应).
     # admin 用一个 <input type="text"> 文本框表示该字段保存的数据(一个单行编辑框)


13.NullBooleanField
   # 类似 BooleanField, 不过允许 NULL 作为其中一个选项. 推荐使用这个字段而不要用 BooleanField 加 null=True 选项
       # admin 用一个选择框 <select> (三个可选择的值: "Unknown", "Yes" 和 "No" ) 来表示这种字段数据.

14.SlugField
# "Slug" 是一个报纸术语. slug 是某个东西的小小标记(短签), 只包含字母,数字,下划线和连字符.#它们通常用于URLs
       # 若你使用 Django 开发版本,你可以指定 maxlength. 若 maxlength 未指定, Django 会使用默认长度: 50.  #在
       # 以前的 Django 版本,没有任何办法改变50 这个长度.
       # 这暗示了 db_index=True.
       # 它接受一个额外的参数: prepopulate_from, which is a list of fields from which to auto-#populate 
       # the slug, via JavaScript,in the object's admin form: models.SlugField
       # (prepopulate_from=("pre_name", "name"))prepopulate_from 不接受 DateTimeFields.


15.XMLField
       #一个校验值是否为合法XML的 TextField,必须提供参数: schema_path, 它是一个用来校验文本的 RelaxNG schema #的文件系统路径.

16.FieldPathField
 # 可选项目为某个特定目录下的文件名. 支持三个特殊的参数, 其中第一个是必须提供的.
        # 参数    描述
        # path    必需参数. 一个目录的绝对文件系统路径. FilePathField 据此得到可选项目. 
        # Example: "/home/images".
        # match    可选参数. 一个正则表达式, 作为一个字符串, FilePathField 将使用它过滤文件名.  
        # 注意这个正则表达式只会应用到 base filename 而不是
        # 路径全名. Example: "foo.*\.txt^", 将匹配文件 foo23.txt 却不匹配 bar.txt 或 foo23.gif.
        # recursive可选参数.要么 True 要么 False. 默认值是 False. 是否包括 path 下面的全部子目录.
        # 这三个参数可以同时使用.
        # match 仅应用于 base filename, 而不是路径全名. 那么,这个例子:
        # FilePathField(path="/home/images", match="foo.*", recursive=True)
        # ...会匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif

17.IPAddressField
# 一个字符串形式的 IP 地址, (i.e. "24.124.1.30").
常用字段Filed

Filed参数说明:

  1. null : 数据库中字段是否可以为空

    2. blank: django的 Admin 中添加数据时是否可允许空值

     3. default:设定缺省值

     4. editable:如果为假,admin模式下将不能改写。缺省为真

     5. primary_key:设置主键,如果没有设置django创建表时会自动加上:
        id = meta.AutoField('ID', primary_key=True)
        primary_key=True implies blank=False, null=False and unique=True. Only one
        primary key is allowed on an object.

     6. unique:数据唯一

     7. verbose_name  Admin中字段的显示名称

     8. validator_list:有效性检查。非有效产生 django.core.validators.ValidationError 错误


     9. db_column,db_index 如果为真将为此字段创建索引

     10. choices:一个用来选择值的2维元组。第一个值是实际存储的值,第二个用来方便进行选择。
                如SEX_CHOICES= (( ‘F’,'Female’),(‘M’,'Male’),)
                gender = models.CharField(max_length=2,choices = SEX_CHOICES)
参数说明

 

模型操作(增删改查):

 --------------------------------------------------------- 增----------------------------------------------------------

import os, django
# 外部调用 Django models
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "DjangoTest.settings")
django.setup()
from app01.models import *
import sys

# create方式
Teacher.objects.create(name='王哲学')
Teacher.objects.create(**{'name':'张三'})

# save 方式
t = Teacher(name='李四')
t.save() #保存

t = Teacher()
t.name = '陈建国'
t.save()

一对多,多对多关系的数据写入:

一对多:
  一个学校有多个班级,school表 关联着 班级表(Grade)的行对象
g = Grade.objects.create(name='三年级一班', number=20)
School.objects.create(name='若智小学',
site='北京二环死胡同288',
city='北京市',
province='北京市',
Grade_Class=g, # 直接指定对象
# 或者直接指定id
#Grade_Class=2, # 相当于将Grade表的ID=2的行对象进行关联
)

多对多:
  一个班级可以有多个老师,多个老师可以对应多个班级。在ORM里,如果有多对多关系的模型,那么两表之间会再自动创建一张新表
      

  

# 方式1:
teacher1 = Teacher.objects.get(id=1)
teacher2 = Teacher.objects.filter(name='李四')[0]
grade = Grade.objects.get(id=1)
grade.teacher.add(teacher1, teacher2)

#方式2 正向关联:
一个班级去关联多个老师, 以 班级 这个对象为中心进行关联教师
teacher1 = Teacher.objects.filter(id__gt=1) # 返回Teacher表ID大于1的所有行对象,返回的是列表集合
grade = Grade.objects.filter(id=1)[0] # 返回Grade表id=1的行对象
grade.teacher.add(*teacher1) # 正向关联
grade.teacher.remove(*teacher1) # 删除


#方式3 反向关联:
1个老师去关联多个班级,以 教师 这个对象为中心进行关联班级
teacher1 = Teacher.objects.filter(id=1)[0] 
grade = Grade.objects.filter(id__gt=1)
teacher1.grade_set.add(*grade)
teacher1.grade_set.remove(*grade)### 删除

 反向关联的 表名_set 比较特殊,能通过 teacher 表 反向找到 grade 表,这是Django已经定义好的

****两表中,ManyToMany 字段定义在谁的那一端,谁就是正向,否则就是反向

 


 --------------------------------------------------------- 删----------------------------------------------------------

Teacher.objects.filter(id=1).delete()  # 删除ID=1的老师

Django默认级联删除,虽然上面看起来删除了1条信息,但实际上,关联了它的表的行对象数据也会被删除

多对多关系删除:
  # 正向删除
  grade = Grade.objects.filter(id=1)[0]
  grade.teacher.clear() # 删除第三张中的与 Grade表中 id=1 的所有关联数据
  
  ------------------------  
   grade = Grade.objects.filter(id=2)[0]
teacher = Teacher.objects.filter(id__gt=1)
grade.teacher.remove(*teacher)


  # 反向
  teacher = Teacher.objects.filter(id=2)[0]
  teacher.grade_set.clear()

 --------------------------------------------------------- 改----------------------------------------------------------

# 方式1
teacher = Teacher.objects.get(id=2) teacher.name = '铁蛋' teacher.save()

# 方式2
Teacher.objects.filter(id=2).update(name='汤姆')


多对多修改:
grade = Grade.objects.filter(id=2)[0]
teacher = Teacher.objects.filter(id__gt=1)
grade.teacher.add(*teacher)

 --------------------------------------------------------- 查----------------------------------------------------------

# 查询相关API:

#  <1>filter(**kwargs):      它包含了与所给筛选条件相匹配的对象

#  <2>all():                 查询所有结果

#  <3>get(**kwargs):         返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。

#-----------下面的方法都是对查询的结果再进行处理:比如 objects.filter.values()--------

#  <4>values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列
                                     
#  <5>exclude(**kwargs):     它包含了与所给筛选条件不匹配的对象

#  <6>order_by(*field):      对查询结果排序

#  <7>reverse():             对查询结果反向排序

#  <8>distinct():            从返回结果中剔除重复纪录

#  <9>values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列

#  <10>count():              返回数据库中匹配查询(QuerySet)的对象数量。

# <11>first():               返回第一条记录

# <12>last():                返回最后一条记录

#  <13>exists():             如果QuerySet包含数据,就返回True,否则返回False。
查询API

惰性机制:

  在执行 teacher.objects.all() 和 teacher.objects.filter() 时,只是返回结果集对象,并不是立即执行sql,当调用QuerySet时才会执行

  QuerySet 特点:

# 可迭代
# 可切片

t = Teacher.objects.all() #[obj1,obj2,obj3,obj4] ,返回一个QuerySet对象
for i in t:
  print(i)

t[1]
t[1:5]
t[::-1]

  QuerySet高效使用

1.QuerySet是惰性的
  如:teacher = Teacher.object.filter(id=1) 在执行这样的代码时,它只是生成了数据库语句,但并没有执行,只要调用的时候才执行;

2.真正地在数据库里执行
  如: print(teacher)
  或者: for t in teacher:
        print(t)
  或者: if teacher:
        print('xxx')

3.QuerySet 是有 cache(缓存) 的
  当遍历或者调用QuerySet时,所有事先生成的数据库语句会在数据库执行,然后转换成Django的model.
     这些model会被保存在QuerySet内置的cache里。当你再次遍历QuerSet时,无需重复执行数据库语句

4.如果查询量过大(QuerySet集合过大),cache会有可能不足
  如果查询量过大,一次性载入内存里非常浪费,要避免这个问题,可以使用 迭代器(iterator)的方式来获取数据,处理完数据就丢弃
  teacher = Teacher.objects.all().iterator() # iterator() 可以一次取少量数据,节省内存,用一次取一次
  for t in teacher:
    print(t.name)
5.exists()检查是否有数据,可以避免数据放入cache里。 teacher.exists() 检测有效数据但不会放入缓存
6.iteraor() 方法虽然可以预防缓存不足的问题,但同样的也有弊端:遍历同一个QuerySet时,会重复执行


  对象、单表、多表条件关联查询

 

# #----------双下划线[ __ ] 多表 正向 查询---------------
sch = School.objects.filter(name='若智小学').values('id')  # 返回name='若智小学' 的id
print(sch)  # 结果:<QuerySet [{'id': 1}]>

# 正向一对多查找:
sch = School.objects.filter(name='若智小学').values('Grade_Class__name')
print(sch)  # 结果:<QuerySet [{'Grade_Class__name': '四年级二班'}]>

# 正向多对多查找:
grade = Grade.objects.filter(name='三年级一班').values('teacher__name')
print(grade)  # <QuerySet [{'teacher__name': None}, {'teacher__name': '王哲学'}]>
grade = Grade.objects.filter(teacher__name='王哲学').values('name') print(grade) # <QuerySet [{'name': '三年级一班'}]> # #----------双下划线[ __ ] 多表 反向 查询--------------- # 反向一对多查找: grade = Grade.objects.filter(school__name='若智小学').values('name') print(grade) # <QuerySet [{'name': '四年级二班'}]> # 反向多对多查询 teacher = Teacher.objects.filter(grade__name='王哲学').values('name') # 取王哲学关联的班级 print(teacher) # <QuerySet [{'name': '四年级二班'}]>


# 一对多或者多对多查找都是通过 字段 来查找的
# 正向: 关联字段定义在谁的一方,就以谁为主
# 反向: 关联字段定义在其他表里,

  聚合查询

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

# 所有班级的平均人数
grade = Grade.objects.all().aggregate(Avg('number'))
print(grade)

# 所有班级的总人数
grade = Grade.objects.all().aggregate(Sum('number'))
print(grade)


# 最大人数
grade = Grade.objects.all().aggregate(Max('number'))
print(grade)

# 最小人数
grade = Grade.objects.all().aggregate(Min('number'))
print(grade)

  Q查询和F查询

from django.db.models import F, Q

q1 = Teacher.objects.filter(Q(name__startswith='')).all() #  查询姓李的老师
print(q1)

# 可以使用 | 和 &
q1 = Teacher.objects.filter(
    Q(name__startswith='')|Q(name__startswith='')).all()
print(q1)

# ~ 否定
q1 = Teacher.objects.filter(
    ~Q(name__startswith='')).all() # 查询不是姓李的老师
print(q1)


---------------F查询-----------------
from django.db.models import F, Q
# 一个班级,突然多了一个插班生
Grade.objects.filter(name='四年级二班').update(number=F('number')+1)

二:admin配置

 admin功能很强大,它能从数据库读取数据并呈现在页面里,并且可以在前端页面实现对数据库的操作

 注册model模型到admin:

  

1:register方法
admin.site.register(模型类, 定制类)

2:register 装饰圈注册
@admin.register(模型类)

定制管理类:

 list_display:     指定要显示的字段
 search_fields:  指定搜索的字段
 list_filter:        指定列表过滤器
 ordering:       指定排序字段

from django.contrib import admin
from app01.models import *
# Register your models here.
class MyAdmin(admin.ModelAdmin):
    list_display = ('id', 'name', 'site',)
    search_fields = ('name',)
    list_filter = ('name',)
    ordering = ('id',)
    fieldsets = [(None, {'fields':['site']})]
admin.site.register(School, MyAdmin)
admin.site.register(Teacher)
admin.site.register(Grade)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

---恢复内容结束---

posted @ 2018-08-03 14:29  lei-jia-ming  阅读(272)  评论(0编辑  收藏  举报