Django源码分析-ORM框架解读(二)

1.Django内部读取配置信息源码分析

  • Django使用settings模块来管理配置信息。settings模块通常命名为settings.py,其中包含Django项目的各种配置选项。当运行Django项目时,配置将被读取并应用以配置应用程序的行为。

  • 下面是Django如何从settings模块中读取配置信息的内部过程。

    1. 位于django/conf/__init__.py文件下的django.conf.settings模块, 它包含一个名为LazySettings的类,负责在访问设置时进行懒加载。

      懒加载: Django使用懒加载来避免一次性导入和处理整个settings模块。这有助于提高性能,因为并非每个请求或命令都需要所有设置。

    2. LazySettings类使用LazyObject类进行延迟加载,直到实际需要设置时才进行加载。覆盖了LazyObject的__getattr__方法以在首次访问时加载设置。__getattr__是一个特殊方法,当尝试访问对象不存在的属性时会被调用

      	def __getattr__(self, name):
      		 # 在这里进行懒加载的逻辑
      		 # 首次访问时对象不存在的属性时才加载对象的实际值,而不是在对象创建时立即加载。
              if self._wrapped is empty:
              	 #对配置对象进行初始化,加载对象属性
                  self._setup(name)
              val = getattr(self._wrapped, name)
      
              if name in {'MEDIA_URL', 'STATIC_URL'} and val is not None:
                  val = self._add_script_prefix(val)
              elif name == 'SECRET_KEY' and not val:
                  raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.")
      		# 返回设置的值并将其缓存在self.__dict__中。
              self.__dict__[name] = val
              return val
      
    3. 通过LazySettings类的_setup方法中来加载项目配置,Settings类是一个用于表示Django项目配置的类。通常是先读取django/conf/global_settings.py文件中的默认配置,然后再使用用户的settings.py文件中的值进行更新

      	class LazySettings(LazyObject):
       		def _setup(self, name=None):
      			...
      	 	 self._wrapped = Settings(settings_module)
      
      	class Settings:
      	    def __init__(self, settings_module): 
      	    # 从global_settings.py文件中读取默认配置信息
      	    for setting in dir(global_settings):
      	            if setting.isupper():
      	                setattr(self, setting, getattr(global_settings, setting))
      			...
      	      # 读取将用户的setting.py的配置信息进行更新
      	    mod = importlib.import_module(self.SETTINGS_MODULE)
      	    self._explicit_settings = set()
      	    for setting in dir(mod):
      	        if setting.isupper():
      	            setting_value = getattr(mod, setting)
      	            # 检查元组形式的设置项的类型
      	            if (setting in tuple_settings and
      	                not isinstance(setting_value, (list, tuple))):
      	                raise ImproperlyConfigured("The %s setting must be a list or a tuple. " % setting) 
      	            # 将设置项赋值给实例
      	            setattr(self, setting, setting_value)
      	            self._explicit_settings.add(setting)
           	   ...
      
      

2.Django中连接类源码分析

1.首先,介绍一下在Django项目中管理和使用多个数据库连接时涉及到的相关类。ConnectionHandler 允许你通过别名获取数据库连接,而 ConnectionRouter 允许你在多数据库环境中定义路由规则,以便在执行查询时选择使用哪个数据库。ConnectionProxy 是一个用于访问默认数据库连接的代理类。代码位于django/db/__init__.py文件

# Django中用于管理数据库连接的类,它允许你通过连接别名(通常是数据库配置中的'default'等)获取数据库连接,执行查询等操作。
connections = ConnectionHandler()
#Django中用于数据库路由的类。它用于确定在执行数据库查询时使用哪个数据库连接。
router = ConnectionRouter()
#是一个用于访问默认数据库连接的代理类
connection = ConnectionProxy(connections, DEFAULT_DB_ALIAS)

