当前位置: 首页 > news >正文

Django 模型继承问题

文章目录

  • Django 模型继承问题
    • 继承出现的情况
      • `Meta` 和多表继承
      • `Meta` 和多表继承
      • 继承与反向关系
      • 指定父类连接字段
    • 代理模型
      • `QuerySet` 仍会返回请求的模型
      • 基类约束
      • 代理模型管理器
      • 代理继承和未托管的模型间的区别
    • 多重继承
      • 不能用字段名 "hiding"
    • 在一个包中管理模型

Django 模型继承问题

Django 模型 ORM 继承最典型一个就是内置 RABC 权限六表中 auth_user 表的扩展。

首先我们先看看源码与实现方式。

auth_user 表源码

class User(AbstractUser):"""Users within the Django authentication system are represented by thismodel.Username and password are required. Other fields are optional."""class Meta(AbstractUser.Meta):swappable = 'AUTH_USER_MODEL'

AbstractUser 类源码

class AbstractUser(AbstractBaseUser, PermissionsMixin):"""An abstract base class implementing a fully featured User model withadmin-compliant permissions.Username and password are required. Other fields are optional."""username_validator = UnicodeUsernameValidator()username = models.CharField(_('username'),max_length=150,unique=True,help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),validators=[username_validator],error_messages={'unique': _("A user with that username already exists."),},)first_name = models.CharField(_('first name'), max_length=30, blank=True)last_name = models.CharField(_('last name'), max_length=150, blank=True)email = models.EmailField(_('email address'), blank=True)is_staff = models.BooleanField(_('staff status'),default=False,help_text=_('Designates whether the user can log into this admin site.'),)is_active = models.BooleanField(_('active'),default=True,help_text=_('Designates whether this user should be treated as active. ''Unselect this instead of deleting accounts.'),)date_joined = models.DateTimeField(_('date joined'), default=timezone.now)objects = UserManager()EMAIL_FIELD = 'email'USERNAME_FIELD = 'username'REQUIRED_FIELDS = ['email']class Meta:verbose_name = _('user')verbose_name_plural = _('users')abstract = Trues

我们可以发现, User 类基本上就是 继承了 AbstractUser 类, 其他什么都没写。

我们在 扩展 User 表时 也是去继承 AbstractUser 类,而不是 User 类。扩展方法如下:

class UserInfo(AbstractUser):phone = models.BigIntegerField()...需要注意的是:1. 在扩展之前没有执行过数据库迁移命令auth_user没有被创建,如果当前库已经创建了那么就需要重新换一个库2. 继承的类里面不要覆盖AbstractUser里面的字段名表里面的字段都不要动,只扩展额外字段即可3. 需要在配置文件中告诉django你要用UserInfo代理auth_user(******)     AUTH_USER_MODEL = 'app01.UserInfo'  # '应用名.表名' 声明认证用户表

那么问题来了。为啥要用User类去建表?为啥扩展 User 表时不继承 User 类 而是去继承 AbstractUser 类?

原因有多条,其中最广而易知的是 AbstractUser 是一个 抽象表,Meta 属性中设置了 abstract = Trues 属性。该类在执行建表命令 makemigrations 和 migrate 时不会去实现。

在本文中,会描述第二个原因。

继承出现的情况

举个栗子:

class Place(models.Model):name = models.CharField(max_length=50)address = models.CharField(max_length=80)class Restaurant(Place):serves_hot_dogs = models.BooleanField(default=False)serves_pizza = models.BooleanField(default=False)

当 Restaurant 表继承了 Place 表,执行建表语句后结果(我插入数据后截下来的图)
在这里插入图片描述
在这里插入图片描述

实际上 继承非抽象表 类 ,默认会加上一个 OnetoOneField 外键关系

class Place(models.Model):name = models.CharField(max_length=50)address = models.CharField(max_length=80)class Restaurant(Place):place_ptr = models.OneToOneField(Place, on_delete=models.CASCADE, parent_link=False)serves_hot_dogs = models.BooleanField(default=False)serves_pizza = models.BooleanField(default=False)

