精华内容
下载资源
问答
  • Python Django框架数据库SQL请求笔记

    数据库SQL Query

    传送门 => QuerySet对象

    from django.db import models
    
    class Mject(models.Model):
        field1 = models.CharField(max_length=100)
        field2 = models.CharField(max_length=100)
        pass    # 没有主键时,django会自动添加名为id的自增整形主键
    
    Mject(field1='field1Value', field2='Value2').save()	# 创建一个对象并保存
    
    mobj = Mject.objects.get(id=1) # return a Model object
    qset = Mject.objects.filter(id=1) # return a QuerySet object
    

    一、前情概要

    1. QuerySet对象中有query属性,可查看当前QuerySet对象的数据库查询SQL语句
      print(qset.query)
      打印出query,是一个列表,包含此QuetrySet的所有SQL请求语句,包括Django默认SQL和此次查询SQL
    2. qset.`ForeignKey`可以获取连接的外键的QuerySet

    二、ORM查询方法filter

    1. Mject.objects.filter(field1__exact='Value') # --> None

      精准字段查询,区分字母大小写,where field = `Value`,跟数据库排序集有关,大部分情况下依然不区分大小写
      查询值为None时,SQLis null查询

    2. Mject.objects.filter(field2__iexact='value2') # --> QuerySet object(1)

      精准字段查询,不区分字母大小写,where field like value,大部分情况下与field__exact无区别

    3. Mject.objects.filter(field1__contains='Val') # --> QuerySet object(1)

      包含字段查询,区分字母大小写,where field like binary %Val%

    4. Mject.objects.filter(field1__icontains='val') # --> QuerySet object(1)

      包含字段查询,不区分字母大小写,where field like %val%

    5. Mject.objects.filter(id__in=[1, 2, 3]) # --> QuerySet object(1, 2, 3)

      与MySQL中的in用法相似,查询指定范围内的数据,可以是一个可迭代对象list, tuple, QuerySet…

    6. Mject.objects.filter(`ForeignKey`__`Field`__in=[1, 2, 3])

      外键联合查询,查找引用了Mject的外键为[1, 2, 3]Mject记录(利用子表数据查找父表数据),`ForegnKey`子表名可以在外键关联时由related_query_name指定,`Field`为引用表查询字段(子表的查询字段)
      SQL实现为关联查询,join
      egg:

      1. articles = Article.objects.filter(title__icontains='hello')
        先选出包含标题hello字样的文章articles
      2. categories = Category.objects.filter(article__id__in=articles)
        选出articles中所包含的文章分类categories
        SQL实现: select c.id, c.name from category c inner join article a on (c.id=a.category_id) where a.id in (select a1.id from article a1 where a1.title like %hello%);
        查询标题含有hello字样的文章的所有文章的分类类型,查询的是categoryarticle引用外键category_id

      `Field`为主键时,可以省略,即`Field`名·省略时,默认是查询关联表的主键

    7. Mject.objects.filter(id__gt=2) # --> QuerySet object(id>2)

      查询id大于2的记录,greater than, `Filed`__lt类似

    8. Mject.objects.filter(id__gte=2) # --> QuerySet object(id>=2)

      查询id大于或等于(不小于)2的记录,greater than or equal, filed__lte类似

    9. Mject.objects.filter(field1__startwith='Field') # --> None

      查询field1Field开头的记录,like binary Field%, 大小写敏感,Field__endwith类似

    10. Mject.objects.filter(field1__istartwith='Field') # --> None

      查询field1Field开头的记录,like Field%, 大小写不敏感,Field__iendwith类似

    11. Mject.objects.filter(`Field`__range=('start', 'end'))

      连续范围查询 between and,可以用于查询时间区间

    12. Mject.objects.filter(`Field`__date='datetimeObj')

      django主动调用mysql函数date()convert_tz(),转换时区

    13. Mject.objects.filter(`Field`__year__gte=2018)
      年,2018之后
      Mject.objects.filter(`Field`__week_day=4)
      星期, 星期四
      Mject.objects.filter(`Field`__time__range='timeObj')
      时分秒, 可以用range范围查询

    14. Mject.objects.filter(`Field`__isnull=True)

      查询字段为空的记录True/False

    15. Mject.objects.filter(`Field`__regex=r'^field')

      正则表达式查询,django自动转换sql查询,大小写敏感

    16. Mject.objects.filter(`Field`__iregex=r'^field')

      正则表达式查询,django自动转换sql查询,大小写不敏感

    三、ORM聚合函数aggregate & annotate

    from django.db.models import Avg, Count, Max, Min, Sum
    from django.db import connection
    
    Mject.objects.aggregate(Avg('field')) # -->return a dict object with defaultKey 'field_avg'
    connection.queries  # 获取SQL语句
    
    1. Mject.objects.aggregate(avg=Avg('`ForeignKey`__`field`'))

      return a dict object with new key 'avg'
      传递关键字参数可以自定义查询结果的命名,返回字典{'avg': Avg()}

    2. Mject.objects.annotate(avg=Avg('ForeignKey__field'))

    • 对比:

      可以使用外键关联
      aggregate不使用分组,而是直接求所有记录的聚合函数结果
      annotate会使用分组group by,并分别对每组数据求聚合函数,默认按查询表主键分组

      books = Book.objects.annotate(avgprice=Avg("bookorder__price"))
      查询book,所有数据按book_id分组

    • 回溯:

      Book存储id, price定价, name, 等信息
      BookOrder存储Book订单信息,id, price售价, book_id关联外键Book.id
      提醒:`ForeignKey`是当前查询对象被引用的外键名(子表名);`field`是外键引用者(子表)所需要查询的字段

      • Mject.objects.aggregate(num=Count('id', distinct=True))
        SQL: count(distinct id), 统计不同id个数;distinct=False时,SQL: count(id),重复内容也会计算
        统计不同book的销售数量:
      • books = Book.objects.annotate(num=Count('bookorder'))
        `field`为主键时,可以省略bookorder__id
      • Mject.objects.aggregate(max=Max('age'), min=Min('age'))
        获取年龄最大值和最小值
        统计不同book的最高售价和最低售价:
      • books = Book.objects.annotate(max=Max('bookorder__price'), min=Min('bookorder__price'))
      • [book.name, book.max, book.min for book in books]
        遍历结果

    提醒:分组返回的类型Book object集合,在返回时django自动为其添加聚合查询的属性值

      • Mject.objects.aggregate(total=Sum('price'))
        return a dict
      • books = Book.objects.annotate(total=Sum('bookorder__price'))
    1. aggregate函数, annotate函数可以用在所有QuerySet类型上

      • BookOrder.objects.filter(create_time__year=2018).aggregate(total=Sum('price'))
        统计2018年所有图书的销售总额
      • books = Book.objects.filter(bookorder__create_time__year = 2018).annotate(total = Sum('bookorder__price'))
        统计2018年每种图书的销售总额
      • [book.name, book.total for book in books]
        遍历获取数据
    展开全文
  • Django数据库的链接处理是这样的,Django程序接受到请求之后,在第一访问数据库的时候会创建一个数据库连接,直到请求结束,关闭连接。下次请求也是如此。因此,这种情况下,随着访问的并发数越来越高,就会产生...

    Django的数据库连接
           Django对数据库的链接处理是这样的,Django程序接受到请求之后,在第一访问数据库的时候会创建一个数据库连接,直到请求结束,关闭连接。下次请求也是如此。因此,这种情况下,随着访问的并发数越来越高,就会产生大量的数据库连接。也就是我们在压测时出现的情况。
           关于Django每次接受到请求和处理完请求时对数据库连接的操作,最后会从源码上来看看。

       使用CONN_MAX_AGE减少数据库请求
           上面说了,每次请求都会创建新的数据库连接,这对于高访问量的应用来说完全是不可接受的。因此在Django1.6时,提供了持久的数据库连接,通过DATABASE配置上添加CONN_MAX_AGE来控制每个连接的最大存活时间。具体使用可以参考最后的链接。
           这个参数的原理就是在每次创建完数据库连接之后,把连接放到一个Theard.local的实例中。在request请求开始结束的时候,打算关闭连接时会判断是否超过CONN_MAX_AGE设置这个有效期。这是关闭。每次进行数据库请求的时候其实只是判断local中有没有已存在的连接,有则复用。

           基于上述原因,Django中对于CONN_MAX_AGE的使用是有些限制的,使用不当,会事得其反。因为保存的连接是基于线程局部变量的,因此如果你部署方式采用多线程,必须要注意保证你的最大线程数不会多余数据库能支持的最大连接数。另外,如果使用开发模式运行程序(直接runserver的方式),建议不要设置CONN_MAX_AGE,因为这种情况下,每次请求都会创建一个Thread。同时如果你设置了CONN_MAX_AGE,将会导致你创建大量的不可复用的持久的连接

       CONN_MAX_AGE设置多久
            CONN_MAX_AGE的时间怎么设置主要取决于数据库对空闲连接的管理,比如你的MySQL设置了空闲1分钟就关闭连接,那你的CONN_MAX_AGE就不能大于一分钟,不过DBA已经习惯了程序中的线程池的概念,会在数据库中设置一个较大的值。

         优化结果:
               了解了上述过程之后,配置了CONN_MAX_AGE参数,再次测试,终于没有接到DBA通知,查看数据库连接数,最大700多
         最好的文档是代码:
               Django的文档上只是简单得介绍了原理和使用方式,对于好奇的同学来说,这个显然是不够的。于是我也好奇的看了下代码,把相关的片段贴到这里

    [Python] 纯文本查看 复制代码
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    #### 请求开始
    # django.core.handlers.wsgi.py
    class WSGIHandler(base.BaseHandler):
        initLock = Lock()
        request_class = WSGIRequest
     
        def __call__(self, environ, start_response):
            #  ..... 省略若干代码
            # 触发request_started这个Signal
            signals.request_started.send(sender=self.__class__, environ=environ)
            try:
                request = self.request_class(environ)
            except UnicodeDecodeError:
                logger.warning('Bad Request (UnicodeDecodeError)',
                    exc_info=sys.exc_info(),
                    extra={
                        'status_code': 400,
                    }
                )
     
    # 请求结束
     
    class HttpResponseBase(six.Iterator):
        """
        An HTTP response base class with dictionary-accessed headers.
     
        This class doesn't handle content. It should not be used directly.
        Use the HttpResponse and StreamingHttpResponse subclasses instead.
        """
     
        def close(self):
            for closable in self._closable_objects:
                try:
                    closable.close()
                except Exception:
                    pass
            # 请求结束时触发request_finished这个触发器
            signals.request_finished.send(sender=self._handler_class)



    这里只是触发,那么在哪对这些signal进行处理呢?
     

    [Python] 纯文本查看 复制代码
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    # django.db.__init__.py
    from django.db.utils import ConnectionHandler
    connections = ConnectionHandler()
     
    # Register an event to reset saved queries when a Django request is started.
    def reset_queries(**kwargs):
        for conn in connections.all():
            conn.queries_log.clear()
    signals.request_started.connect(reset_queries)
     
    # Register an event to reset transaction state and close connections past
    # their lifetime.
    def close_old_connections(**kwargs):
        for conn in connections.all():
            conn.close_if_unusable_or_obsolete()
    signals.request_started.connect(close_old_connections)
    signals.request_finished.connect(close_old_connections)



    在这里对触发的signal进行了处理,从代码上看,逻辑就是,遍历所有已存在的链接,关闭不可用的连接。
    再来看ConnectionHandler代码:
     

    [Python] 纯文本查看 复制代码
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    class ConnectionHandler(object):
     
        def __init__(self, databases=None):
            """
            databases is an optional dictionary of database definitions (structured
            like settings.DATABASES).
            """
            # databases来自settings对数据库的配置
            self._databases = databases
            self._connections = local()
     
        @cached_property
        def databases(self):
            if self._databases is None:
                self._databases = settings.DATABASES
            if self._databases == {}:
                self._databases = {
                    DEFAULT_DB_ALIAS: {
                        'ENGINE': 'django.db.backends.dummy',
                    },
                }
            if DEFAULT_DB_ALIAS not in self._databases:
                raise ImproperlyConfigured("You must define a '%s' database" % DEFAULT_DB_ALIAS)
            return self._databases
     
        def __iter__(self):
            return iter(self.databases)
     
        def all(self):
            # 调用__iter__和__getitem__
            return [self[alias] for alias in self]
     
        def __getitem__(self, alias):
            if hasattr(self._connections, alias):
                return getattr(self._connections, alias)
     
            self.ensure_defaults(alias)
            self.prepare_test_settings(alias)
            db = self.databases[alias]
            backend = load_backend(db['ENGINE'])
            # 关键在这了,这个就是conn
            conn = backend.DatabaseWrapper(db, alias)
            # 放到 local里
            setattr(self._connections, alias, conn)
            return conn


    这个代码的关键就是生成对于backend的conn,并且放到local中。backend.DatabaseWrapper继承了db.backends.__init__.BaseDatabaseWrapper类的 close_if_unusable_or_obsolete() 的方法,来直接看下这个方法。

    [Python] 纯文本查看 复制代码
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    class BaseDatabaseWrapper(object):
        """
        Represents a database connection.
        """
     
        def connect(self):
            """Connects to the database. Assumes that the connection is closed."""
            # 连接数据库时读取配置中的CONN_MAX_AGE
            max_age = self.settings_dict['CONN_MAX_AGE']
            self.close_at = None if max_age is None else time.time() + max_age
     
        def close_if_unusable_or_obsolete(self):
            """
            Closes the current connection if unrecoverable errors have occurred,
            or if it outlived its maximum age.
            """
            if self.connection is not None:
                # If the application didn't restore the original autocommit setting,
                # don't take chances, drop the connection.
                if self.get_autocommit() != self.settings_dict['AUTOCOMMIT']:
                    self.close()
                    return
     
                # If an exception other than DataError or IntegrityError occurred
                # since the last commit / rollback, check if the connection works.
                if self.errors_occurred:
                    if self.is_usable():
    展开全文
  • 但凡介绍数据库连接池的文章,都会说“数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能...

    但凡介绍数据库连接池的文章,都会说“数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。”

    这句话虽然说得很好,但也很让人疑惑。比如,多个请求是怎样共用数据库连接池啊?

    其实,数据库连接池主要是利用了程序,静态变量与静态方法的概念实现的。静态变量和静态方法,是程序运行时,就被加载到内存中的。该进程中所有对于它的访问,都是对“唯一”的它的访问。所以,才能有数据库连接池被共享的概念。

    可以看到,静态变量a以及静态方法add,即使类A从未被实例化过,它们也都会被加载到内存中。

    另外,在python的此次运行(一个进程)中,多次对a的操作,都是对为一个的这个a变量的操作,所以它的值是在被操作后累加的。

    这个在我上面简单的例子中很好理解。那么如何理解Web应用程序(如django程序)在接到url请求时的场景呢?在多个请求时,他们是如何可以共享数据库连接池的?

    我写了一个简单的例子:

    Test model,使用了单例模式,它的功能是调用sqlalchemy.pool中的数据库连接池。

    而views.py的index方法,则是调用Test的getinstance方法获得它的实例,同时用它的数据库连接池。

    为了看得清楚,我在这个方法中增加打印了当前所属进程的pid,test和test.connpool信息。

    首先要说明一点,apache在windows和linux中的运行方式不尽相同(windows是两个httpd进程,一个父进程,一个子进程,子进程里面多个线程处理请求)。在linux中,默认用prefork的方式运行。即一个父进程,多个子进程,这多个子进程负责处理web请求。

    如下图所示:

    然后我们尝试多次url请求(适当变化url,避免缓存);并记录结果:

    http://10.67.2.21:8081/ips/
    count:3,processid:20016<br/>test:<ipsapp.models.Test object at 0x7f2b1070ac50>,connpool:<sqlalchemy.pool.QueuePool object at 0x7f2b1070ad10>


    http://10.67.2.21:8081/ips/?user=kjsdkfjsdf&kljsdlkfjsdf
    count:3,processid:20013<br/>test:<ipsapp.models.Test object at 0x7f2b107c6c10>,connpool:<sqlalchemy.pool.QueuePool object at 0x7f2b107c6cd0>


    http://10.67.2.21:8081/ips/?user=kjsdkfjsdf&kljsdlkfjsdf&pass=ksjdkjdf
    count:3,processid:20018<br/>test:<ipsapp.models.Test object at 0x7f2b103c6c50>,connpool:<sqlalchemy.pool.QueuePool object at 0x7f2b103c6d10>


    http://10.67.2.21:8081/ips/?user=123u42i3u4
    count:3,processid:20016<br/>test:<ipsapp.models.Test object at 0x7f2b1070ac50>,connpool:<sqlalchemy.pool.QueuePool object at 0x7f2b1070ad10>


    http://10.67.2.21:8081/ips/?user=123u42i3u4&tewstsjdfkjslfj
    count:3,processid:20013<br/>test:<ipsapp.models.Test object at 0x7f2b107c6c10>,connpool:<sqlalchemy.pool.QueuePool object at 0x7f2b107c6cd0>


    http://10.67.2.21:8081/ips/?user=passwode
    count:3,processid:20018<br/>test:<ipsapp.models.Test object at 0x7f2b103c6c50>,connpool:<sqlalchemy.pool.QueuePool object at 0x7f2b103c6d10>


    http://10.67.2.21:8081/ips/?newiusd=kjsdkjfd&kjsdkjf=ksdjflksjdlkf
    count:3,processid:20016<br/>test:<ipsapp.models.Test object at 0x7f2b1070ac50>,connpool:<sqlalchemy.pool.QueuePool object at 0x7f2b1070ad10>


    apache pid             Test object               QueuePool object
    20016                  0x7f2b1070ac50            0x7f2b1070ad10
    20013                  0x7f2b107c6c10            0x7f2b107c6cd0
    20018                  0x7f2b103c6c50            0x7f2b103c6d10
    20016                  0x7f2b1070ac50            0x7f2b1070ad10
    20013                  0x7f2b107c6c10            0x7f2b107c6cd0
    20018                  0x7f2b103c6c50            0x7f2b103c6d10
    20016                  0x7f2b1070ac50            0x7f2b1070ad10

    我把分属于不同apache进程处理的请求用颜色标出了,在本例子中,7个请求,分配到了3个apache进程处理。可以看到,被同一个apache子进程处理的请求,是共用同一个test和test.connpool实例的,即他们共享数据库连接池。

    所以,数据库连接池,对于web请求而言,是属于同一个apache子进程处理的请求共用一个数据库连接池。
    --------------------- 
    作者:rongyongfeikai2 
    来源:CSDN 
    原文:https://blog.csdn.net/rongyongfeikai2/article/details/45245427 
    版权声明:本文为博主原创文章,转载请附上博文链接!

     

     

     

    阅读上述转载文章,收获一下知识点:

    1、python可通过静态方法和静态变量来实现在同一个进程下共享对象问题;

    2、django的web请求中,同一个进程下,数据库连接池是共享的,(但要说明,连接池对象一定要是静态变更),不同进程下使用不同数据库连接实例,这也验证了上述观点;

    3、django在开发模式下(runserver)只启动一个进程,即所有请求都共享一个连接池,当django集成apache或nginx等正规web服务器后,可能启动多个进程,启动的多个进程每个进程都会实例化一个数据库连接池实例。

    展开全文
  • models 是对数据库操作的 ORM 加入子应用 生成迁移脚本 python manage.py makemigrations on_delete 级联删除

    第三步: 项目的数据库模型

    (1). 连接 数据库配置

    在 settings.py 文件中,通过DATABASES项进行数据库设置
    Django 支持的数据库包括: sqlite 、 mysql 等主流数据库
    Django 默认使用 **SQLite** 数据库
    

    Django数据库设置参考文档

    其中ENGINE设置为数据库后端使用。内置数据库后端有:

    'django.db.backends.postgresql'
     'django.db.backends.mysql'
     'django.db.backends.sqlite3'
      'django.db.backends.oracle'
    

    使用sqlite

    (2). 创建数据库模型

    本示例完成“图书-英雄”信息的维护,需要存储两种数据:图书、英雄
    图书表结构设计: 表名: Book

    图书名称: title
    图书发布时间: pub_date
    

    英雄表结构设计: 表名: Hero

    英雄姓名: name
    英雄性别: gender
    英雄简介: hcontent
    所属图书: hbook
    

    图书-英雄的关系为一对多

    (3). 生成数据库表

    激活模型:编辑 settings.py 文件,将应用加入到 INSTALLED_APPS 中

    生成迁移文件:根据模型类生成 sql 语句

    python manage.py makemigrations
    产生的迁移文件如下图

    生成数据库表bookApp_book,数据库表中有三列信息: id ,title ,pub_date

    from django.db import models
    
    """
    名词: 
        ORM(Object Ralational Mapping,对象关系映射)用来把对象模型表示的对象映射到基于S Q L 的关系模型数据库结构中去。
        这样,我们在具体的操作实体对象的时候,就不需要再去和复杂的 SQ L 语句打交道,只需简单的操作实体对象的属性和方法。
    一对多关系:外键写在多的一端
    book:hero = 1:n
    """
    # Create your models here.
    
    # 类对应数据库表, 表名称默认为bookApp_book.
    class Book(models.Model):
        # 属性对应数据库表的列名,默认会添加id这一列。
        name = models.CharField(max_length=40, verbose_name="书籍名称")
        pub_date = models.DateField(verbose_name="出版日期")
    
        # 魔术方法,字符串友好展示, 便于调试代码
        def __str__(self):
            return  self.name
    
        class Meta:
            # 单数时显示的名称
            verbose_name = "图书管理"
            # 复数时显示的名称
            verbose_name_plural = verbose_name
    
    
    
    """
    更多查询操作请参考网址: https://docs.djangoproject.com/zh-hans/3.1/topics/db/queries/
    """
    # 类对应数据库表, 表名称默认为bookApp_hero.
    class Hero(models.Model):
        # 属性对应数据库表的列名,默认会添加id这一列。
        gender_choice = [
            (1, "男"),
            (2, "女")
        ]
        name = models.CharField(max_length=20, verbose_name="人物名称")
        # 性别只能选择男(1)或者女(2)
        gender = models.IntegerField(choices=gender_choice, verbose_name="性别")  # 1, 2
        content = models.TextField(max_length=1000, verbose_name="人物描述")
        # 外键关联, 如果删除书籍时,相关hero对应的书籍设置为空。
        book_id = models.ForeignKey(Book, on_delete=models.SET_NULL,
                                    null=True, verbose_name="书籍id")
    
        def __str__(self):
            return  self.name
    
        # Meta选项的更多使用请参考网址: https://docs.djangoproject.com/zh-hans/3.1/ref/models/options/
        class Meta:
            # 单数时显示的名称
            verbose_name = "人物管理"
            # 复数时显示的名称
            verbose_name_plural = verbose_name
    

    在这里插入图片描述

    加入子应用
    在这里插入图片描述
    生成迁移脚本

    python manage.py makemigrations
    执行迁移:执行 sql 语句生成数据表
    python manage.py migrate
    在这里插入图片描述

    在这里插入图片描述

    (4). 数据库模型基本操作

    现在进入交互式的Python shell,并使用 Django 提供的免费API

    pip install ipython
    python manage.py shell
    

    引入需要的包:

    from bookApp.models import Hero, Book
    

    查询所有图书信息:

    Book.objects.all()
    

    在这里插入图片描述

    新建图书信息:

    from datetime import datetime
    book = Book(title="射雕英雄传", pub_date=datetime(year=1990,month=1,day=10)) 
    book.save()
    

    在这里插入图片描述
    退出当前环境,重新进入

    在这里插入图片描述

    查找图书信息:

    book = Book.objects.get(pk=1) 
    book.id
    book.title
    book.pub_date
    

    在这里插入图片描述
    在这里插入图片描述

    修改图书信息

    book.title = "天龙八部"
    book.save()
    

    删除图书信息:

    book.delete()
    

    在这里插入图片描述

    添加关联对象

    # 书籍的创建
    book = Book(title="倚天屠龙记", pub_date=datetime(year=1990,month=1,day=10))
    book.save()
    

    在这里插入图片描述

    # 人物的创建
    info1 = "峨眉第四代掌门人,先为峨眉派掌门灭绝师太的徒儿,颇获灭绝师太欢心并对她>青睐有加,将峨 眉派镇派之宝“蛾眉九阳功”传给了她,张无忌的追求者之一。"
    info2 = "原名敏敏特穆尔,汝阳王(朝廷大将军察罕特穆尔)的女儿,封号“绍敏郡主”,>赵敏是她的汉 名,是从她的封号“绍敏郡主”而来。" 
    hero1 = Hero(name="周芷若", gender=False, info=info1)
    hero2 = Hero(name="赵敏", gender=False, info=info2)
    hero1.Book=book
    hero2.Book=book 
     hero1.save()
     hero2.save()
    

    在这里插入图片描述 hero1.book_id = book 在save前加

    获得关联集合:返回当前book对象的所有hero

    book.hero_set.all()
    

    在这里插入图片描述
    查找书籍

     books = Book.objects.filter(name__contains="红")
     books = Book.objects.filter(pub_date__lt=date.today())
     books = Book.objects.exclude(name__contains="红")
    

    在这里插入图片描述
    在这里插入图片描述

    有一个 Hero 存在,必须要有一个 Book 对象,提供了创建关联的数据:

    book.hero_set.create(name="张无忌", gender=True, content="武当派第二代“张五侠”张翠山与天鹰教紫微堂堂主殷素素的儿子")
    

    第四步: 启用后台Admin 站点管理

    站点分为“内容发布(后台管理)”和“公共访问(前台管理)”两部分
    “内容发布”的部分负责添加、修改、删除内容,开发这些重复的功能是一件单调乏味、缺乏创造力
    的工作。
    因此, Django 会根据定义的模型类完全自动地生成管理模块

    Django 框架中有一个非常强大的应用功能: 自动管理界面。 常被Web平台管理者使用,去管理整个
    Web平台。
    默认情况下,在 settings.py 配置文件中 INSTALLED_APPS 包含以下应用程序,为了后续的开发,默
    认这些应用程序都是包含在里面的。
    在这里插入图片描述(0)(1)(2)详细操作见前篇博客

    (0). 数据库迁移

    使用这些 Django 自带的应用程序,需要我们在数据库中创建一些数据表对应,然后才能使用它们。

    python manage.py makemigrations
    python manage.py migrate
    

    (1). 创建管理员用户

    # 按提示输入用户名、邮箱、密码
    python manage.py createsuperuser
    启动服务器,通过 “127.0.0.1:8000/admin” 访问,输入上面创建的用户名、密码完成登录
    进入管理站点,默认可以对 groups、users 进行管理
    
    

    (2). 管理界面本地化

    编辑 settings.py 文件,设置编码、时区

    LANGUAGE_CODE = 'zh-hans' 
    TIME_ZONE = 'Asia/Shanghai'
    

    (3). 自定义模型加入后台管理

    打开bookApp/admin.py 文件,注册模型

    from django.contrib import admin
    from models import Book,Hero
    admin.site.register([Book,Hero])
    

    在这里插入图片描述
    刷新管理页面,可以对 Book 的数据进行增删改查操作 ;
    问题一: python2 版本中, 如果在 str 方法中返回中文,在修改和添加时会报 ascii 的错误
    在 str() 方法中,将字符串末尾添加 “.encode(‘utf-8’)” 进行字符串编码
    问题二: 后台管理时, Book管理显示的是英文,如何变成中文

    在这里插入图片描述# bookApp/models.py
    文件添加

       # Meta选项的更多使用请参考网址: https://docs.djangoproject.com/zh-hans/3.1/ref/models/options/
        class Meta:
            # 单数时显示的名称
            verbose_name = "人物管理"
            # 复数时显示的名称
            verbose_name_plural = verbose_name
    

    在pycharm的terminal界面一直运行,python manage.py runserver 9999
    更改文件后刷新网页即可
    在这里插入图片描述

    (4). 自定义管理页面

    Django 提供了 admin.ModelAdmin 类
    通过定义 ModelAdmin 的子类,来定义模型在 Admin 界面的显示方式

    #bookApp/admin.py
    from django.contrib import admin
    from bookApp.models import  Book,Hero
    # 自定义后台站点管理的拓展阅读: https://docs.djangoproject.com/zh-hans/3.1/ref/contrib/admin/
    # Register your models here.
    
    class HeroInline(admin.StackedInline):
        model = Hero
        extra = 3
    
    #书籍自定义管理页面
    class BookAdmin(admin.ModelAdmin):
        # 列表页展示的设置
        list_display =  ['id', 'name', 'pub_date']
        list_filter = ['pub_date']
        search_fields = ['name']
        list_display_links = ['name']
        list_per_page =  5
        inlines =  [HeroInline]
    #任务自定义管理页面
    class HeroAdmin(admin.ModelAdmin):
        # 列表页展示的设置
        list_display =  ['id', 'name', 'gender']
        list_filter = ['gender']
        search_fields = ['name', 'content']
        list_display_links = ['name']
        list_per_page =  5
    
    
        # 增加和编辑页的设置
        fieldsets = [('必填信息', {'fields': ['name', 'book_id']}),
                     ('选填信息', {'fields': ['gender', 'content']}), ]
    
    #关联注册
    admin.site.register(Book, BookAdmin)
    admin.site.register(Hero, HeroAdmin)
    

    列表页属性性

    list_display:显示字段,可以点击列头进行排序 list_display = [‘pk’, ‘title’, ‘pub_date’]
    list_filter:过滤字段,过滤框会出现在右侧 list_filter = [‘title’]
    search_fields:搜索字段,搜索框会出现在上侧 search_fields = [‘title’]
    list_per_page:分页,分页框会出现在下侧 list_per_page = 10

    在这里插入图片描述

    添加、修改页属性

    fields:属性的先后顺序 fields = [‘pub_date’, ‘title’]
    fieldsets :属性分组, 注意: fields和fieldsets 只能设置一个. fieldsets = [(‘基础信息’, {‘fields’: [‘title’]}), (‘详细信息’, {‘fields’: [‘pub_date’]}), ]

    在这里插入图片描述

    关联对象
    对于 Hero 模型类,有两种注册方式
    方式一:与 Book 模型类相同
    方式二关联注册

    admin.StackedInline : 内嵌关联注册类
    admin.TabularInline : 表格 关联注册类
    #bookApp/admin.py
    class HeroInline(admin.StackedInline):
        model = Hero
        extra = 3
    class BookAdmin(admin.ModelAdmin):
        # 列表页展示的设置
        list_display =  ['id', 'name', 'pub_date']
      .....
        inlines =  [HeroInline]    
    
    

    在这里插入图片描述

    Django快速入门: 前台管理

    第一步: URLconf 路由管理

    在 Django 中,定义 URLconf 包括正则表达式、视图两部分 。
    Django 使用正则表达式匹配请求的URL,一旦匹配成功,则调用应用的视图 。
    注意:只匹配路径部分,即除去域名、参数后的字符串 。
    在主配置文件中添加子配置文件,使主 urlconf 配置连接到子模块的 urlconf 配置文件
    

    主配置文件配置如下, 已经配置过, 可以忽略此步骤:

    # BookManage/urls.py
    from django.contrib import admin
    from django.urls import path, include
    from bookApp.views import index
    # 当用户访问的url地址以book开头, 请访问bookApp.urls这个url配置文件进行匹配并执行对应 的视图函数
    urlpatterns = [
       path('admin/', admin.site.urls),
       path('book/', include('bookApp.urls')),
    ]
    

    bookApp 子应用的子配置文件如下:

    # bookApp/urls.py
    from django.urls import path
    
    from bookApp import views
    
    urlpatterns = [
        # 当用户访问路径是book/, 执行views.index视图函数。
        path(r'', views.index, name='index'),
        # 显示书籍的详情页, 接收一个int值并赋值给id
        path(r'<int:id>/', views.detail, name='detail'),
    ]
    

    第二步: 视图函数处理业务逻辑

    在 Django 中,视图对WEB请求进行回应( response )。
    视图接收 reqeust 请求对象作为第一个参数,包含了请求的信息 。
    视图函数就是一个Python函数,被定义在 views.py 中 。
    定义完成视图后,需要配置 urlconf ,否则无法处理请求。
    

    在方法中调用模板 :

    # bookApp/views.py
    from django.shortcuts import render
    from django.http import HttpResponse
    # Create your views here.
    #试图: 对用户的请求(request)进行 业务逻辑操作,最后返回给用户一个相应(response)
    from bookApp.models import Book
    def index(request):
        print("用户请求的路径:", request.path)
        books = Book.objects.all()
        # 返回响应信息
        # return  HttpResponse(books)
        # 渲染: 将上下文context{'books': books}填充到book/index.html代码的过程。
        return render(request, 'book/index.html', {'books': books})
    
    
    def detail(request, id):
        """书籍详情页信息"""
        book = Book.objects.filter(id=id).first()
        heros = book.hero_set.all()
        return render(request, 'book/detail.html',
                      {'book': book, 'heros': heros})
    

    第三步: 模板管理实现好看的HTML页面

    作为Web 框架, Django 需要一种很便利的方法以动态地生成HTML。最常见的做法是使用模板。
    模板包含所需HTML 输出的静态部分,以及一些特殊的语法,描述如何将动态内容插入。

    (1) 模板引擎配置

    创建模板的目录如下图:

    在这里插入图片描述

    #templates/book/detail.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>{{book.name}}</h1>
    <h1>{{book.pub_date}}</h1>
    <h1>{{heros}}</h1>
    </body>
    </html>
    
    #templates/book/index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1 style="color: blueviolet">图书管理系统</h1>
    <ul>
        {% for book in books %}
            <li><a href="/book/{{ book.id }}/">{{ book.name }}</a></li>
        {% endfor %}
    </ul>
    </body>
    </html>
    

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    (2) 模板语法: 变量

    变量输出语法
    { { var } }

    当模版引擎遇到一个变量,将计算这个变量,然后将结果输出。

    变量名必须由字母、数字、下划线(不能以下划线开头)和点组成。

    当模版引擎遇到点("."),会按照下列顺序查询:

    字典查询,例如: foo[“bar”]
    属性或方法查询,例如: foo.bar
    数字索引查询,例如: foo[bar]

    如果变量不存在, 模版系统将插入’’ (空字符串)。

    (3) 模板语法: 常用标签

    语法
    { % tag % }

    作用
    在输出中创建文本。
    控制循环或逻辑。
    加载外部信息到模板中
    

    for标签

    
    {% for ... in ... %}
       循环逻辑
    {% endfor %}
    

    if标签

    {% if ... %} 
     逻辑1
    {% elif ... %} 
      逻辑2 
    {% else %}
      逻辑3 
    {% endif %}
    

    comment标签

    {% comment %} 
       多行注释
    {% endcomment %}
    

    include标签
    加载模板并以标签内的参数渲染

    {% include "base/left.html" %}
    

    url :反向解析

    {% url 'name' p1 p2 %}
    
    

    csrf_token 标签
    用于跨站请求伪造保护

    {% csrf_token %}
    

    多种html页面
    直接在pycharm的页面中点击
    1.标题标签

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>标题</h1>
    <h2>标题</h2>
    <h3>标题</h3>
    <h4>标题</h4>
    <h5>标题</h5>
    <h6>标题</h6>
    </body>
    </html>
    

    在这里插入图片描述

    2.列表标签

    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    /* 无序列表 */
    <ul>
        <li>book1</li>
        <li>book2</li>
        <li>book3</li>
        <li>book4</li>
    </ul>
    
    /* 有序列表 */
    <ol>
        <li>book1</li>
        <li>book2</li>
        <li>book3</li>
        <li>book4</li>
    </ol>
    </body>
    </html>
    

    3.图片标签

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <img src="cat.jpg">
    </body>
    </html>
    

    4.链接标签

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <a href="https://www.baidu.com">百度一下</a>
    <a href="https://www.baidu.com"><img src="cat.jpg"></a>
    </body>
    </html>
    

    5.表格标签

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    {# r: row #}
    <table border="1">
        <tr>
            <td>主机名</td>
            <td>IP</td>
        </tr>
        <tr>
            <td>localhost</td>
            <td>127.0.0.1</td>
        </tr>
            <tr>
            <td>server1</td>
            <td>127.0.0.1</td>
        </tr>
    </table>
    </body>
    </html>
    

    6.表单标签

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form>
        用户名: <input type="text" placeholder="username"><br/>
        密码: <input type="password" placeholder="password"><br/>
        <input type="submit" value="登录">
    </form>
    </body>
    </html>
    

    Django请求的生命周期

    wsgi : 封装请求后交给后端的web框架( Flask、Django )。
    请求中间件: 对请求进行校验或在请求对象中添加其他相关数据,例如: csrf、 request.session 。
    路由匹配: 根据浏览器发送的不同 url 去匹配不同的视图函数。
    视图函数: 在视图函数中进行业务逻辑的处理,可能涉及到: ORM、Templates 。
    响应中间件: 对响应的数据进行处理。
    wsgi : 将响应的内容发送给浏览器。

    在这里插入图片描述
    待更新

    展开全文
  • 我们在 django-rest-framework解析请求参数 文章中完成了接口文档到参数解析, 一个完整的流程中还缺少对数据库的操作. 本篇内容为django连接数据库, 并编写一个image表用来存储图片路径, 编写图片上传接口和查看...
  • Django MySQL 数据库连接

    2017-10-25 16:54:00
    default:0 保存在每个请求结束时关闭数据库连接的历史行为。 None:保持长连接 Other:xx 单位秒 连接管理 Django连接发生在每次请求时,如果没有可用连接便主动建立连接,如果限制了连接时间的话。 警告 每个...
  • Django构建数据库缓存

    千次阅读 2019-02-20 13:02:47
    由于Django构建得是动态网站,每次客户端请求都要严重依赖数据库,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问...
  • 上周对我们用Django+Django-rest-framework提供的一套接口进行了压力测试。压测的过程中,收到DBA通知——数据库连接数过多,希望我们优化下...Django数据库的链接处理是这样的,Django程序接受到请求之后,在第一...
  • 在实际开发中,有的业务可能需要经常的请求一个处理比较慢,变化又不频繁的接口,这时候就根据需求就可以使用缓存来加速后端接口的处理返回.,在这里我使用数据库进行缓存(也可以使用其他方式缓存) # setting.py ...
  • Django数据库并发处理

    千次阅读 2018-08-25 03:38:02
    比如限量商品在热销时,当多个用户同时请求购买商品时,最终修改的数据就会出现异常 下面我们来写点代码还原一下现象: 1.新建项目Optimistic locking,创建应用app01,编辑models创建一张表并执行数据库迁移,...
  • 为诊断目的记录 django 请求数据 所有匹配过滤器功能的请求都将记录在数据库中。 记录以下数据: * 用户(如果经过身份验证) * IP 地址 * 请求路径(url) * 请求方法 * 请求参数 * 会话密钥 * 会话快照 * 请求 ...
  • Django数据库模型的使用

    千次阅读 2015-03-01 22:28:12
    简介: Django试图去支持各式各样的后台数据库,但是所有的... 持久连接避免重新建立在每个请求数据库连接的开销,由参数CONN_MAX_AGE控制连接时间0表示请求完后自动断开连接,none表示永久连接 2.连接管理 在Django
  • 查了很多方面,从模板引擎到请求(request),再到django配置,nginx等等,都没有查出原因。虽然也查过是不是数据库的原因,但都因为查的不够深入,没有查出所以然。 有一次在处理权限问题时,不断地追...
  • 开发过程中需要根据前端请求数据库中查询符合条件数据,然后组织数据返回给浏览器下载,网上找到的django提供下载文件功能多以读取服务器已存在文件再返回给用户,本次需求服务器没有该文件,同时也不想生成该临时...
  • /Add/AttributeError type object 'Article' has no attribute 'object' 请求方法: ... Django版本: 2.2.1 例外类型: 属性错误 例外值: type object 'Article' has n...
  • 今天小编就为大家分享一篇浅谈django url请求数据库连接池的共享问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • django默认会在请求进来的时候创建数据库连接,并在请求完成后关闭连接。从以上三方面的资源消耗来说,较多的连接会明显降低应用响应速度、增加服务器端压力。 使用连接池就是一个简单的缓解这种压力的办法。 设想...
  • 请求方式为post方式: 上传图片部分 import requests def main(): with open('../2222.jpg','rb') as f: img = f.read() file = {'image':('img.jpg',img,'image/jpg')} # image为字段名 不能修改 connt = ...
  • 2018-9-5 18:10:52 先贴上笔记 day61 2018-04-28 1. 内容回顾 1. HTTP协议消息的格式: 1. 请求(request) 请求方法 路径 HTTP/1.1\r\n k1:v1\r\n ...\r\n \...
  • form表单知识回顾三、 request对象方法初识四、 pycharm链接数据库五、 django链接数据库(MySQL)1.在settings.py配置文件修改配置2.在项目文件夹或者应用文件夹内的__init__.py文件中书写固定的代码六、 django ...
  • 1.请求url url(r'^grades/(\d+)$', views.grade_stu), 2.定义视图 def grade_stu(request, num): grade = Grades.objects.get(pk = num) #获取班级 stu = grade.students_set.all() #通过班级获取学生 return ...
  • 通过CONN_MAX_AGE优化Django数据库连接: 上周对我们用Django+Django-rest-framework...Django数据库的链接处理是这样的,Django程序接受到请求之后,在第一访问数据库的时候会创建一个数据库连接,直到请求结束,
  • Django使用mysql数据库 1. pip install pymysql 2. 在 __init__.py 添加 import pymysql pymysql.install_as_MySQLdb() mysite/ manage.py mysite/ __init__.py settings.py urls.py wsgi.py 3. 在 ...
  • Django请求生命周期

    2018-07-09 19:32:00
    生命周期: 指浏览器访问开始,经过Django都发生了什么 ? 1 首先客服端发送http请求,把请求体(请求头和请求内容)生成 2 服务器接收请求后,根据路由映射表一个一个匹配.匹配成功后,后面不匹配了(从上到下执行) 3 ...
  • 文章目录Django请求生命周期流程图与ORM表关系一、ORM表关系1.三种对应关系1.1 一对多1.2 一对一1.3 多对多2.表关系判断3.表关系举例4.ORM 针对外键字段的创建位置5.创建外键示例二、Django生命请求周期流程图 ...
  • Django数据库连接池(mysql)

    千次阅读 2016-04-14 16:40:08
    都知道django每次请求都会连接数据库和释放数据库连接。Django为每个请求使用新的数据库连接。一开始这个方法行得通。然而随着服务器上的负载的增加,创建/销毁连接数据库开始花大量的时间。要避免这个,你可以使用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,602
精华内容 640
关键字:

django请求数据库