2.具体创建数据库连接对象的过程如下:

  • 首先,调用位于django/db/util.pyConnectionHandler类的父类BaseConnectionHandler__getitem__() 方法获取数据库连接,通过别名 alias 进行索引。然后调用create_connection()创建一个新的数据库连接。

       class BaseConnectionHandler:
        ...
           # 在 BaseConnectionHandler 类中,通过使用 [] 运算符(如 connections[alias])调用了 __getitem__ 方法。
    	   def __getitem__(self, alias):
    	        try:
    	          # 通过 getattr(self._connections, alias) 尝试从 _connections 属性获取指定别名的数据库连接。
    	            return getattr(self._connections, alias)
    	        except AttributeError:
    	            # 如果在 _connections 中找不到对应别名的连接,会抛出 AttributeError 异常
    	            # 在这种情况下,会检查 alias 是否存在于 settings 中,即是否在项目的配置文件中定义了该别名的数据库连接。
    	            if alias not in self.settings:
    	                raise self.exception_class(f"The connection '{alias}' doesn't exist.")
    	        # 如果 alias 不存在于 _connections 中,并且在 settings 中存在,就调用 create_connection 方法创建一个新的数据库连接。
    	        conn = self.create_connection(alias)
    	        setattr(self._connections, alias, conn)
    	        return conn
          ...
             
        class ConnectionHandler(BaseConnectionHandler):
         ...
          	def create_connection(self, alias):
          		# 调用 ensure_defaults(alias) 确保数据库连接别名存在于 settings 中
    	        self.ensure_defaults(alias)
    	        # 调用 prepare_test_settings(alias) 准备用于测试的数据库设置(如果需要)
    	        self.prepare_test_settings(alias)
    	        # 获取指定别名的数据库配置信息,也就是setting.py文件中的配置的default中数据库信息
    	        db = self.databases[alias]
    	        backend = load_backend(db['ENGINE'])
    	        # 使用加载的后端创建 DatabaseWrapper 实例,该实例封装了数据库连接的配置信息。
    	        return backend.DatabaseWrapper(db, alias)
            ...
    
  • Django中数据库连接的核心类是位于django/db/backends/mysql/base.py文件BaseDatabaseWrapper类。这个类提供了数据库连接的基本功能,包括数据库的连接、断开连接、执行SQL查询等。其底层原理是BaseDatabaseWrapper 类在MySQLdb 库的基础上进行了一层封装,以便提供更高级别、更易用的接口,使得 Django ORM 层能够更方便地与 MySQL 数据库进行交互。

    MySQLdb 是一个 Python 库,提供了与 MySQL 数据库交互的功能。它是一个 MySQL 数据库的驱动程序,使得 Python 能够通过该库与 MySQL 数据库进行通信

    Django ORM 层是 Django 框架中的对象关系映射系统,它允许开发者使用 Python 对象来表示数据库中的数据,而不直接使用 SQL 查询语句。这一层提供了高级的、面向对象的接口,用于进行数据库操作。

    import MySQLdb as Database
    ....
    class BaseDatabaseWrapper:
    	....
        def get_new_connection(self, conn_params):
        	# 使用 MySQLdb创建新的 MySQL 连接
            connection = Database.connect(**conn_params)
            if connection.encoders.get(bytes) is bytes:
                connection.encoders.pop(bytes)
            return connection
      	 ....    
         def create_cursor(self, name=None):
            # self.connection属性值就是MySQLdb模块中的connectionn对象
            # 创建的cursor对象其实就是MySQLdb模块中的cursor对象
            cursor = self.connection.cursor()
        	return CursorWrapper(cursor)
    

3.Django中ORM相关类源码分析

Django的ORM系统允许开发者使用Python对象表示数据库中的表和记录。每个Django模型类对应数据库中的一个表。模型类定义了表的结构,包括字段和它们的属性。创建模型对象实际上是在内存中创建了一个Python对象,该对象与数据库中的记录相对应。

下面是一些 Django ORM 中用到的主要类以及它们之间的关系和作用:

Model 类:

作用: Model 类是 Django ORM 的核心,用于定义数据模型。每个模型类对应数据库中的一张表。
示例:一个简单的模型类如下:
class Book(models.Model):
 	title = models.CharField(max_length=200)
	author = models.CharField(max_length=100)

Manager 类:

作用: Manager 类是 Django 中模型类默认的管理器,用于提供数据库查询的接口。每个模型类都有一个默认的管理器(通常叫做 objects)。
示例:在上述的 Book 模型中,objects 就是 Manager 的实例。

QuerySet 类:

作用: QuerySet 是数据库查询的实际执行器。它提供了链式调用的方法,用于构建和执行数据库查询。
示例:在模型的管理器中,filter()、exclude() 等方法返回的就是 QuerySet 实例。

Query 类:

作用: Query 类用于构建数据库查询的结构。它是 QuerySet 的基础,负责生成 SQL 查询语句。
示例:在 QuerySet 内部,有一个 _query 属性,该属性是 Query 类的实例。

Field 类:

作用: Field 类是 Django 中模型字段的基类,用于定义模型的各种字段类型。
示例:CharField、IntegerField 等都是 Field 的子类,用于表示不同类型的字段。

3.1.RawQuery类的源码解读

  • RawQuery 类是 Django ORM 中的一个类,用于执行原始的 SQL 查询。这个类的源码位于 django/db/models/query.py文件下,主要用于处理复杂的数据库查询需求。

  • 可通过RawQuery进行原始的数据查询, 通过RawQuery('select * from app01_packetinfo','default')查询默认default数据库中app01_packetinfo表的数据:

    PS D:\桌面应用\浏览器\谷歌浏览器下载\django-3.2.23\code\first_project> python .\manage.py shell
    Python 3.9.10 (tags/v3.9.10:f2f3f53, Jan 17 2022, 15:14:21) [MSC v.1929 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>> from django.db.models.sql.query import RawQuery
    >>> rq = RawQuery('select * from app01_packetinfo','default')
    >>> rq.get_columns()
    ['id', 'name', 'type', 'desc']
    
  • RawQuery 类通过调用数据库连接的 cursor 方法获取游标,然后执行 SQL 查询语句,最后将执行结果保存在 self.cursor 属性中,通过 cursor.description 获取查询结果的列名,通过 cursor.fetchall() 获取所有的查询结果行。

class RawQuery:
 	def __init__(self, sql, using, params=()):
        self.params = params # 表示查询中的参数(默认为空)
        self.sql = sql # 原始 SQL 查询语句
        self.using = using # 使用的数据库别名
        self.cursor = None
    # chain 方法用于创建一个新的 RawQuery 对象,其中使用了新的数据库别名(using 参数)。
    def chain(self, using):
        return self.clone(using)
	# clone 方法用于创建当前 RawQuery 对象的副本,其中使用了新的数据库别名(using 参数)。这是为了支持链式操作,如Books.object.filter(),filter()...
    def clone(self, using):
        return RawQuery(self.sql, using, params=self.params)
	# get_columns 方法用于获取查询结果的列名
    def get_columns(self):
        if self.cursor is None:
        # 则调用 _execute_query 方法执行查询
            self._execute_query()
         # 使用数据库连接的 introspection 属性获取列名,并返回一个包含列名的列表。
        converter = connections[self.using].introspection.identifier_converter
        return [converter(column_meta[0])
                for column_meta in self.cursor.description]
	# __iter__ 方法实现了迭代器协议,允许使用 for item in RawQuery(...) 这样的语法
    def __iter__(self):
   		# 调用 _execute_query 方法执行 SQL 查询,获取数据库游标
        self._execute_query()
        # 将执行结果保存在 self.cursor 属性中。
        if not connections[self.using].features.can_use_chunked_reads:
            result = list(self.cursor)
        else:
            result = self.cursor
        return iter(result)
    # 主要负责执行原始 SQL 查询   
   def _execute_query(self):
   
       connection = connections[self.using]
       # 获取查询参数类型
       params_type = self.params_type
       # 获取参数适配器
       adapter = connection.ops.adapt_unknown_value
       if params_type is tuple:
           params = tuple(adapter(val) for val in self.params)
       elif params_type is dict:
           params = {key: adapter(val) for key, val in self.params.items()}
       elif params_type is None:
           params = None
       else:
           raise RuntimeError("Unexpected params type: %s" % params_type)

       self.cursor = connection.cursor()
       self.cursor.execute(self.sql, params)

3.2.Query类的源码解读

  • 在Django中,Query 类是用于构建数据库查询的核心类,它位于 django/db/models/query.py文件中。Query 类实际上是Django ORM系统中的一部分,用于表示数据库查询,并提供了许多方法和属性来构建和执行查询, 同时提供了链式调用和属性的灵活性

  • Query 类的核心原理通过构建查询条件、设置选择的字段、排序等属性,然后通过 SQLCompiler 将这些属性转换为 SQL 语句,并最终通过数据库连接执行这个 SQL 查询。这个类的设计充分利用了Python的链式调用和属性的特性,提供了一种灵活而强大的查询构建方式。

    class Query(BaseExpression):
    	 # ... 
        def __str__(self):
           # 使用 sql_with_params 方法获取 SQL 查询及其参数
           sql, params = self.sql_with_params()
           return sql % params
       
        def sql_with_params(self):
          # 实例化 SQLCompiler 对象:
           return self.get_compiler(DEFAULT_DB_ALIAS).as_sql()
       
        def get_compiler(self, using=None, connection=None):
         # 使用指定的别名(如果提供了)获取连接,并使用它来实例化一个 SQL 编译器
            if using is None and connection is None:
                raise ValueError("Need either using or connection")
            if using:
                connection = connections[using]
            return connection.ops.compiler(self.compiler)(self, connection, using)
    
    
  • SQLCompiler类是数据库查询的关键组件之一,它负责将Django ORM查询转换为特定数据库的SQL语句。该类位于django/db/models/sql/compiler.py文件中。

     class SQLCompiler:
    	...
    		# 核心方法
        def as_sql(self, with_limits=True, with_col_aliases=False):
        	#这是SQLCompiler类最关键的方法之一。它负责将Django查询转换为SQL语句。方法中的逻辑会处理查询中的条件、表、字段、排序等,并最终生成数据库可以执行的SQL语句。
        	...
        def execute_sql(self, result_type=MULTI, chunked_fetch=False, chunk_size=GET_ITERATOR_CHUNK_SIZE)
        	# 该方法用于执行通过as_sql生成的SQL语句。它在数据库上执行SQL查询,并返回结果。
           		...
    

3.3.RawQuerySet类源码解读

  • 在 Django 中,RawQuerySet 类是用于执行原始 SQL 查询并返回结果的类。位于django/db/models/query.py文件中, 它允许你执行任意的 SQL 查询语句,而不受 Django 模型的限制。

    RawQuerySet 类和 RawQuery类的区分
    联系:
         RawQuerySet`类和 RawQuery 类都与执行原始 SQL 查询有关。
         在某些情况下,RawQuerySet 类的实例可能使用 RawQuery 对象来表示其底层的原始 SQL 查询。
    区别:
         RawQuerySet 类是一个用于执行原始 SQL 查询并返回结果的查询集,类似于 Django 的 QuerySet。
         RawQuery 类是一个用于表示原始 SQL 查询的对象,它本身不执行查询,但可以用于构建原始查询的表示。 
    
  • RawQuerySet 类的功能主要通过其内部的 iterator()方法来实现。RawQuerySet 是 Django 中的一个查询集类,它允许执行原始 SQL 查询,并将结果映射到 Django 模型实例。

    class RawQuerySet(QuerySet):
    # ... 省略其他方法和属性 ...
    
    def iterator(self):
        db = self.db
        # 使用 connections 对象获取数据库连接,并通过连接的 ops.compiler 方法获取 SQL 编译器
        compiler = connections[db].ops.compiler('SQLCompiler')(
            self.query, connections[db], db
        )
    	# 使用 iter(self.query) 准备原始 SQL 查询的迭代器
        query = iter(self.query)
    
        try:
        # 调用 resolve_model_init_order 方法解析模型初始化的顺序,获取相关信息
            model_init_names, model_init_pos, annotation_fields = self.resolve_model_init_order()
             # 确保原始查询中包含模型的主键
            if self.model._meta.pk.attname not in model_init_names:
                raise exceptions.FieldDoesNotExist(
                    'Raw query must include the primary key'
                )
            model_cls = self.model
            # 获取模型类和模型字段,这些信息用于后续生成模型实例。
            fields = [self.model_fields.get(c) for c in self.columns]
            # 使用 SQL 编译器的 get_converters 方法获取字段转换器。
            converters = compiler.get_converters([
                f.get_col(f.model._meta.db_table) if f else None for f in fields
            ])
            if converters:
            # 如果存在字段转换器,通过 SQL 编译器的 apply_converters 方法将其应用于原始查询
                query = compiler.apply_converters(query, converters)  
            for values in query:
               # 遍历原始查询结果,为每一行创建一个模型实例
                model_init_values = [values[pos] for pos in model_init_pos]
                #  将查询结果中的值按照模型初始化的顺序关联到模型实例的属性上
                instance = model_cls.from_db(db, model_init_names, model_init_values)
                # 如果存在注解字段,将它们设置在模型实例上
                if annotation_fields:
                    for column, pos in annotation_fields:
                        setattr(instance, column, values[pos])
                 # 使用 yield 关键字逐个返回生成的模型实例
                yield instance
        finally:
        	# 在迭代结束后,如果原始查询具有自己的游标,关闭该游标。
            if hasattr(self.query, 'cursor') and self.query.cursor:
                self.query.cursor.close()
    
    

3.4.QuerySet类源码解读

  • Django中的QuerySet类是ORM系统的核心之一,位于django/db/models/query.py文件,用于构建数据库查询的条件,以及执行这些查询并返回结果。这样,开发者可以链式调用这些方法,构建出复杂的查询逻辑,最终通过执行查询获取结果。

    from django.db import models
    
    class Book(models.Model):
        title = models.CharField(max_length=100)
        author = models.CharField(max_length=50)
        published_date = models.DateField()
        price = models.DecimalField(max_digits=5, decimal_places=2)
    # Book.objects 是一个 Manager 对象,它返回一个 QuerySet 对象
    query_set = Book.objects
    # 创建并返回一个新的 QuerySet 对象,包含了 filter 的查询条件
    filtered_books = query_set.filter(author='John Doe')
    # 继续在原有的 QuerySet 基础上添加新的查询条件
    chained_query_set = filtered_books.exclude(published_date__year=2020).order_by('published_date')
    
  • QuerySet 支持切片操作,即可以通过 some_queryset[start:stop] 来限制查询结果的范围。在下面的例子中all_books[:5] 生成了一个新的 QuerySet 对象,该对象表示对所有图书的查询结果进行切片,但实际的数据库查询直到迭代 first_five_books 的时候才会触发。

    # 获取所有图书
    all_books = Book.objects.all()
    # 对查询结果进行切片,获取前5本图书
    first_five_books = all_books[:5]
    # 实际数据库查询发生在这里,只获取前5本图书的数据
    for book in first_five_books:
    	print(book.title)
    

    切片的实现原理:切片操作是在 __getitem__ 方法中触发的,当你对 QuerySet 对象进行切片时,__getitem__ 方法被调用。在 __getitem__ 方法中,Django 记录了切片的开始和结束索引,并创建一个新的 QuerySet 对象,该对象继承了原始 QuerySet 对象的查询条件和其他属性。当对新的 QuerySet 对象进行实际数据访问时(例如,通过迭代、调用 list()、调用 len() 等操作),Django 才会执行数据库查询,并将切片条件应用于查询。

    def __getitem__(self, k):
    #  检查传入的索引是否为整数或切片,如果不是则抛出 TypeError。
        if not isinstance(k, (int, slice)):
            raise TypeError(
                'QuerySet indices must be integers or slices, not %s.'
                % type(k).__name__
            )
        assert ((not isinstance(k, slice) and (k >= 0)) or
                (isinstance(k, slice) and (k.start is None or k.start >= 0) and
                 (k.stop is None or k.stop >= 0))), \
        
        # 如果结果缓存不为空,直接从缓存中获取
        if self._result_cache is not None:
            return self._result_cache[k]
    
        # 处理切片的情况,如果是切片操作,创建一个新的 QuerySet 对象,并设置查询的限制范围(start 和 stop)。
        if isinstance(k, slice):
            qs = self._chain()
            if k.start is not None:
                start = int(k.start)
            else:
                start = None
            if k.stop is not None:
                stop = int(k.stop)
            else:
                stop = None
            qs.query.set_limits(start, stop)
            return list(qs)[::k.step] if k.step else qs
    
        # 处理单个索引的情况,同样创建一个新的 QuerySet 对象,并设置查询的限制范围,最后执行数据库查询并获取结果
        qs = self._chain()
        qs.query.set_limits(k, k + 1)
        qs._fetch_all()
        return qs._result_cache[0]
    
    
  • QuerySet类常用的一些方法源码解析
    filter()方法代码解析,原理创建一个新的 QuerySet 实例,并在该实例上_query 属性中加入过滤条件,最终,过滤条件会被转化为相应的数据库查询语句,用于从数据库中检索满足条件的记录。

    class QuerySet:
        def __init__(self, model, query=None, using=None, hints=None):
            # sql.Query 类的实例,用于构建数据库查询。
             self._query = query or sql.Query(self.model)
             ...
    
        def filter(self, *args, **kwargs):
          self._not_support_combined_queries('filter')
          # 调用 _filter_or_exclude 方法进行实际的过滤操作。
          return self._filter_or_exclude(False, args, kwargs)
    
        def _filter_or_exclude(self, negate, args, kwargs):
            if args or kwargs:
                assert not self.query.is_sliced, \
                    "Cannot filter a query once a slice has been taken."
            clone = self._chain()
            if self._defer_next_filter:
                self._defer_next_filter = False
                clone._deferred_filter = negate, args, kwargs
            else:
              # 调用了 _filter_or_exclude_inplace 方法,根据传入的参数进行条件的构建,并将条件应用到查询中。
                clone._filter_or_exclude_inplace(negate, args, kwargs)
            return clone
    
    	 def _filter_or_exclude_inplace(self, negate, args, kwargs):
    	      # 传入的参数构建 Q 对象(Django中的查询条件对象),然后将这些条件添加到查询中
    	        if negate:
    	            self._query.add_q(~Q(*args, **kwargs))
    	        else:
    	            self._query.add_q(Q(*args, **kwargs))
    
    

3.5.SQL编译类源码解读

  • 在 Django 中,SQLCompiler 类是 SQL 查询编译器的基类,用于将高级查询 API 转换为实际的 SQL 查询语句。它位于 django/db/models/sql/compiler.py 文件中。

    class SQLCompiler:
        def __init__(self, query, connection, using):
            self.query = query
            self.connection = connection
            self.using = using
            self.subquery = False
    
        def setup_query(self):
            # 初始化查询设置,包括表、列、条件等
            self.select, self.klass_info, self.annotation_col_map = self.get_select()
            self.col_count = len(self.select)
            self.where, self.having = self.query.where, self.query.having
    
        def get_select(self):
            # 获取查询的 SELECT 部分,包括表、列和注解等信息
            # 返回一个三元组 (select, klass_info, annotation_col_map)
            # select: 一个包含查询的列的列表
            # klass_info: 包含有关查询模型的信息的元组 (model, alias, fields)
            # annotation_col_map: 包含注解列的映射
            pass
    
        def get_order_by(self):
            # 获取 ORDER BY 部分的 SQL 语句
            pass
    
        def pre_sql_setup(self):
            # 在生成 SQL 查询之前的准备工作
            pass
    
        def compile(self, node):
            # 编译查询节点为 SQL 查询语句
            pass
    
        def as_sql(self, with_limits=True, with_col_aliases=False):
            # 生成最终的 SQL 查询语句
            pass
    
        def execute_sql(self, result_type=MULTI, chunked_fetch=False, chunk_size=GET_ITERATOR_CHUNK_SIZE):
            # 执行 SQL 查询,返回结果
            pass
    
    

3.6.Model类源码解读

  • Django 中的 Model 类是 Django ORM(Object-Relational Mapping)的核心,用于定义与数据库表的映射关系。Model 类位于 django/db/models/base.py 文件中。

    python中的元类(Metaclass)
    1.元类的作用:元类是类的类,用于控制类的创建和行为。对象是由类创建,类是由默认是由type创建,元类可以指定类是由谁来创建。

    # 传统的类创建方式
    class Foo(object):
    a = 1
    def func(self):
        print('a的值={}'.format(self.a))
    
    # 非传统的类创建方式
    NewFoo = type('Foo', (object,), {'a': 1, 'func': lambda self: print('a的值={}'.format(self.a))})
    
    # 类的实例化
    f = NewFoo()
    f.func() 
    

    2.在 Python 中,每个类都有一个默认的元类,通常是 type。type 本身也是一个类,同时也是元类,用于创建类的实例。它接受三个参数,分别是类的名称继承的父类元组类的属性字典
    3.可以定义自己的元类,只需要继承自 type 类,并在元类中重写 newinit 方法。

    class MetaPerson(type):
        def __new__(cls, name, bases, dct):
            # 在类创建时,添加额外的属性和方法
            dct['class_variable'] = 10
    
            def greet(self):
                print(f"Hello, I'm {self.name}!")
    
            dct['greet'] = greet
    
            # 调用父类的 __new__ 方法创建类
            return super().__new__(cls, name, bases, dct)
    
    # 使用自定义元类创建类
    class Person(metaclass=MetaPerson):
        def __init__(self, name):
            self.name = name
    
    # 创建 Person 类的实例
    john = Person(name='John')
    
    # 访问额外的属性和调用额外的方法
    print(john.class_variable)  # 输出: 10
    john.greet()  # 输出: Hello, I'm John!
    
    
  • 在 Django 中,ModelBase 类是所有模型类的元类(metaclass)。这个元类负责处理模型类的定义,包括字段的收集、生成数据库表的元数据等。Model 类则是所有模型类的基类,它包含了一些通用的方法和属性,用于模型实例的创建、保存、删除等操作。

    class ModelBase(type):
        def __new__(cls, name, bases, attrs, **kwargs):
            super_new = super().__new__
    
            # 创建模型类的新实例
            parents = [b for b in bases if isinstance(b, ModelBase)]
            if not parents:
                return super_new(cls, name, bases, attrs, **kwargs)
    
            module = attrs.pop('__module__')
            new_class = super_new(cls, name, bases, {'__module__': module}, **kwargs)
    
            # 收集字段信息
            fields = [(field_name, attrs.pop(field_name)) for field_name, obj in list(attrs.items()) if isinstance(obj, Field)]
            fields.sort(key=lambda x: x[1].creation_counter)
    
            # 将字段信息添加到新类的 `_meta` 属性中
            new_class._meta = Options(new_class)
            new_class._meta.local_fields = [x for _, x in fields]
    
            return new_class
    
    class Model:
        _state = ModelState()
    
        def __init__(self, *args, **kwargs):
            # 初始化模型实例,根据字段定义,创建属性并赋初值
            opts = self._meta
            self._db = None
    
            # 处理传递的参数,将值赋给相应的属性
            for i, arg in enumerate(args):
                setattr(self, opts.fields[i].attname, arg)
    
            for kwarg in kwargs:
                setattr(self, kwarg, kwargs[kwarg])
    
        def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
            # 保存模型实例到数据库
            pass
    
        def delete(self, using=None, keep_parents=False):
            # 从数据库中删除模型实例
            pass
    
        # 其他通用方法...
    
    
  • 怎么理解模型对象的objects属性,为什么能够通过all()等方法得到QuerySet对象?

    objects属性是一个默认的管理器(Manager)实例,继承的方式获得了与QuerySet相关的方法
    过调用这些方法,你能够直接与数据库进行交互,得到QuerySet对象,进而执行各种查询和操作。

      class BaseManager:
    	  @classmethod
    	    def _get_queryset_methods(cls, queryset_class):
    	    	# 从给定的 queryset_class 中获取方法,并为这些方法创建新的管理器方法
    	        def create_method(name, method):
    	            def manager_method(self, *args, **kwargs):
    	                return getattr(self.get_queryset(), name)(*args, **kwargs)
    	            manager_method.__name__ = method.__name__
    	            manager_method.__doc__ = method.__doc__
    	            return manager_method
    	
    	        new_methods = {}
    	        for name, method in inspect.getmembers(queryset_class, predicate=inspect.isfunction):
    	            
    	            if hasattr(cls, name):
    	                continue.
    	            queryset_only = getattr(method, 'queryset_only', None)
    	            if queryset_only or (queryset_only is None and name.startswith('_')):
    	                continue
    	            # Copy the method onto the manager.
    	            new_methods[name] = create_method(name, method)
    	        return new_methods
    	    
    	     @classmethod
    	    def from_queryset(cls, queryset_class, class_name=None):
    	        if class_name is None:
    	            class_name = '%sFrom%s' % (cls.__name__, queryset_class.__name__)
    	        # type() 函数用于动态创建类,接受三个参数:类的名称、基类的元组和包含类属性和方法的字典。
    	        return type(class_name, (cls,), {
    	            '_queryset_class': queryset_class,
    	            **cls._get_queryset_methods(queryset_class),# 通过调用 _get_queryset_methods 方法来获取其他与 queryset_class 相关的方法,并将它们添加到新类中
    	        })
    	# Manager 类是通过 BaseManager.from_queryset(QuerySet) 创建的一个新类。这个新类继承了 BaseManager 中的方法和 QuerySet 类中的一些方法。
    	class Manager(BaseManager.from_queryset(QuerySet)):
              pass
    

4.总结

第一次写博客,有些不足希望大家能够见谅,同时,还请各位大佬能够给出一些宝贵的意见!

  • 51
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值