插入数据

pl = models.Place.objects.create(name="Bod2", address="shanghai")
print(pl)
Re = models.Restaurant.objects.create(name="Bod2", address="shanghai")
print(Re)

执行完后,你会发现 place 表中插入了两条数据,restaurant 表中只有一条数据。并且 place_ptr_id 值指向 place 表中的第二条数据。

Place 的所有字段均在 Restaurant 中可用,虽然数据分别存在不同的表中。所有,以下操作均可:

Place.objects.filter(name="Bob's Cafe")
Restaurant.objects.filter(name="Bob's Cafe")

若有一个 Place 同时也是 Restaurant,你可以通过小写的模型名将 Place 对象转为 Restaurant 对象。

r = Restaurant.objects.get(id=3)
r.place_ptr  p = Place.objects.get(id=3)
p.restaurant
<Restaurant: ...>

然而,若上述例子中的 p 不是 一个 Restaurant (它仅是个 Place 对象或是其它类的父类),指向 p.restaurant 会抛出一个 Restaurant.DoesNotExist 异常。

但是我们可以通过设置 parent_link = True 来解决这个报错,允许 其通过父类 访问子类

class Place(models.Model):name = models.CharField(max_length=50)address = models.CharField(max_length=80)class Restaurant(Place):place_ptr = models.OneToOneField(Place, on_delete=models.CASCADE, parent_link=True)serves_hot_dogs = models.BooleanField(default=False)serves_pizza = models.BooleanField(default=False)

Meta 和多表继承

多表继承情况下,子类不会继承父类的 Meta。所以的 Meta 类选项已被应用至父类,在子类中再次应用会导致行为冲突(与抽象基类中应用场景对比,这种情况下,基类并不存在)。

故,子类模型无法访问父类的 Meta 类。不过,有限的几种情况下:若子类未指定 ordering 属性或 get_latest_by属性,子类会从父类继承这些。

如果父类有排序,而你并不期望子类有排序,你可以显示的禁止它:

class ChildModel(ParentModel):# ...class Meta:# Remove parent's ordering effectordering = []

Meta 和多表继承

多表继承情况下,子类不会继承父类的 Meta。所以的 Meta 类选项已被应用至父类,在子类中再次应用会导致行为冲突(与抽象基类中应用场景对比,这种情况下,基类并不存在)。

故,子类模型无法访问父类的 Meta 类。不过,有限的几种情况下:若子类未指定 ordering 属性或 get_latest_by 属性,子类会从父类继承这些。

如果父类有排序,而你并不期望子类有排序,你可以显示的禁止它:

class ChildModel(ParentModel):# ...class Meta:# Remove parent's ordering effectordering = []

继承与反向关系

由于多表继承使用隐式的 OneToOneField 连接子类和父类,所以直接从父类访问子类是可能的,就像上述例子展示的那样。然而,使用的名字是ForeignKeyManyToManyField关系的默认值。如果你在继承父类模型的子类中添加了这些关联,你 必须 指定 related_name属性。假如你忘了,Django 会抛出一个合法性错误。

比如,让我们用上面的 Place 类创建另一个子类,包含一个 ManyToManyField:

class Supplier(Place):customers = models.ManyToManyField(Place)

这会导致以下错误:

Reverse query name for 'Supplier.customers' clashes with reverse query
name for 'Supplier.place_ptr'.HINT: Add or change a related_name argument to the definition for
'Supplier.customers' or 'Supplier.place_ptr'.

related_name 像下面这样加至 customers 字段能解决此错误: models.ManyToManyField(Place, related_name='provider')

指定父类连接字段

如上所述,Django 会自动创建一个 OneToOneField,将子类连接回非抽象的父类。如果你想修改连接回父类的属性名,你可以自己创建 OneToOneField,并设置 parent_link=True,表明该属性用于连接回父类。

