zoukankan      html  css  js  c++  java
  • Django进阶Model篇—数据库操作(ORM)

    一、数据库配置

      django 默认支持sqlite、mysql、oracle、postgresql数据库,像db2和sqlserver之类的数据库需要第三方的支持,具体详见https://docs.djangoproject.com/en/1.10/ref/databases/

      一、环境准备

      1、创建项目

        1、使用命令创建项目和应用
    创建项目:django-admin startprojcet xxx 
    创建应用:python manage.py startapp app01
    启动应用:python manage.py runserver 127.0.0.1:8000
    
        2、使用pycharm创建项目和应用

      2、查看项目的目录结构

      

      二、MySQL介绍与连接数据库

      1、MySQL介绍

        1、MySQL引擎名称介绍

        django.db.backends.mysql

        2、MySQL驱动程序介绍

        MySQLdb(mysql-python):https://pypi.python.org/pypi/MySQL-python/1.2.5

        PyMySQL(纯python的mysql驱动-推荐) :https://pypi.python.org/pypi/PyMySQL

      2、连接设置

        1、安装pymysql
    pip install pymysql
        2、连接数据库配置

      修改settings.py文件

        DATABASES = {
            'default': {
                'ENGINE': 'django.db.backends.mysql',
                'NAME':'数据库名称', # 记得自己先去创建数据库
                'USER': 'root',
                'PASSWORD': 'xxx',
                'HOST': '127.0.0.1',
                'PORT': 3306,
            }
        }
        3、修改procjet底下procjet底下的__init__.py(如下图)加入下面的代码如下

      注意:Python3中,连接mysql用的库不再支持MySQLdb模块,可以使用pymysql或mysqlclient模块。所以Django项目要连接数据,需要添加下面的代码。

    import pymysql
    pymysql.install_as_MySQLdb()

       

      3、创建数据库

      

      4、使用pycharm的数据库sqlite,使用默认的配置即可

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

    二、ORM

      一、初识ORM

      1、数据库和ORM映射关系

      对象关系映射(ORM),用于实现面向对象编程里不同类型系统的数据之间的转换。换句话说,就是用面向对象的方式去操作数据库的创建表,增加、修改、删除、查询等操作。

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

      2、models.py

      models.py里面一个类就是一个数据表

      每个模型相当于单个数据库表(这条规则的例外情况是多对多关系,多对多关系的时候会多生成一张关系表),每个属性也是这个表中的一个字段。属性名就是字段名,它的类型(例如CharField)相当于数据库的字段类型(例如varchar)。

      3、演示ORM生成的sql语句

        1、查看QuerySet的query属性
    def hello(request):
        user_list=User.objects.all()
        print user_list.query
        2、配置日志系统,将sql显示到控制台(修改settings.py)
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',
            },
        },
        'loggers': {
            'django': {
                'handlers': ['console'],
                'level': 'DEBUG',
                'propagate': True,
            },
        },
    }

      更多详情见:https://docs.djangoproject.com/en/1.10/topics/logging/

      二、创建表(建立模型)

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

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

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

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

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

      2、模型建立如下

    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()<br>    commentNum=models.IntegerField()
     
        # 与Publish建立一对多的关系,外键字段建立在多的一方
        publish=models.ForeignKey(to="Publish",to_field="nid")
     
        # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
        authors=models.ManyToManyField(to='Author')  

      3、注意事项

      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

      4、模型常用字段类型

     1 BooleanField: 布尔类型字段
     2 CharField: 字符串类型字段
     3 DateField: 日期字段
     4 DateTimeField:日期时间字段
     5 DecimalField:(精确)小数字段
     6 EmailField:Email字段
     7 FileField:文件字段
     8 FloatField:(浮点数)小数字段
     9 ImageField:图片字段
    10 IntegerField:整数字段
    11 IPAddressField:IP字段
    12 SmallIntegerField:小整数字段
    13 TextField:文本字段
    14 URLField:网址地址字段

      5、字段选项

      每个字段有一些特有的参数,例如,CharField需要max_length参数来指定VARCHAR数据库字段的大小。还有一些适用于所有字段的通用参数。 这些参数在文档中有详细定义,这里我们只简单介绍一些最常用的:

    (1)null
    
    如果为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False.
    
    (1)blank
    
    如果为True,该字段允许不填。默认为False。
    要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。
    如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。
    
    (2)default
    
    字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用。
    
    (3)primary_key
    
    如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True,
    Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为,
    否则没必要设置任何一个字段的primary_key=True。
    
    (4)unique
    
    如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的
    
    (5)choices
    由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,而且这个选择框的选项就是choices 中的选项。
    
    这是一个关于 choices 列表的例子:
    
    YEAR_IN_SCHOOL_CHOICES = (
        ('FR', 'Freshman'),
        ('SO', 'Sophomore'),
        ('JR', 'Junior'),
        ('SR', 'Senior'),
        ('GR', 'Graduate'),
    )
    每个元组中的第一个元素,是存储在数据库中的值;第二个元素是在管理界面或 ModelChoiceField 中用作显示的内容。 在一个给定的 model 类的实例中,想得到某个 choices 字段的显示值,就调用 get_FOO_display 方法(这里的 FOO 就是 choices 字段的名称 )。例如:
    
    from django.db import models
    
    class Person(models.Model):
        SHIRT_SIZES = (
            ('S', 'Small'),
            ('M', 'Medium'),
            ('L', 'Large'),
        )
        name = models.CharField(max_length=60)
        shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
    
    
    >>> p = Person(name="Fred Flintstone", shirt_size="L")
    >>> p.save()
    >>> p.shirt_size
    'L'
    >>> p.get_shirt_size_display()
    'Large' 
    View Code

      一旦你建立好数据模型之后,django会自动生成一套数据库抽象的API,可以让你执行关于表记录的增删改查的操作。

       三、添加表记录

      1、普通字段

      方式1

    publish_obj=Publish(name="人民出版社",city="北京",email="renMin@163.com")
    publish_obj.save() # 将数据保存到数据库

      方式2

    publish_obj=Publish.objects.create(name="人民出版社",city="北京",email="renMin@163.com")<br><br>方式3<br>表.objects.create(**request.POST.dict())

      2、外键字段

      方式1:

       publish_obj=Publish.objects.get(nid=1)
       Book.objects.create(title="python",publishDate="2012-12-12",price=665,pageNum=334,publish=publish_obj)

      方式2:

    Book.objects.create(title="python",publishDate="2012-12-12",price=665,pageNum=334,publish_id=1)  

      3、多对多字段

    book_obj=Book.objects.create(title="追风筝的人",publishDate="2012-11-12",price=69,pageNum=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()       #清空被关联对象集合。

      四、查询表记录

      1、查询相关API

    <1> all():                 查询所有结果
    <2> filter(**kwargs):      它包含了与所给筛选条件相匹配的对象
    <3> get(**kwargs):         返回与所给筛选条件相匹配的对象,返回结果有且只有一个,
                               如果符合筛选条件的对象超过一个或者没有都会抛出错误。
    <5> exclude(**kwargs):     它包含了与所给筛选条件不匹配的对象
    <4> values(*field):        返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
                               model的实例化对象,而是一个可迭代的字典序列
    <9> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
    <6> order_by(*field):      对查询结果排序
    <7> reverse():             对查询结果反向排序
    <8> distinct():            从返回结果中剔除重复纪录
    <10> count():              返回数据库中匹配查询(QuerySet)的对象数量。
    <11> first():              返回第一条记录
    <12> last():               返回最后一条记录
    <13> exists():             如果QuerySet包含数据,就返回True,否则返回False

      注意:一定区分object与querySet的区别 !!!

      2、双下划线之单表查询

    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.exclude(id__in=[11, 22, 33])  # not in
     
    models.Tb1.objects.filter(name__contains="ven")
    models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
     
    models.Tb1.objects.filter(id__range=[1, 2])      # 范围bettwen and
     
    startswith,istartswith, endswith, iendswith 

      3、基于对象的跨表查询

        1、一对多查询(Publish 与 Book)

      正向查询(按字段:publish):

    # 查询nid=1的书籍的出版社所在的城市<br>
    book_obj=Book.objects.get(nid=1)<br>print(book_obj.publish.city) # book_obj.publish 是nid=1的书籍对象关联的出版社对象  

      反向查询(按表名:book_set):

    # 查询 人民出版社出版过的所有书籍
     
        publish=Publish.objects.get(name="人民出版社")
     
        book_list=publish.book_set.all()  # 与人民出版社关联的所有书籍对象集合
     
        for book_obj in book_list:
            print(book_obj.title)
        2、一对一查询(Author 与 AuthorDetail)

       正向查询(按字段:authorDetail):

    # 查询egon作者的手机号
     
        author_egon=Author.objects.get(name="egon")
        print(author_egon.authorDetail.telephone)

      反向查询(按表名:author):

    # 查询所有住址在北京的作者的姓名
     
        authorDetail_list=AuthorDetail.objects.filter(addr="beijing")
     
        for obj in authorDetail_list:
            print(obj.author.name)
        3、多对多查询 (Author 与 Book)

      正向查询(按字段:authors):

    # python所有作者的名字以及手机号
     
        book_obj=Book.objects.filter(title="金瓶眉").first()
     
        authors=book_obj.authors.all()
     
        for author_obj in authors:
     
            print(author_obj.name,author_obj.authorDetail.telephone)

      反向查询(按表名:book_set):

    # 查询egon出过的所有书籍的名字
     
        author_obj=Author.objects.get(name="egon")
        book_list=author_obj.book_set.all() #与egon作者相关的所有书籍
     
        for book_obj in book_list:
            print(book_obj.title)

      注意:

    你可以通过在 ForeignKey() 和ManyToManyField的定义中设置 related_name 的值来覆写 FOO_set 的名称。例如,如果 Article model 中做一下更改: publish = ForeignKey(Blog, related_name='bookList'),那么接下来就会如下:

    # 查询 人民出版社出版过的所有书籍
     
       publish=Publish.objects.get(name="人民出版社")
     
       book_list=publish.bookList.all()  # 与人民出版社关联的所有书籍对象集合

       4、基于双下划线的跨表查询

      Django 还提供了一种直观而高效的方式在查询(lookups)中表示关联关系,它能自动确认 SQL JOIN 联系。要做跨关系查询,就使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的 model 为止。

      关键点:正向查询按字段,反向查询按表明。

    # 练习1:  查询人民出版社出版过的所有书籍的名字与价格(一对多)
    
        # 正向查询 按字段:publish
    
        queryResult=Book.objects
                .filter(publish__name="人民出版社")
                .values_list("title","price")
    
        # 反向查询 按表名:book
    
        queryResult=Publish.objects
                  .filter(name="人民出版社")
                  .values_list("book__title","book__price")
    
    # 练习2: 查询egon出过的所有书籍的名字(多对多)
    
        # 正向查询 按字段:authors:
        queryResult=Book.objects
                .filter(authors__name="yuan")
                .values_list("title")
    
        # 反向查询 按表名:book
        queryResult=Author.objects
                  .filter(name="yuan")
                  .values_list("book__title","book__price")
    
    # 练习3: 查询人民出版社出版过的所有书籍的名字以及作者的姓名
    
        # 正向查询
        queryResult=Book.objects
                .filter(publish__name="人民出版社")
                .values_list("title","authors__name")
        # 反向查询
        queryResult=Publish.objects
                  .filter(name="人民出版社")
                  .values_list("book__title","book__authors__age","book__authors__name")
    
    
    # 练习4: 手机号以151开头的作者出版过的所有书籍名称以及出版社名称
    
        queryResult=Book.objects
                .filter(authors__authorDetail__telephone__regex="151")
                .values_list("title","publish__name")

       注意:

    反向查询时,如果定义了related_name ,则用related_name替换表名,例如: publish = ForeignKey(Blog, related_name='bookList'):

    # 练习1:  查询人民出版社出版过的所有书籍的名字与价格(一对多)
     
        # 反向查询 不再按表名:book,而是related_name:bookList
     
        queryResult=Publish.objects
                  .filter(name="人民出版社")
                  .values_list("bookList__title","bookList__price")

      5、聚合查询与分组查询

        1、聚合:aggregate(*args, **kwargs)
    # 计算所有图书的平均价格
        >>> from django.db.models import Avg
        >>> Book.objects.all().aggregate(Avg('price'))
        {'price__avg': 34.35}

      aggregate()QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它。

    >>> Book.objects.aggregate(average_price=Avg('price'))
    {'average_price': 34.35}

      如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:

    >>> from django.db.models import Avg, Max, Min
    >>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
    {'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
        2、分组:annotate()

      为调用的QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数)。 

      (1) 练习:统计每一本书的作者个数

    bookList=Book.objects.annotate(authorsNum=Count('authors'))
    for book_obj in bookList:
        print(book_obj.title,book_obj.authorsNum)
    SELECT 
    "app01_book"."nid", 
    "app01_book"."title", 
    "app01_book"."publishDate", 
    "app01_book"."price", 
    "app01_book"."pageNum", 
    "app01_book"."publish_id", 
    COUNT("app01_book_authors"."author_id") AS "authorsNum" 
    FROM "app01_book" LEFT OUTER JOIN "app01_book_authors" 
    ON ("app01_book"."nid" = "app01_book_authors"."book_id") 
    GROUP BY 
    "app01_book"."nid", 
    "app01_book"."title", 
    "app01_book"."publishDate", 
    "app01_book"."price", 
    "app01_book"."pageNum", 
    "app01_book"."publish_id"
    SQL语句

      (2) 如果想对所查询对象的关联对象进行聚合:

      练习:统计每一个出版社的最便宜的书

       方式一:

    publishList=Publish.objects.annotate(MinPrice=Min("book__price"))
     
    for publish_obj in publishList:
        print(publish_obj.name,publish_obj.MinPrice)

      annotate的返回值是querySet,如果不想遍历对象,可以用上valuelist:

    queryResult= Publish.objects
                .annotate(MinPrice=Min("book__price"))
                .values_list("name","MinPrice")
    print(queryResult)

        方式二:

    queryResult=Book.objects.values("publish__name").annotate(MinPrice=Min('price'))

      (3) 统计每一本以py开头的书籍的作者个数:

    queryResult=Book.objects
               .filter(title__startswith="Py")
               .annotate(num_authors=Count('authors'))

      (4) 统计不止一个作者的图书:

    queryResult=Book.objects
              .annotate(num_authors=Count('authors'))
              .filter(num_authors__gt=1)

      (5) 根据一本图书作者数量的多少对查询集 QuerySet进行排序:

    Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')

      (6) 查询各个作者出的书的总价格:

    # 按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)

      6、F查询与Q查询

        1、F查询

      在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?

      Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

    # 查询评论数大于收藏数的书籍
     
       from django.db.models import F
       Book.objects.filter(commnetNum__lt=F('keepNum'))

      Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。

    # 查询评论数大于收藏数2倍的书籍
        Book.objects.filter(commnetNum__lt=F('keepNum')*2)

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

    Book.objects.all().update(price=F("price")+30)
        2、Q查询

      filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q对象

    from django.db.models import Q
    Q(title__startswith='Py')

      Q 对象可以使用& 和| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。

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

      等同于下面的SQL WHERE 子句:

    WHERE name ="yuan" OR name ="egon"

      你可以组合& 和|  操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询:

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

      查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:

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

      五、修改表记录

    Publisher.objects.filter(id=2).update(name='American publisher')

      注意:

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

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

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

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

      六、删除表记录

      删除方法就是 delete()。它运行时立即删除对象而不返回任何值。例如:

    Publisher.objects.filter(id=2).update(name='American publisher')

      你也可以一次性删除多个对象。每个 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)
    
  • 相关阅读:
    00 学习资源整理
    07 MySQL的应用层调整,查询缓存设置,内存管理设置,并发参数的设置常识
    06 SQL语句编写优化
    05 Java的ReentrantLock与线程的顺序控制
    05 索引的使用常识(如何编写SQL语句避免索引失效)
    04 MYSQ的SQL优化需要了解的工具explain,profile,trace
    04 JAVA中park/unpark的原理以及JAVA在API层面线程状态总结
    03 MYSQL的体系结构以及存储引擎的基本知识
    02 链表编程题
    01 栈与队列
  • 原文地址:https://www.cnblogs.com/happy-king/p/8338404.html
Copyright © 2011-2022 走看看