代理模型

使用多表继承时,每个子类模型都会创建一张新表。这一般是期望的行为,因为子类需要一个地方存储基类中不存在的额外数据字段。不过,有时候你只想修改模型的 Python 级行为——可能是修改默认管理器,或添加一个方法。

这是代理模型继承的目的:为原模型创建一个 代理。你可以创建,删除和更新代理模型的实例,所以的数据都会存储的像你使用原模型(未代理的)一样。不同点是你可以修改代理默认的模型排序和默认管理器,而不需要修改原模型。

代理模型就像普通模型一样申明。你需要告诉 Django 这是一个代理模型,通过将 Meta 类的proxy 属性设置为 True

例如,假设你想为 Person 模型添加一个方法。你可以这么做:

from django.db import modelsclass Person(models.Model):first_name = models.CharField(max_length=30)last_name = models.CharField(max_length=30)class MyPerson(Person):class Meta:proxy = Truedef do_something(self):# ...pass

MyPerson 类与父类 Person 操作同一张数据表。特别提醒, Person 的实例能通过 MyPerson 访问,反之亦然。

p = Person.objects.create(first_name="foobar")
MyPerson.objects.get(first_name="foobar")
<MyPerson: foobar>

你也可以用代理模型定义模型的另一种不同的默认排序方法。你也许不期望总对 “Persion” 进行排序,但是在使用代理时,总是依据 “last_name” 属性进行排序。这很简单:

class OrderedPerson(Person):class Meta:ordering = ["last_name"]proxy = True

现在,普通的 Person 查询结果不会被排序,但 OrderdPerson 查询接轨会按 last_name 排序。

代理模型继承“Meta”属性 和普通模型一样。

QuerySet 仍会返回请求的模型

当你用 Person 对象查询时,Django 永远不会返回 MyPerson 对象。Person 对象的查询结果集总是返回对应类型。代理对象存在的全部意义是帮你复用原 Person 提供的代码和自定义的功能代码(并未依赖其它代码)。不存在什么方法能在你创建完代理后,帮你替换所有 Person (或其它)模型。

基类约束

一个代理模型必须继承自一个非抽象模型类。你不能继承多个非抽象模型类,因为代理模型无法在不同数据表之间提供任何行间连接。一个代理模型可以继承任意数量的抽象模型类,假如他们 没有 定义任何的模型字段。一个代理模型也可以继承任意数量的代理模型,只需他们共享同一个非抽象父类。

代理模型管理器

若你未在代理模型中指定模型管理器,它会从父类模型中继承。如果你在代理模型中指定了管理器,它会成为默认管理器,但父类中定义的管理器仍是可用的。

随着上面的例子一路走下来,你可以在查询 Person 模型时这样修改默认管理器:

from django.db import modelsclass NewManager(models.Manager):# ...passclass MyPerson(Person):objects = NewManager()class Meta:proxy = True

若你在不替换已存在的默认管理器的情况下,为代理添加新管理器,可以去自定义管理器中介绍的技巧:创建一个包含新管理器的基类,在继承列表中,主类后追加这个基类:

# Create an abstract class for the new manager.
class ExtraManagers(models.Model):secondary = NewManager()class Meta:abstract = Trueclass MyPerson(Person, ExtraManagers):class Meta:proxy = True

通常情况下,你可能不需要这么做。然而,你需要的时候,这也是可以的。

代理继承和未托管的模型间的区别

代理模型继承可能看起来和创建未托管的模型很类似,通过在模型的 Meta 类中定义 managed 属性。

通过小心地配置 Meta.db_table,你将创建一个未托管的模型,该模型将对现有模型进行阴影处理,并添加一些 Python 方法。然而,这会是个经常重复的且容易出错的过程,因为你要在做任何修改时保持两个副本的同步。

另一方面,代理模型意在表现的和所代理的模型一样。它们总是与父模型保持一致,因为它们直接从福利继承字段和管理器。

通用性规则:

  1. 当你克隆一个已存在模型或数据表时,并且不想要所以的原数据表列,配置 Meta.managed=False。这个选项在模型化未受 Django 控制的数据库视图和表格时很有用。
  2. 如果你只想修改模型的 Python 行为,并保留原有字段,配置 Meta.proxy=True。这个配置使得代理模型在保存数据时,确保数据结构和原模型的完全一样。

多重继承

和 Python 中的继承一样,Django 模型也能继承自多个父类模型。请记住,Python 的命名规则这里也有效。第一个出现的基类(比如 Meta )就是会被使用的那个;举个例子,如果存在多个父类包含 Meta,只有第一个会被使用,其它的都会被忽略。

一般来说,你并不会同时继承多个父类。常见的应用场景是 “混合” 类:为每个继承此类的添加额外的字段或方法。试着保持你的继承层级尽可能的简单和直接,这样未来你就不用为了确认某段信息是哪来的而拔你为数不多的头发了。

注意,继承自多个包含 id 主键的字段会抛出错误。正确的使用多继承,你可以在基类中显示使用 AutoField

class Article(models.Model):article_id = models.AutoField(primary_key=True)...class Book(models.Model):book_id = models.AutoField(primary_key=True)...class BookReview(Book, Article):pass

或者在公共祖先中存储 AutoField。这会要求为每个父类模型和公共祖先使用显式的 OneToOneField,避免与子类自动生成或继承的字段发生冲突:

class Piece(models.Model):passclass Article(Piece):article_piece = models.OneToOneField(Piece, on_delete=models.CASCADE, parent_link=True)...class Book(Piece):book_piece = models.OneToOneField(Piece, on_delete=models.CASCADE, parent_link=True)...class BookReview(Book, Article):pass

不能用字段名 “hiding”

在普通的 Python 类继承中,允许子类重写父类的任何属性。在 Django 中,针对模型字段在,这一般是不允许的。如果有个非抽象模型基类,拥有一个名为 author 字段,你可以任意继承自基类的类中创建另一个模型字段,或定义一个叫 author 的属性。

此规范不针对从抽象模型基类继承获得的字段。这些字段可被其它字段或值重写,也可以通过配置 field_name = None 删除。

警告

模型管理器是由抽象基类继承来的。重写由 Manager指定的字段可能会导致精细的 bug。

注解

某些字段在模型内定义了额外的属性,比如,一个 ForeignKey 定义了一个额外属性,名称为字段名接 _id,并在外部模型中的添加 related_namerelated_query_name

这些额外属性不能被重写,除非定义该属性的字段被修改或删除,这样就不会定义额外属性了。

在父模型中重写字段会在很多方面造成困难,比如创建新实例(特指那些字段在 Model.__init__ 中初始化的那些)和序列化。这些特性,普通的 Python 类继承不需要用完全一样的方式处理,故此, Django 的模型继承和 Python 的类继承之间的区别不是随意的。

这些限制只针对那些是 Field 实例的属性。普通的 Python 属性可被随便重写。它还对 Python 能识别的属性生效:如果你同时在子类和多表继承的祖先类中指定了数据表的列名(它们是两张不同的数据表中的列)。

若你在祖先模型中重写了任何模型字段,Django 会抛出一个 FieldError

在一个包中管理模型

manage.py startapp命令创建了一个应用结构,包含一个 models.py 文件。若你有很多 models.py 文件,用独立的文件管理它们会很实用。

为了达到此目的,创建一个 models 包。删除 models.py,创建一个 myapp/models 目录,包含一个 __init__.py 文件和存储模型的文件。你必须在 __init__.py 文件中导入这些模块。

比如,若你在 models 目录下有 organic.pysynthetic.py

myapp/models/init.py

from .organic import Person
from .synthetic import Robot

显式导入每个模块,而不是使用 from .models import * 有助于不打乱命名空间,使代码更具可读性,让代码分析工具更有用。

相关文章:

Django 模型继承问题

文章目录Django 模型继承问题继承出现的情况Meta 和多表继承Meta 和多表继承继承与反向关系指定父类连接字段代理模型QuerySet 仍会返回请求的模型基类约束代理模型管理器代理继承和未托管的模型间的区别多重继承不能用字段名 "hiding"在一个包中管理模型Django 模型…...

Vue3篇.01-简介及基本使用,项目创建方式, 模板语法, 事件监听, 修饰符

一.简介1.概念Vue 是一款用于构建用户界面的 JS框架&#xff0c; 基于标准 HTML、CSS 和 JavaScript 构建&#xff0c;并提供了一套声明式的、组件化的编程模型&#xff0c; 高效地开发用户界面。渐进式框架&#xff0c; 适应不同需求进行开发。两个核心功能&#xff1a;声明式…...

别学英语了,真的

文 / 王不留&#xff08;微信公众号&#xff1a;王不留&#xff09; 这两年&#xff0c;很多朋友加我微信后&#xff0c;第一句常是&#xff0c;学英语有什么用啊&#xff1f; 我会统一给出真诚答复&#xff1a;没用&#xff0c;真的。 看新闻&#xff0c;中文海量信息已经严重…...

CRM系统五大技巧集成Excel为销售流程赋能

销售过程中有很多情况会降低团队的效率。通过正确的实施CRM客户管理系统&#xff0c;可以帮助您的企业自动执行手动任务、减少错误并专注于完成交易。这里有5个技巧&#xff0c;可以帮助您的销售人员通过CRM集成Excel为销售流程赋能并提高他们的整体效率。 技巧1&#xff1a;将…...

交通部互通互联码的根证书规则

引言 为了更好的服务交通互通互联码而更新这篇文章。 中金根证书其实是可以自己生成的。 代码内调整 中心公钥索引要保证自己的唯一性。 此处的唯一&#xff0c;是要保证在机具侧的唯一&#xff0c;因为他要根据这个索引去查找证书以及公钥。 提供根公钥给机具侧 生成的公钥…...

Map和Set(Java详解)

在开始详解之前&#xff0c;先来看看集合的框架&#xff1a; 可以看到Set实现了Collection接口&#xff0c;而Map又是一个单独存在的接口。 而最下面又分别各有两个类&#xff0c;分别是TreeSet&#xff08;Map&#xff09;和 HashSet&#xff08;Map&#xff09;。 TreeSet&…...

Vue 3的响应式机制

什么是响应式 Js代码是自上而下执行的&#xff0c;结合下面代码看&#xff0c;代码执行后&#xff0c;会打印两次double的结果&#xff0c;结果也都是2&#xff0c;即使修改了代码中count的值后&#xff0c;double的值也不会发生任何改变。 let count 1 let double count * …...

30岁了,说几句大实话

是的&#xff0c;我 30 岁了&#xff0c;还是周岁。 就在这上个月末&#xff0c;我度过了自己 30 岁的生日。 都说三十而立&#xff0c;要对自己有一个正确的认识&#xff0c;明确自己以后想做什么&#xff0c;能做什么。 想想时间&#xff0c;过得真快。 过五关斩六将&…...

AsyncTask使用及源码查看Android P

AsyncTask AsyncTask用于处理耗时任务&#xff0c;可以即时通知进度&#xff0c;最终返回结果。可以用于下载等处理。 使用 实现类继承三个方法 1. doInBackground后台执行&#xff0c;在此方法中进行延时操作 /*** Override this method to perform a computation on a back…...

花2个月面过华为测开岗,拿个30K不过分吧?

背景介绍 美本计算机专业&#xff0c;代码能力一般&#xff0c;之前有过两段实习以及一个学校项目经历。第一份实习是大二暑期在深圳的一家互联网公司做前端开发&#xff0c;第二份实习由于大三暑假回国的时间比较短&#xff08;小于两个月&#xff09;&#xff0c;于是找的实…...

JAVA练习51-最大子数组和

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、题目-最大子数组和 1.题目描述 2.思路与代码 2.1 思路 2.2 代码 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 2月15日练…...

Inception Transformer

paper链接: https://arxiv.org/abs/2205.12956v2 code链接: https://github.com/sail-sg/iFormer Inception Transformer一、引言二、实现细节三、实验一、分类二、检测三、分割四、消融实验一、引言 最近的研究表明&#xff0c;Transformer具有很强的建立远程依赖关系的能力…...

10分钟学会数据库压力测试,你敢信?

目录 前言 查看数据库版本 下载驱动&#xff1a; 菜单路径 配置 Variable Name Bound to Pool模块配置 Connection pool configuration模块配置 Database Connection Configuration模块配置 菜单路径 Variable Name Bound to Pool 脚本结构 脚本&#xff08;执行查询…...

论文阅读 | Video Super-Resolution Transformer

引言&#xff1a;2021年用Transformer实现视频超分VSR的文章&#xff0c;改进了SA并在FFN中加入了光流引导 论文&#xff1a;【here】 代码&#xff1a;【here】 Video Super-Resolution Transformer 引言 视频超分中有一组待超分的图片&#xff0c;因此视频超分也经常被看做…...

7-6 带头节点的双向循环链表操作

本题目要求读入一系列整数&#xff0c;依次插入到双向循环链表的头部和尾部&#xff0c;然后顺序和逆序输出链表。 链表节点类型可以定义为 typedef int DataType; typedef struct LinkedNode{DataType data;struct LinkedNode *prev;struct LinkedNode *next; }LinkedNode;链…...

npm publish 、 npm adduser 提示 403 的问题

0. 查看使用的源&#xff1a;npm config get registry1. 如果使用的不是官方的源&#xff0c;切换&#xff1a;npm config set registry https://registry.npmjs.org/2. 登录&#xff1a;npm adduser3. 查看是否登录成功&#xff1a;npm whoami4. 执行发布命令&#xff1a;npm …...

Java 8的函数式接口使用示例

什么是函数式接口 有且只有一个抽象方法的接口被称为函数式接口&#xff0c;函数式接口适用于函数式编程的场景&#xff0c;Lambda就是Java中函数式编程的体现&#xff0c;可以使用Lambda表达式创建一个函数式接口的对象&#xff0c;一定要确保接口中有且只有一个抽象方法&…...

2023年企业如何改善员工体验?为什么员工体验很重要?

什么是员工体验&#xff1f;大约 96% 的企业领导者表示&#xff0c;专注于员工体验可以更轻松地留住顶尖人才。[1] 这还不是全部。令人震惊的是&#xff0c;87%的企业领导者还表示&#xff0c;优先考虑员工的幸福感将给他们带来竞争优势。尽管有这些发现&#xff0c;但只有19%的…...

设计模式:桥接模式让抽象和实现解耦,各自独立变化

一、问题场景 现在对”不同手机类型“的 “不同品牌”实现操作编程(比如: 开机、关机、上网&#xff0c;打电话等) 二、传统解决方案 传统方案解决手机使用问题类图&#xff1a; 三、传统方案分析 传统方案解决手机操作问题分析 1、扩展性问题(类爆炸)&#xff0c;如果我们…...

C++学习记录——십 STL初级认识、标准库string类

文章目录1、什么是STL2、STL简介3、什么是string类4、string类的常用接口说明1、常见构造函数2、容量操作3、迭代器4、其他的标准库的string类关于string类的内容&#xff0c;可以在cplusplus.com查看到。 1、什么是STL STL是C标准库的重要组成部分&#xff0c;不仅是一个可复…...

测试微信模版消息推送

进入“开发接口管理”--“公众平台测试账号”&#xff0c;无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息&#xff1a; 关注测试号&#xff1a;扫二维码关注测试号。 发送模版消息&#xff1a; import requests da…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...