<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title>Blog Feed</title><link href="https://www.moshanghua.net/feed.xml" rel="self" /><link href="https://www.moshanghua.net" /><id>https://www.moshanghua.net</id><updated>2025-03-28T14:57:44.000Z</updated><entry><title>火狐同步改国内服务器账号登录</title><link href="https://www.moshanghua.net/archives/%E7%81%AB%E7%8B%90%E5%90%8C%E6%AD%A5%E6%94%B9%E5%9B%BD%E5%86%85%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%B4%A6%E5%8F%B7%E7%99%BB%E5%BD%95.html" /><id>https://www.moshanghua.net/archives/%E7%81%AB%E7%8B%90%E5%90%8C%E6%AD%A5%E6%94%B9%E5%9B%BD%E5%86%85%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%B4%A6%E5%8F%B7%E7%99%BB%E5%BD%95.html</id><updated>2025-03-28T14:57:44.000Z</updated><summary></summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;更新升级了macOS Sequoia。某次停电后，再次打开电脑用游览器时，结果重置变崭新的初始游览器界面了....&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;火狐在同步选项里没有“切换全球/本地服务器”的选项了。而火狐默认同步登录的是&lt;a href=&quot;https://accounts.firefox.com&quot;&gt;https://accounts.firefox.com&lt;/a&gt;（国际账号），但自己的数据又是在&lt;a href=&quot;https://accounts.firefox.com.cn&quot;&gt;accounts.firefox.com.cn&lt;/a&gt;（国内账号）上。&lt;/p&gt;
&lt;p&gt;记录一下修改使用国内的账号服务器&lt;/p&gt;
&lt;p&gt;首先需要先在搜索框输入&lt;code&gt;about:config&lt;/code&gt; 进入Firefox的配置页面
&lt;img src=&quot;http://assets.moshanghua.net/images/2025/03/msh-3483-02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在配置页面中，需要找到与同步相关的配置项。这些配置项通常以&lt;code&gt;identity.fxaccounts&lt;/code&gt;开头。
可以通过在搜索框中输入来快速找到它们。&lt;/p&gt;
&lt;p&gt;然后改变下面的三项配置&lt;/p&gt;
&lt;p&gt;&lt;code&gt;identity.fxaccounts.autoconfig.uri&lt;/code&gt; 输入 &lt;a href=&quot;https://accounts.firefox.com.cn/&quot;&gt;&lt;code&gt;https://accounts.firefox.com.cn&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;identity.fxaccounts.contextParam&lt;/code&gt; 改为 &lt;code&gt;fx_desktop_v3&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;identity.fxaccounts.oauth.enabled&lt;/code&gt; 改为&lt;code&gt; false&lt;/code&gt;
&lt;img src=&quot;http://assets.moshanghua.net/images/2025/03/msh-3483-04.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后重启浏览器，就能正常使用国内的火狐账号服务器&lt;/p&gt;
&lt;h2&gt;其他配置&lt;/h2&gt;
&lt;p&gt;在火狐浏览器中设置打开书签时自动在新页面（新标签页）中打开&lt;/p&gt;
&lt;p&gt;&lt;code&gt;browser.tabs.loadBookmarksInTabs&lt;/code&gt; 这个设置项决定了书签是否在新标签页中打开，把“false”将其改为“true”，这样，当你点击书签时，它们就会在新标签页中打开了。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;browser.tabs.closeTabByDblclick&lt;/code&gt;将其值改为“true”，可以双击标签页来关闭它。&lt;/p&gt;</content></entry><entry><title>几首近期在听歌曲-洛天依游学季，歌行戏曲季</title><link href="https://www.moshanghua.net/archives/%E5%87%A0%E9%A6%96%E8%BF%91%E6%9C%9F%E5%9C%A8%E5%90%AC%E6%AD%8C%E6%9B%B2-%E6%B4%9B%E5%A4%A9%E4%BE%9D%E6%B8%B8%E5%AD%A6%E5%AD%A3-%E6%AD%8C%E8%A1%8C%E6%88%8F%E6%9B%B2%E5%AD%A3.html" /><id>https://www.moshanghua.net/archives/%E5%87%A0%E9%A6%96%E8%BF%91%E6%9C%9F%E5%9C%A8%E5%90%AC%E6%AD%8C%E6%9B%B2-%E6%B4%9B%E5%A4%A9%E4%BE%9D%E6%B8%B8%E5%AD%A6%E5%AD%A3-%E6%AD%8C%E8%A1%8C%E6%88%8F%E6%9B%B2%E5%AD%A3.html</id><updated>2025-03-12T15:07:57.000Z</updated><summary></summary><content type="html">&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/tianyi/3279/f29c07ad58f4137a53d5d4365cc1deec36081646.jpg&quot; alt=&quot;&quot; /&gt;
&lt;a href=&quot;https://www.bilibili.com/festival/ltyyxj2?bvid=BV1HWkwYWETx&quot; title=&quot;“可是天意总将 有情人放逐”洛天依原创曲《聘书》【歌行黄梅戏篇·天仙配】&quot;&gt;“可是天意总将 有情人放逐”洛天依原创曲《聘书》【歌行黄梅戏篇·天仙配】&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/tianyi/3276/f266269cab493b038abc9e519dc2450b36081646.jpg&quot; alt=&quot;&quot; /&gt;
&lt;a href=&quot;https://www.bilibili.com/festival/ltyyxj2?bvid=BV1HWkwYWETx&quot; title=&quot;“定教这凡规俗矩 尽为骇浪冲淹！”洛天依原创曲《倒瞰清白》【歌行川剧篇·白蛇传】&quot;&gt;“定教这凡规俗矩 尽为骇浪冲淹！”洛天依原创曲《倒瞰清白》【歌行川剧篇·白蛇传】&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/tianyi/3273/0fe698529dafe1b8e0a1d138513714cb36081646.jpg&quot; alt=&quot;&quot; /&gt;
&lt;a href=&quot;https://www.bilibili.com/festival/ltyyxj2?bvid=BV1HWkwYWETx&quot; title=&quot;“我自有我去留无怕，同天地斗法”洛天依原创《金鳞甲》【歌行豫剧篇单曲】&quot;&gt;“我自有我去留无怕，同天地斗法”洛天依原创《金鳞甲》【歌行豫剧篇单曲】&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/festival/bnj2025?bvid=BV1AvfpYsE4t&quot; title=&quot;天星问【2025拜年纪单品】&quot;&gt;天星问【2025拜年纪单品】&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/festival/VSF2025live?bvid=BV1vJwmepEGz&quot; title=&quot;“攒我千年，赐你一眼，余生都看遍”【洛天依原创曲】《不堪人间》【2025虚拟歌手贺岁纪单品】&quot;&gt;“攒我千年，赐你一眼，余生都看遍”【洛天依原创曲】《不堪人间》【2025虚拟歌手贺岁纪单品】&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/festival/ltyyxj2?bvid=BV1HWkwYWETx&quot; title=&quot;献给历久弥新的中华戏曲｜戏游九州&quot;&gt;献给历久弥新的中华戏曲｜戏游九州&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;UP主调校&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV15u9dYXEWr&quot; title=&quot;【洛天依民族腔】突破天灵盖！《九儿》|“高粱熟来红满天，九儿我送你去远方”【原创PV付】&quot;&gt;【洛天依民族腔】突破天灵盖！《九儿》|“高粱熟来红满天，九儿我送你去远方”【原创PV付】&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1ufNUexEu8&quot; title=&quot;【洛天依】《月光》|“月光色女子香，泪断剑情多长？”【原创PV付】&quot;&gt;【洛天依】《月光》|“月光色女子香，泪断剑情多长？”【原创PV付】&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV16BfaYVENR&quot; title=&quot;【洛天依】《世界赠予我的》| 2025年总台春晚特别单曲【原创PV付】&quot;&gt;【洛天依】《世界赠予我的》| 2025年总台春晚特别单曲【原创PV付】&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1r668YbEyp&quot; title=&quot;【洛天依戏腔】《赤伶》|“戏幕起戏幕落谁是客？”【原创PV付】&quot;&gt;【洛天依戏腔】《赤伶》|“戏幕起戏幕落谁是客？”【原创PV付】&lt;/a&gt;&lt;/p&gt;</content></entry><entry><title>洛天依歌行宇宙·无限共鸣全息演唱会</title><link href="https://www.moshanghua.net/archives/2024-%E6%B4%9B%E5%A4%A9%E4%BE%9D%E6%AD%8C%E8%A1%8C%E5%AE%87%E5%AE%99-%E6%97%A0%E9%99%90%E5%85%B1%E9%B8%A3%E5%85%A8%E6%81%AF%E6%BC%94%E5%94%B1%E4%BC%9A.html" /><id>https://www.moshanghua.net/archives/2024-%E6%B4%9B%E5%A4%A9%E4%BE%9D%E6%AD%8C%E8%A1%8C%E5%AE%87%E5%AE%99-%E6%97%A0%E9%99%90%E5%85%B1%E9%B8%A3%E5%85%A8%E6%81%AF%E6%BC%94%E5%94%B1%E4%BC%9A.html</id><updated>2024-10-06T15:29:57.000Z</updated><summary></summary><content type="html">&lt;h2&gt;2024 洛天依歌行宇宙·无限共鸣全息演唱会&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;http://assets.moshanghua.net/images/2024/10/3419/31b40d03130262babfb00a0e653b506e36081646.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;之前预热时就有注意到，期间还多次起念头想去体验一下现场来着，奈何...算了，期待日后有机会能支持一场。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://assets.moshanghua.net/images/2024/10/3419/e7d25d38a977f11457ec0c0186333cc736081646.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://assets.moshanghua.net/images/2024/10/3419/b9a6d71a5041a992757dfdc8a0c44ab936081646.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://assets.moshanghua.net/images/2024/10/3419/3ded86d4148cf46da1e5d864d55ecefe36081646.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://assets.moshanghua.net/images/2024/10/3419/329089a3933f05ab7ab46f53f08c616136081646.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;图片来自官号，也算是云体验了一番了，从昨晚开始就刷到了些演唱会的单曲片段，凑起来也算是看了大半场演唱会了，23333&lt;/p&gt;
&lt;p&gt;日常在循环着听的万古生香、万分之一的光、夏虫、蝴蝶、大哉乾元、三月雨、歌行四方、上山岗、心印、光与影的对白、为了你唱下去等歌曲居然都在其中，挺惊喜和意外的。&lt;/p&gt;
&lt;p&gt;这版三月雨挺好听的，还有就是下半场的几首歌伴随着全场的合唱，听着也别有一番心情！！！&lt;/p&gt;
&lt;p&gt;忙碌一天回来，本想翻出稍后再看里的几个片段来重温一下，结果躺列表里的视频不翼而飞了，点开历史记录一看，视频失效了，好吧....还是逃不掉给B站删了的命运，还有一份约等于拍摄了全场的视频都还没来得及看，也没有了，而且，发现那老哥还给封号关小黑屋了..&lt;/p&gt;
&lt;p&gt;算了，等 8 号的官方回放视频吧，只是这份资源应该就没有现场的一些声音了，而且还是收费的..&lt;/p&gt;
&lt;p&gt;附上部分花絮和还能听的单曲片段（虽然不好，但感谢不删之恩！）：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1qp1qYQErT&quot; title=&quot;在天依展演奏V家热曲串烧，再度引发全场大合唱！&quot;&gt;在天依展演奏V家热曲串烧，再度引发全场大合唱！&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1NE1eYZEWv&quot; title=&quot;洛天依无限共鸣·开场花絮（夜场自用）&quot;&gt;洛天依无限共鸣·开场花絮（夜场自用）&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1Tn1iYNE29&quot; title=&quot;洛天依无限共鸣全息演唱会安可环节&quot;&gt;洛天依无限共鸣全息演唱会安可环节&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV12v1dYxE8C&quot; title=&quot;洛天依演唱会《三月雨》&quot;&gt;洛天依演唱会《三月雨》&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1C11dYUEFL&quot; title=&quot;【4K杜比视界】三月雨-洛天依无限共鸣演唱会&quot;&gt;【4K杜比视界】三月雨-洛天依无限共鸣演唱会&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV17B1oYVESB&quot; title=&quot;源流万世，大哉乾元&quot;&gt;源流万世，大哉乾元&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1Xt1dYcEMy&quot; title=&quot;[洛天依演唱会]《夏虫》——感动的不会只有我一个人&quot;&gt;[洛天依演唱会]《夏虫》——感动的不会只有我一个人&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1es1dYPEj3&quot; title=&quot;[洛天依演唱会]《歌行四方》——果然合唱赛高！！！&quot;&gt;[洛天依演唱会]《歌行四方》——果然合唱赛高！！！&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV13Q1oYeEPN&quot; title=&quot;洛天依演唱会 光与影的对白合唱 日场&quot;&gt;洛天依演唱会 光与影的对白合唱 日场&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1wX2FYhEnf/&quot; title=&quot;洛天依演唱会《上山岗》&quot;&gt;洛天依演唱会《上山岗》&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1yn1oYREkh&quot; title=&quot;【自用留存】上山岗-洛天依演唱会&quot;&gt;【自用留存】上山岗-洛天依演唱会&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1Np1oYsEyA&quot; title=&quot;【4K 60fps】《上海·洛天依2024无限共鸣全息演唱会》上山岗（内场A1二排中部视角）&quot;&gt;【4K 60fps】《上海·洛天依2024无限共鸣全息演唱会》上山岗（内场A1二排中部视角）&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1Eb1RYrEkh&quot; title=&quot;洛天依无限共鸣全息演唱会 保留节目 《为了你唱下去》&quot;&gt;洛天依无限共鸣全息演唱会 保留节目 《为了你唱下去》&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;为了你唱下去这首听的不同视角的好几个片段都给删了，就这一个了...&lt;/p&gt;
&lt;p&gt;最后，真心希望咱们的小姑娘越来越好~&lt;/p&gt;
&lt;p&gt;华风夏韵，洛水天依！&lt;/p&gt;</content></entry><entry><title>Django CRUD操作</title><link href="https://www.moshanghua.net/archives/django-crud%E6%93%8D%E4%BD%9C.html" /><id>https://www.moshanghua.net/archives/django-crud%E6%93%8D%E4%BD%9C.html</id><updated>2024-08-01T02:34:16.000Z</updated><summary></summary><content type="html">&lt;p&gt;在 ORM 框架中，所有模型相关的操作，比如添加/删除等，其实都是映射到数据库中一条数据的操作，因此模型操作也就是数据库表中数据的操作。&lt;/p&gt;
&lt;p&gt;首先需要创建一个模型。添加模型到数据库中。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.db import models

# Create your models here.
class User(models.Model):
    username = models.CharField(max_length=20)
    password = models.CharField(max_length=100)

# 表一对一,用户表和用户信息表, 常用和不常用
class UserExtension(models.Model):
    birthday = models.DateTimeField()
    university = models.CharField(max_length=200)
    user = models.OneToOneField(&amp;quot;User&amp;quot;, on_delete=models.CASCADE)

class Article(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    pub_time = models.DateTimeField(auto_now_add=True, null=True)

    author = models.ForeignKey(
        &amp;quot;User&amp;quot;, on_delete=models.SET_DEFAULT, default=1, related_name=&amp;quot;articles&amp;quot;
    )

    tags = models.ManyToManyField(&amp;quot;Tag&amp;quot;, related_name=&amp;quot;articles&amp;quot;)

class Tag(models.Model):
    name = models.CharField(max_length=100)

class Comment(models.Model):
    content = models.TextField()
    origin_comment = models.ForeignKey(&amp;quot;self&amp;quot;, on_delete=models.CASCADE, null=True)&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;添加一个模型实例到数据库中&lt;/h2&gt;
&lt;p&gt;添加模型到数据库中，首先需要创建一个模型，创建模型的方式很简单，就跟创建普通的 Python 对象是一摸一样的。&lt;/p&gt;
&lt;p&gt;在创建完模型之后，需要调用模型的 save 方法，这样 Django 会自动的将这个模型转换成sql 语句，然后存储到数据库中。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.shortcuts import HttpResponse

def add_user(request):
    user = User(username=&amp;quot;xiaoming&amp;quot;, password=&amp;quot;111111&amp;quot;)
    # 调用save()方法：是将模型对象的数据保存到数据库表中，即在数据库表中插入一条新的记录。
    user.save()
    return HttpResponse(f&amp;quot;用户 {user.username} 添加成功!&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行访问以上视图函数 &lt;code&gt;add_user&lt;/code&gt; 就会往&lt;code&gt;User&lt;/code&gt;这个表里面添加一条数据&lt;/p&gt;
&lt;p&gt;二次添加或者更新数据，比如创建用户时没创建&lt;code&gt;UserExtension&lt;/code&gt; 表里的数据&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.shortcuts import HttpResponse
from django.utils import timezone
from .models import User, UserExtension

def add_user_extension(request):
    # 获取已经存在的用户
    try:
        user = User.objects.get(username=&amp;quot;xiaoming&amp;quot;)
    except User.DoesNotExist:
        return HttpResponse(&amp;quot;用户 xiaoming 不存在。&amp;quot;)

    # 准备要添加的扩展信息数据
    birthday = &amp;quot;2024-08-01&amp;quot;
    university = &amp;quot;Example University&amp;quot;

    # 创建或更新 UserExtension 数据
    user_extension, created = UserExtension.objects.get_or_create(
        user=user,
        defaults={&amp;#039;birthday&amp;#039;: birthday, &amp;#039;university&amp;#039;: university}
    )

    if not created:
        # UserExtension 已经存在，更新数据
        user_extension.birthday = birthday
        user_extension.university = university
        user_extension.save()
        return HttpResponse(f&amp;quot;用户 {user.username} 的扩展信息已更新。&amp;quot;)

    return HttpResponse(f&amp;quot;用户 {user.username} 的扩展信息已添加。&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;get_or_create()&lt;/code&gt;&lt;/strong&gt; ：尝试在数据库中获取一个匹配的对象。如果找到了对象，返回该对象和一个布尔值 &lt;code&gt;False&lt;/code&gt;，表示对象不是新创建的。&lt;/p&gt;
&lt;p&gt;如果没有找到对象，创建一个新的对象并保存到数据库中，然后返回该对象和一个布尔值 &lt;code&gt;True&lt;/code&gt;，表示对象是新创建的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;user=user&lt;/code&gt;&lt;/strong&gt; ：左边的 &lt;code&gt;user&lt;/code&gt; 是 &lt;code&gt;UserExtension&lt;/code&gt; 模型中的字段。右边的 &lt;code&gt;user&lt;/code&gt; 是你在代码中获取或创建的 &lt;code&gt;User&lt;/code&gt; 对象，这行代码的意思是在 &lt;code&gt;UserExtension&lt;/code&gt; 表中查找 &lt;code&gt;user&lt;/code&gt; 字段等于指定 &lt;code&gt;User&lt;/code&gt; 对象的记录。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;efaults={&amp;#039;birthday&amp;#039;: birthday, &amp;#039;university&amp;#039;: university}&lt;/code&gt;**&lt;/strong&gt; **：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;get_or_create&lt;/code&gt; 方法的一个参数，它用于在对象不存在时指定默认值。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;defaults&lt;/code&gt;&lt;/strong&gt;: 这是一个字典，包含了一组键值对，用于在创建新对象时提供默认值。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;#039;birthday&amp;#039;: birthday&lt;/code&gt;&lt;/strong&gt;: 如果创建新对象，使用 &lt;code&gt;birthday&lt;/code&gt; 变量的值作为 &lt;code&gt;birthday&lt;/code&gt; 字段的默认值。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;user_extension, created = ...&lt;/code&gt;&lt;/strong&gt; ：这行代码将 &lt;code&gt;get_or_create&lt;/code&gt; 方法的返回值解包为两个变量：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;user_extension&lt;/code&gt;&lt;/strong&gt;: 这是获取到的或新创建的 &lt;code&gt;UserExtension&lt;/code&gt; 对象。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;created&lt;/code&gt;&lt;/strong&gt;: 这是一个布尔值，如果对象是新创建的，则为 &lt;code&gt;True&lt;/code&gt;，否则为 &lt;code&gt;False&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;查找数据&lt;/h2&gt;
&lt;p&gt;查找数据都是通过模型下的 &lt;code&gt;objects&lt;/code&gt; 对象来实现的。&lt;/p&gt;
&lt;h3&gt;查找所有数据&lt;/h3&gt;
&lt;p&gt;要查找 &lt;code&gt;User&lt;/code&gt; 这个模型对应的表下的所有数据，使用&lt;code&gt;.all()&lt;/code&gt; 将返回 模型下的所有数据。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;users = User.objects.all()&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;数据过滤&lt;/h3&gt;
&lt;p&gt;在查找数据的时候，有时候需要对一些数据进行过滤。那么这时候需要调用 &lt;code&gt;objects&lt;/code&gt; 的 &lt;code&gt;filter&lt;/code&gt; 方法。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;users = User.objects.filter(username=&amp;quot;chixm&amp;quot;)
for user in users:
    print({user.username})
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;获取单个对象&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;objects.get&lt;/code&gt; 是 Django ORM 中用于从数据库中获取单个对象的方法。&lt;/p&gt;
&lt;p&gt;它期望查询条件只返回一个对象，如果查询结果中没有对象或有多个对象，会抛出相应的异常。&lt;/p&gt;
&lt;p&gt;用于获取符合条件的唯一对象，适用于查询结果唯一的情况。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;user = User.objects.get(username=&amp;quot;henry&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;数据排序&lt;/h3&gt;
&lt;p&gt;在之前的例子中，数据都是无序的。如果你想在查找数据的时候使用某个字段来进行排序，那么可以使用 order_by 方法来实现。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;users = User.objects.order_by(&amp;quot;username&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上代码在提取所有用户名数据的时候，将会使用 &lt;code&gt;username&lt;/code&gt;  首字母从小到大进行排序。如果想要进行倒序排序，那么可以在 &lt;code&gt;username&lt;/code&gt; 前面加一个负号。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;users = User.objects.order_by(&amp;quot;-username&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;修改数据&lt;/h2&gt;
&lt;p&gt;在查找到数据后，便可以进行修改了。修改的方式非常简单，只需要将查找出来的对象的某个属性进行修改，然后再调用这个对象的 save 方法便可以进行修改。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;def modify_user(request):
    user = User.objects.get(id=1)
    user.username = &amp;quot;ching&amp;quot;
    user.save()

    return HttpResponse(&amp;quot;success!&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;删除数据&lt;/h2&gt;
&lt;p&gt;在查找到数据后，便可以进行删除了。删除数据非常简单，只需要调用这个对象的 &lt;code&gt;delete&lt;/code&gt; 方法即可。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;def delete_user(request):
    user = User.objects.get(id=2)
    user.delete()

    return HttpResponse(&amp;quot;delete success!&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;查询操作&lt;/h2&gt;
&lt;p&gt;查找是数据库操作中一个非常重要的技术。&lt;/p&gt;
&lt;p&gt;查询一般就是使用 &lt;code&gt;filter&lt;/code&gt; 、 &lt;code&gt;exclude&lt;/code&gt; 以及 &lt;code&gt;get&lt;/code&gt; 三个方法来实现。&lt;/p&gt;
&lt;p&gt;我们可以在调用这些方法的时候传递不同的参数来实现查询需求。在 ORM 层面，这些查询条件都是使用 &lt;code&gt;field + __ + condition&lt;/code&gt; 的方式来使用的。&lt;/p&gt;
&lt;h2&gt;查询条件&lt;/h2&gt;
&lt;h3&gt;exact&lt;/h3&gt;
&lt;p&gt;使用精确的 &lt;code&gt;=&lt;/code&gt; 进行查找。如果提供的是一个 &lt;code&gt;None&lt;/code&gt; ，那么在 SQL 层面就是被解释为 &lt;code&gt;NULL&lt;/code&gt; 。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;article = Article.objects.get(id__exact=14) 
article = Article.objects.get(id__exact=None)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上的两个查找在翻译为 SQL 语句为如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;select ... from article where id=14; 
select ... from article where id IS NULL;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查询结果 &lt;code&gt;.query&lt;/code&gt;  看到就可以看到底层执行的 SQL 语句，如上就是 &lt;code&gt;article.query&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;iexact&lt;/h3&gt;
&lt;p&gt;使用 &lt;code&gt;like&lt;/code&gt;  是忽略大小写进行查找。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;article = Article.objects.filter(title__iexact=&amp;#039;hello world&amp;#039;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么以上的查询就等价于以下的 SQL 语句：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;select ... from article where title like &amp;#039;hello world&amp;#039;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意上面这个 &lt;code&gt;sql&lt;/code&gt; 语句，因为在 &lt;code&gt;MySQL&lt;/code&gt; 中，没有一个叫做 &lt;code&gt;ilike &lt;/code&gt;的。所以 &lt;code&gt;exact&lt;/code&gt; 和 &lt;code&gt;iexact&lt;/code&gt; 的区别实际上就是 &lt;code&gt;LIKE&lt;/code&gt; 和 &lt;code&gt;=&lt;/code&gt;  的区别，在大部分 collation=utf8_general_ci 情况下都是一样的（ collation 是
用来对字符串比较的）。&lt;/p&gt;
&lt;h3&gt;contains&lt;/h3&gt;
&lt;p&gt;大小写敏感，判断某个字段是否包含了某个数据。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;articles = Article.objects.filter(title__contains=&amp;#039;hello&amp;#039;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在翻译成 SQL 语句为如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;select ... where title like binary &amp;#039;%hello%&amp;#039;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在使用 &lt;code&gt;contains&lt;/code&gt; 的时候，翻译成的 &lt;code&gt;sql&lt;/code&gt; 语句左右两边是有百分号的，意味着使用的是模糊查询。而 &lt;code&gt;exact&lt;/code&gt; 翻译成 &lt;code&gt;sql&lt;/code&gt; 语句左右两边是没有百分号的，意味着使用的是精确的查询。&lt;/p&gt;
&lt;h3&gt;icontains&lt;/h3&gt;
&lt;p&gt;大小写不敏感的匹配查询。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;articles = Article.objects.filter(title__icontains=&amp;#039;hello&amp;#039;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在翻译成 SQL 语句为如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;select ... where title like &amp;#039;%hello%&amp;#039;;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;in&lt;/h3&gt;
&lt;p&gt;提取那些给定的 field 的值是否在给定的容器中。容器可以为 list 、 tuple 或者任何一个可以迭代的对象，包括 QuerySet 对象。（可以用一个列表、元组或其他可迭代对象里的值来筛选数据库中的记录）&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;articles = Article.objects.filter(id__in=[1,2,3])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上代码在翻译成 SQL 语句为如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;select ... where id in (1,3,4)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当然也可以传递一个 &lt;code&gt;QuerySet&lt;/code&gt; 对象进去。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;inner_qs = Article.objects.filter(title__contains=&amp;#039;hello&amp;#039;) 
categories = Category.objects.filter(article__in=inner_qs)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上代码的意思是获取那些文章标题包含 &lt;code&gt;hello&lt;/code&gt; 的所有分类。&lt;/p&gt;
&lt;p&gt;将翻译成以下 SQL 语句，示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;select ...from category where article.id in (select id from article where title like &amp;#039;%hello%&amp;#039;);&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;gt&lt;/h3&gt;
&lt;p&gt;某个 &lt;code&gt;field&lt;/code&gt; 的值要大于给定的值。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;articles = Article.objects.filter(id__gt=4)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上代码的意思是将所有 &lt;code&gt;id&lt;/code&gt; 大于4的文章全部都找出来。&lt;/p&gt;
&lt;p&gt;将翻译成以下 SQL 语句：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;select ... where id &amp;gt; 4;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;gte&lt;/h3&gt;
&lt;p&gt;类似于 &lt;code&gt;gt&lt;/code&gt; ，是大于等于。&lt;/p&gt;
&lt;h3&gt;lt&lt;/h3&gt;
&lt;p&gt;类似于 &lt;code&gt;gt&lt;/code&gt; 是小于。&lt;/p&gt;
&lt;h3&gt;lte&lt;/h3&gt;
&lt;p&gt;类似于 &lt;code&gt;lt&lt;/code&gt; ，是小于等于。&lt;/p&gt;
&lt;h3&gt;startswith&lt;/h3&gt;
&lt;p&gt;判断某个字段的值是否是以某个值开始的。大小写敏感。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;articles = Article.objects.filter(title__startswith=&amp;#039;hello&amp;#039;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上代码的意思是提取所有标题以 &lt;code&gt;hello &lt;/code&gt;字符串开头的文章。&lt;/p&gt;
&lt;p&gt;将翻译成以下 SQL 语句：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;select ... where title like &amp;#039;hello%&amp;#039;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;istartswith&lt;/h3&gt;
&lt;p&gt;类似于 &lt;code&gt;startswith&lt;/code&gt; ，但是大小写是不敏感的。&lt;/p&gt;
&lt;h3&gt;endswith&lt;/h3&gt;
&lt;p&gt;判断某个字段的值是否以某个值结束。大小写敏感。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;articles = Article.objects.filter(title__endswith=&amp;#039;world&amp;#039;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上代码的意思是提取所有标题以 &lt;code&gt;world&lt;/code&gt; 结尾的文章。&lt;/p&gt;
&lt;p&gt;将翻译成以下 SQL 语句：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;select ... where title like &amp;#039;%world&amp;#039;;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;iendswith&lt;/h3&gt;
&lt;p&gt;类似于 &lt;code&gt;endswith&lt;/code&gt; ，只不过大小写不敏感。&lt;/p&gt;
&lt;h3&gt;range&lt;/h3&gt;
&lt;p&gt;判断某个 &lt;code&gt;field&lt;/code&gt; 的值是否在给定的区间中。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.utils.timezone import make_aware
from datetime import datetime
start_date = make_aware(datetime(year=2024,month=1,day=1)) 
end_date = make_aware(datetime(year=2024,month=3,day=29,)) 
articles = Article.objects.filter(pub_date__range=(start_date,end_date))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上代码的意思是提取所有发布时间在 2024/1/1 到 2024/3/29 之间的文章。&lt;/p&gt;
&lt;p&gt;将翻译成以下的 SQL 语句：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;select ... from article where pub_time between &amp;#039;2024-01-01&amp;#039; and &amp;#039;2024-03-29&amp;#039;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意的是，以上提取数据，不会包含最后一个值。也就是不会包含 &lt;code&gt;2024/3/29&lt;/code&gt; 的文章。&lt;/p&gt;
&lt;h3&gt;date&lt;/h3&gt;
&lt;p&gt;针对某些 &lt;code&gt;date&lt;/code&gt; 或者 &lt;code&gt;datetime&lt;/code&gt; 类型的字段。可以指定 &lt;code&gt;date&lt;/code&gt; 的范围。并且这个时间过滤，还可以使用链式调用。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;articles = Article.objects.filter(pub_date__date=date(2024,3,29))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上代码的意思是查找时间为 &lt;code&gt;2024/3/29&lt;/code&gt; 这一天发表的所有文章。&lt;/p&gt;
&lt;p&gt;将翻译成以下的 sql 语句：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;select ... WHERE DATE(CONVERT_TZ(`front_article`.`pub_date`, &amp;#039;UTC&amp;#039;, &amp;#039;Asia/Shanghai&amp;#039;)) = 2018-03-29&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;year&lt;/h3&gt;
&lt;p&gt;根据年份进行查找。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;articles = Article.objects.filter(pub_date__year=2024) 
articles = Article.objects.filter(pub_date__year__gte=2023)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上的代码在翻译成 SQL 语句为如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;select ... where pub_date between &amp;#039;2024-01-01&amp;#039; and &amp;#039;2024-12-31&amp;#039;; 
select ... where pub_date &amp;gt;= &amp;#039;2023-01-01&amp;#039;;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;month&lt;/h3&gt;
&lt;p&gt;同 &lt;code&gt;year&lt;/code&gt; ，根据月份进行查找。&lt;/p&gt;
&lt;h3&gt;day&lt;/h3&gt;
&lt;p&gt;同 &lt;code&gt;year&lt;/code&gt; ，根据日期进行查找。&lt;/p&gt;
&lt;h3&gt;week_day&lt;/h3&gt;
&lt;p&gt;Django 1.11 新增的查找方式。同 &lt;code&gt;year&lt;/code&gt; ，根据星期几进行查找。1表示星期天，7表示星期六， 2-6 代表的是星期一到星期五。&lt;/p&gt;
&lt;h3&gt;time&lt;/h3&gt;
&lt;p&gt;根据时间进行查找。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;articles = Article.objects.filter(pub_date__time=datetime.time(12,12,12));&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上的代码是获取每一天中12点12分12秒发表的所有文章。
更多的关于时间的过滤，可以参考 Django 官方文档：&lt;a href=&quot;https://docs.djangoproject.com/zh-hans/5.0/ref/models/querysets/#range&quot;&gt;https://docs.djangoproject.com/zh-hans/5.0/ref/models/querysets/#range&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;isnull&lt;/h3&gt;
&lt;p&gt;根据值是否为空进行查找。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;articles = Article.objects.filter(pub_date__isnull=False)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上的代码的意思是获取所有发布日期不为空的文章。&lt;/p&gt;
&lt;p&gt;将来翻译成 SQL 语句如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;select ... where pub_date is not null;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;regex和iregex&lt;/h3&gt;
&lt;p&gt;大小写敏感和大小写不敏感的正则表达式。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;articles = Article.objects.filter(title__regex=r&amp;#039;^hello&amp;#039;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上代码的意思是提取所有标题以 hello 字符串开头的文章。&lt;/p&gt;
&lt;p&gt;将翻译成以下的 SQL 语句：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;select ... where title regexp binary &amp;#039;^hello&amp;#039;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;iregex&lt;/code&gt; 是大小写不敏感的。&lt;/p&gt;
&lt;h3&gt;根据关联的表进行查询&lt;/h3&gt;
&lt;p&gt;假如现在有两个 &lt;code&gt;ORM&lt;/code&gt; 模型，一个是 &lt;code&gt;Article&lt;/code&gt; ，一个是 &lt;code&gt;Category&lt;/code&gt; 。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;class Category(models.Model):     
    &amp;quot;&amp;quot;&amp;quot;文章分类表&amp;quot;&amp;quot;&amp;quot;
    name = models.CharField(max_length=100)

class Article(models.Model):
    &amp;quot;&amp;quot;&amp;quot;文章表&amp;quot;&amp;quot;&amp;quot;
    title = models.CharField(max_length=100,null=True)     
    category = models.ForeignKey(&amp;quot;Category&amp;quot;,on_delete=models.CASCADE)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;比如想要获取文章标题中包含&amp;quot;hello&amp;quot;的所有的分类。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;categories = Category.object.filter(article__title__contains(&amp;quot;hello&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;聚合函数&lt;/h2&gt;
&lt;p&gt;如果使用原生 &lt;code&gt;SQL&lt;/code&gt; ，则可以使用聚合函数来提取数据。比如提取某个商品销售的数量，那么可以使用&lt;code&gt;Count&lt;/code&gt; ，如果想要知道商品销售的平均价格，那么可以使用 &lt;code&gt;Avg &lt;/code&gt;。
在Django ORM中，聚合函数通过&lt;code&gt;aggregate&lt;/code&gt;方法来实现。Django提供了一组聚合函数，允许你在查询集中执行聚合计算，包括&lt;code&gt;Count&lt;/code&gt;、&lt;code&gt;Avg&lt;/code&gt;、&lt;code&gt;Sum&lt;/code&gt;、&lt;code&gt;Max&lt;/code&gt;、&lt;code&gt;Min&lt;/code&gt;等。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.db import models

class Author(models.Model):      
    &amp;quot;&amp;quot;&amp;quot;作者模型&amp;quot;&amp;quot;&amp;quot;
    name = models.CharField(max_length=100)      
    age = models.IntegerField()      
    email = models.EmailField()

    class Meta:          
        db_table = &amp;#039;author&amp;#039;

class Publisher(models.Model):      
    &amp;quot;&amp;quot;&amp;quot;出版社模型&amp;quot;&amp;quot;&amp;quot;
    name = models.CharField(max_length=300)

    class Meta:          
        db_table = &amp;#039;publisher&amp;#039;

class Book(models.Model):
    &amp;quot;&amp;quot;&amp;quot;图书模型&amp;quot;&amp;quot;&amp;quot;
    name = models.CharField(max_length=300)
    pages = models.IntegerField()
    price = models.FloatField()
    rating = models.FloatField()
    author = models.ForeignKey(Author,on_delete=models.CASCADE)      
    publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)

    class Meta:          
        db_table = &amp;#039;book&amp;#039;

class BookOrder(models.Model):
    &amp;quot;&amp;quot;&amp;quot;图书订单模型&amp;quot;&amp;quot;&amp;quot;
    book = models.ForeignKey(&amp;quot;Book&amp;quot;,on_delete=models.CASCADE)      
    price = models.FloatField()
    class Meta:          
        db_table = &amp;#039;book_order&amp;#039;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以下这些聚合函数的用法，都是基于以上的模型对象来实现的。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;Avg&lt;/code&gt; ：求平均值&lt;/h3&gt;
&lt;p&gt;比如想要获取所有图书的价格平均值。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.db.models import Avg 
result = Book.objects.aggregate(Avg(&amp;#039;price&amp;#039;)) 
print(result)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上的打印结果是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt; {&amp;quot;price__avg&amp;quot;:23.0}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中 &lt;code&gt;price__avg&lt;/code&gt; 的结构是根据 &lt;code&gt;field__avg&lt;/code&gt; 规则构成的。如果想要修改默认的名字，那么可以将 &lt;code&gt;Avg&lt;/code&gt; 赋值给一个关键字参数。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.db.models import Avg 
result = Book.objects.aggregate(my_avg=Avg(&amp;#039;price&amp;#039;)) 
print(result)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么以上的结果打印为：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt; {&amp;quot;my_avg&amp;quot;:23}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Count ：获取指定的对象的个数&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.db.models import Count 
result = Book.objects.aggregate(book_num=Count(&amp;#039;id&amp;#039;))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上的 &lt;code&gt;result&lt;/code&gt; 将返回 &lt;code&gt;Book&lt;/code&gt; 表中总共有多少本图书。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Count&lt;/code&gt; 类中，还有另外一个参数叫做 &lt;code&gt;distinct&lt;/code&gt; ，默认是等于 &lt;code&gt;False&lt;/code&gt; ，如果是等于 &lt;code&gt;True&lt;/code&gt; ，那么将去掉那些重复的值。&lt;/p&gt;
&lt;p&gt;比如要获取作者表中所有的不重复的邮箱总共有多少个，那么可以通过以下代码来实现：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from djang.db.models import Count
result = Author.objects.aggregate(count=Count(&amp;#039;email&amp;#039;,distinct=True))&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Max 和Min ：获取指定对象的最大值和最小值&lt;/h3&gt;
&lt;p&gt;比如想要获取 &lt;code&gt;Author&lt;/code&gt; 表中，最大的年龄和最小的年龄分别是多少。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.db.models import Max,Min 
result = Author.objects.aggregate(Max(&amp;#039;age&amp;#039;),Min(&amp;#039;age&amp;#039;))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果最大的年龄是88,最小的年龄是18。那么以上的result将为：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;{&amp;quot;age__max&amp;quot;:88,&amp;quot;age__min&amp;quot;:18}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sum ：求指定对象的总和&lt;/h3&gt;
&lt;p&gt;比如要求图书的销售总额。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from djang.db.models import Sum
result = Book.objects.annotate(total=Sum(&amp;quot;bookstore__price&amp;quot;)).values(&amp;quot;name&amp;quot;,&amp;quot;total&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上的代码 &lt;code&gt;annotate&lt;/code&gt; 的意思是给 &lt;code&gt;Book&lt;/code&gt; 表在查询的时候添加一个字段叫做 &lt;code&gt;total&lt;/code&gt; ，这个字段的数据来源是从 &lt;code&gt;BookStore&lt;/code&gt; 模型的 &lt;code&gt;price&lt;/code&gt; 的总和而来。 &lt;code&gt;values&lt;/code&gt; 方法是只提取 &lt;code&gt;name&lt;/code&gt; 和 &lt;code&gt;total&lt;/code&gt; 两个字段的值。&lt;/p&gt;
&lt;p&gt;更多的聚合函数可以参考官方文档：&lt;a href=&quot;https://docs.djangoproject.com/zh-hans/5.0/ref/models/querysets/#aggregation-functions&quot;&gt;https://docs.djangoproject.com/zh-hans/5.0/ref/models/querysets/#aggregation-functions&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;aggregate和annotate的区别&lt;/h2&gt;
&lt;p&gt;aggregate ：返回使用聚合函数后的字段和值。&lt;/p&gt;
&lt;p&gt;annotate ：在原来模型字段的基础之上添加一个使用了聚合函数的字段，并且在使用聚合函数的时候，会使用当前这个模型的主键进行分组（&lt;code&gt;group by&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;比如以上 &lt;code&gt;Sum&lt;/code&gt; 的例子，如果使用的是 &lt;code&gt;annotate&lt;/code&gt; ，那么将在每条图书的数据上都添加一个字段叫做&lt;code&gt;total&lt;/code&gt; ，计算这本书的销售总额。&lt;/p&gt;
&lt;p&gt;而如果使用的是 &lt;code&gt;aggregate&lt;/code&gt; ，那么将求所有图书的销售总额。&lt;/p&gt;
&lt;h2&gt;F表达式和Q表达式&lt;/h2&gt;
&lt;h3&gt;F表达式&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;F表达式&lt;/code&gt; 是用来优化 &lt;code&gt;ORM&lt;/code&gt; 操作数据库的。比如我们要将公司所有员工的薪水都增加1000元，如果按照正常的流程，应该是先从数据库中提取所有的员工工资到Python内存中，然后使用Python代码在员工工资的基础之上增加1000元，最后再保存到数据库中。这里面涉及的流程就是，首先从数据库中提取数据到Python内存中，然后在Python内存中做完运算，之后再保存到数据库中。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;employees = Employee.objects.all() 
for employee in employees:     
    employee.salary += 1000     
    employee.save()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而 &lt;code&gt;F表达式&lt;/code&gt; 就可以优化这个流程，它可以不需要先把数据从数据库中提取出来，计算完成后再保存回去，他可以直接执行 &lt;code&gt;SQL语句&lt;/code&gt; ，就将员工的工资增加1000元。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from djang.db.models import F 
Employee.object.update(salary=F(&amp;quot;salary&amp;quot;)+1000)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;F表达式&lt;/code&gt; 并不会马上从数据库中获取数据，而是在生成 SQL 语句的时候，动态的获取传给 &lt;code&gt;F表达式&lt;/code&gt; 的值。&lt;/p&gt;
&lt;p&gt;比如如果想要获取作者中， &lt;code&gt;name&lt;/code&gt; 和 &lt;code&gt;email&lt;/code&gt; 相同的作者数据。如果不使用 &lt;code&gt;F表达式&lt;/code&gt; ，那么需要使用以下代码来完成：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt; authors = Author.objects.all()     
 for author in authors:         
     if author.name == author.email:             
         print(author)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果使用 &lt;code&gt;F表达式 &lt;/code&gt;，那么一行代码就可以搞定。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.db.models import F
authors = Author.objects.filter(name=F(&amp;quot;email&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Q表达式&lt;/h3&gt;
&lt;p&gt;如果想要实现所有价格高于100元，并且评分达到9.0以上评分的图书。那么可以通过以下代码来实现：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;books = Book.objects.filter(price__gte=100,rating__gte=9)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上这个案例是一个并集查询，可以简单的通过传递多个条件进去来实现。
但是如果想要实现一些复杂的查询语句，比如要查询所有价格低于10元，或者是评分低于9分的图书。那就没有办法通过传递多个条件进去实现了。&lt;/p&gt;
&lt;p&gt;这时候就需要使用 &lt;code&gt;Q表达式&lt;/code&gt; 来实现了。示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.db.models import Q
books = Book.objects.filter(Q(price__lte=10) | Q(rating__lte=9))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上是进行或运算，当然还可以进行其他的运算，比如有 &lt;code&gt;&amp;amp;&lt;/code&gt; 和  &lt;code&gt;~&lt;/code&gt; （非） 等。一些用&lt;code&gt;Q表达式&lt;/code&gt;的例子如下&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.db.models import Q
# 获取id等于3的图书
books = Book.objects.filter(Q(id=3))
# 获取id等于3，或者名字中包含文字&amp;quot;记&amp;quot;的图书
books = Book.objects.filter(Q(id=3)|Q(name__contains(&amp;quot;记&amp;quot;))) 
# 获取价格大于100，并且书名中包含&amp;quot;记&amp;quot;的图书
books = Book.objects.filter(Q(price__gte=100)&amp;amp;Q(name__contains(&amp;quot;记&amp;quot;))) 
# 获取书名包含“记”，但是id不等于3的图书
books = Book.objects.filter(Q(name__contains=&amp;#039;记&amp;#039;) &amp;amp; ~Q(id=3))&lt;/code&gt;&lt;/pre&gt;</content></entry><entry><title>Django 模型</title><link href="https://www.moshanghua.net/archives/django-%E6%A8%A1%E5%9E%8B.html" /><id>https://www.moshanghua.net/archives/django-%E6%A8%A1%E5%9E%8B.html</id><updated>2024-07-31T12:37:09.000Z</updated><summary></summary><content type="html">&lt;h2&gt;Django数据库&lt;/h2&gt;
&lt;h3&gt;MySQL驱动程序安装&lt;/h3&gt;
&lt;p&gt;使用 Django 来操作 MySQL ，实际上底层还是通过 Python 来操作的。因此想要用 Django 来操作 MySQL ，首先还是需要安装一个驱动程序。&lt;/p&gt;
&lt;p&gt;在 Python3 中，驱动程序有多种选择。比如有 pymysql 以及 mysqlclient 等。这里我们就使用 mysqlclient 来操作。 &lt;/p&gt;
&lt;p&gt;mysqlclient 安装非常简单&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;pip install mysqlclient&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;配置连接数据库&lt;/h3&gt;
&lt;p&gt;在操作数据库之前，首先要连接数据库，这里以配置 MySQL 为例。&lt;/p&gt;
&lt;p&gt;Django 连接数据库，不需要单独的创建一个连接对象。只需要在 &lt;code&gt;settings.py&lt;/code&gt; 文件中找到&lt;code&gt;DATABASES&lt;/code&gt;字段做好数据库相关的配置就可以了。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;DATABASES = {
    &amp;quot;default&amp;quot;: {
        # 数据库引擎（是mysql还是oracle等）
        &amp;quot;ENGINE&amp;quot;: &amp;quot;django.db.backends.mysql&amp;quot;,
        # 数据库的名字
        &amp;quot;NAME&amp;quot;: &amp;quot;database_django&amp;quot;,
        # 连接mysql数据库的用户名
        &amp;quot;USER&amp;quot;: &amp;quot;root&amp;quot;,
        # 连接mysql数据库的密码
        &amp;quot;PASSWORD&amp;quot;: &amp;quot;root&amp;quot;,
        # mysql数据库的主机地址
        &amp;quot;HOST&amp;quot;: &amp;quot;127.0.0.1&amp;quot;,
        # mysql数据库的端口号
        &amp;quot;PORT&amp;quot;: &amp;quot;3306&amp;quot;,
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中 &lt;code&gt;engine&lt;/code&gt; 的选择还有以下：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;#039;django.db.backends.postgresql&amp;#039;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;#039;django.db.backends.mysql&amp;#039;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;#039;django.db.backends.sqlite3&amp;#039;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;#039;django.db.backends.oracle&amp;#039;&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;在Django中操作数据库&lt;/h3&gt;
&lt;p&gt;在 Django 中操作数据库有两种方式。第一种方式就是使用原生 sql 语句操作，第二种就是使用 ORM 模型来操作。&lt;/p&gt;
&lt;p&gt;本笔记记录使用ORM 模型来操作，这里稍微记录一下原生 sql 语句操作&lt;/p&gt;
&lt;p&gt;在 Django 中使用原生 sql 语句操作其实就是使用 python db api 的接口来操作。如果你的 mysql 驱动使用的是 pymysql ，那么你就是使用 pymysql 来操作的，只不过 Django 将数据库连接的这一部分封装好了，我们只要在 settings.py 中配置好了数据库连接信息后直接使用 Django 封装好的接口就可以操作了。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# 使用django封装好的connection对象，会自动读取settings.py中数据库的配置信息
from django.db import connection

# 获取游标对象
cursor = connection.cursor()
# 拿到游标对象后执行sql语句
cursor.execute(&amp;quot;select * from book&amp;quot;) 
# 获取所有的数据
rows = cursor.fetchall()
# 遍历查询到的数据
for row in rows:
    print(row)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上的 execute 以及 fetchall 方法都是 Python DB API 规范中定义好的。&lt;/p&gt;
&lt;h2&gt;ORM模型介绍&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ORM&lt;/code&gt; ，全称 Object Relational Mapping ，中文叫做对象关系映射，通过 ORM 我们可以通过类的方式去操作数据库，而不用再写原生的SQL语句。通过把表映射成类，把行作实例，把字段作为属性， ORM
在执行对象操作的时候最终还是会把对应的操作转换为数据库原生语句。&lt;/p&gt;
&lt;h2&gt;创建ORM模型&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ORM&lt;/code&gt; 模型一般都是放在 &lt;code&gt;app&lt;/code&gt; 的 &lt;code&gt;models.py&lt;/code&gt; 文件中。每个 &lt;code&gt;app&lt;/code&gt; 都可以拥有自己的模型。&lt;/p&gt;
&lt;p&gt;并且如果这个模型想要映射到数据库中，那么这个 &lt;code&gt;app&lt;/code&gt; 必须要放在 &lt;code&gt;settings.py&lt;/code&gt; 的 &lt;code&gt;INSTALLED_APP&lt;/code&gt; 中进行安装。&lt;/p&gt;
&lt;p&gt;以下是写一个简单的书籍 ORM 模型。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# 从Django的 django.db 模块中导入了 models 模块
# models 模块包含了用于定义各种数据库字段类型和模型的类
from django.db import models

# 定义了一个名为 Book 的类，并继承自 models.Model
# 继承 models.Model 表示这个类是一个Django模型，将映射到数据库中的一个表
class Book(models.Model):
    # 包含四个字段：name、author、pub_time 和 price
    name = models.CharField(max_length=20,null=False)     
    author = models.CharField(max_length=20,null=False)     
    pub_time = models.DateTimeField(auto_add_now=True)     
    price = models.FloatField(default=0)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上便定义了一个模型。&lt;/p&gt;
&lt;p&gt;这个模型继承自 &lt;code&gt;django.db.models.Model&lt;/code&gt;，如果这个模型想要映射到数据库中，就必须继承自这个类。这个模型以后映射到数据库中，表名是模型名称的小写形式，为 book 。&lt;/p&gt;
&lt;p&gt;在这个表中，有四个字段，还有一个字段没有写，就是主键 &lt;code&gt;id &lt;/code&gt;，在 django 中，&lt;strong&gt;如果一个模型没有定义主键，那么将会自动生成一个自动增长的 int 类型的主键，并且这个主键的名字就叫做&lt;/strong&gt; &lt;code&gt;id &lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;映射模型到数据库中&lt;/h2&gt;
&lt;p&gt;将 ORM 模型映射到数据库中，总结起来就是以下几步：&lt;/p&gt;
&lt;p&gt;1.在 &lt;code&gt;settings.py&lt;/code&gt; 中，配置好 &lt;code&gt;DATABASES&lt;/code&gt; ，做好数据库相关的配置。&lt;/p&gt;
&lt;p&gt;2.在 &lt;code&gt;app&lt;/code&gt; 中的 &lt;code&gt;models.py&lt;/code&gt; 中定义好模型，这个模型必须继承自 django.db.models 。&lt;/p&gt;
&lt;p&gt;3.将这个 &lt;code&gt;app&lt;/code&gt; 添加到 &lt;code&gt;settings.py&lt;/code&gt; 的 &lt;code&gt;INSTALLED_APP&lt;/code&gt; 中的末尾。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;INSTALLED_APPS = [
    ...
    &amp;quot;django.contrib.messages&amp;quot;,
    &amp;quot;django.contrib.staticfiles&amp;quot;,
    # 
    &amp;quot;APP 名称&amp;quot;,
]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;4在命令行终端，进入到项目所在的路径，然后执行命令 &lt;code&gt;python manage.py makemigrations&lt;/code&gt; 来生成迁移脚本文件。&lt;/p&gt;
&lt;p&gt;5.同样在命令行中，执行命令 &lt;code&gt;python manage.py migrate&lt;/code&gt; 来将迁移脚本文件映射到数据库中。&lt;/p&gt;
&lt;h2&gt;模型常用Field和参数&lt;/h2&gt;
&lt;p&gt;在 Django 中，定义了一些 Field 来与数据库表中的字段类型来进行映射。&lt;/p&gt;
&lt;p&gt;在Django模型中，字段用于定义模型的属性，代表数据库表中的列。&lt;/p&gt;
&lt;p&gt;每个字段代表一个特定的数据类型，并定义可以存储在相应列中的数据类型。&lt;/p&gt;
&lt;p&gt;Django提供了多种字段类型来处理不同的数据类型和约束。&lt;/p&gt;
&lt;p&gt;常用字段的示例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.db import models

# CharField类
class Book(models.Model):
    title = models.CharField(max_length=100)  # 存储书名的字段（最大长度：100个字符）

# IntegerField类
class Student(models.Model):
    age = models.IntegerField()  # 存储学生年龄的字段

# FloatField类
class Product(models.Model):
    price = models.FloatField()  # 存储产品价格的字段

# DateField类
class Event(models.Model):
    event_date = models.DateField()  # 存储事件日期的字段

# DateTimeField类
class Post(models.Model):
    pub_date = models.DateTimeField()  # 存储帖子发布日期和时间的字段

# BooleanField类
class Task(models.Model):
    is_completed = models.BooleanField()  # 存储任务完成状态的字段

# ForeignKey类
class Author(models.Model):
    name = models.CharField(max_length=100)
class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)  # 外键字段，建立一对多关系

# ManyToManyField类
class Course(models.Model):
    name = models.CharField(max_length=100)
class Student(models.Model):
    name = models.CharField(max_length=100)
    courses = models.ManyToManyField(Course)  # 多对多字段，建立多对多关系

# EmailField类
class Contact(models.Model):
    email = models.EmailField()  # 存储联系人电子邮件地址的字段

# ImageField类
class UserProfile(models.Model):
    profile_picture = models.ImageField(upload_to=&amp;#039;profile_pics/&amp;#039;)  # 存储用户个人资料图片的字段&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;常用字段&lt;/h3&gt;
&lt;h4&gt;AutoField：&lt;/h4&gt;
&lt;p&gt;映射到数据库中是 &lt;code&gt;int&lt;/code&gt; 类型，可以有自动增长的特性。一般不需要使用这个类型，如果不指定主键，那么模型会自动的生成一个叫做 &lt;code&gt;id &lt;/code&gt;的自动增长的主键。如果你想指定一个其他名字的并且具有自动增长的主键，使用 &lt;code&gt;AutoField&lt;/code&gt; 也是可以的。&lt;/p&gt;
&lt;h4&gt;BigAutoField：&lt;/h4&gt;
&lt;p&gt;64位的整形，类似于 &lt;code&gt;AutoField&lt;/code&gt; ，只不过是产生的数据的范围是从 1-9223372036854775807 。&lt;/p&gt;
&lt;h4&gt;BooleanField：&lt;/h4&gt;
&lt;p&gt;在模型层面接收的是 &lt;code&gt;True/False&lt;/code&gt; 。在数据库层面是 &lt;code&gt;tinyint&lt;/code&gt; 类型。如果没有指定默认值，默认值是&lt;code&gt;None&lt;/code&gt; 。&lt;/p&gt;
&lt;h4&gt;CharField：&lt;/h4&gt;
&lt;p&gt;在数据库层面是 &lt;code&gt;varchar&lt;/code&gt; 类型。在 Python 层面就是普通的字符串。这个类型在使用的时候必须要指定最大的长度，也即必须要传递 &lt;code&gt;max_length&lt;/code&gt; 这个关键字参数进去。&lt;/p&gt;
&lt;h4&gt;DateField：&lt;/h4&gt;
&lt;p&gt;日期类型。在 Python 中是 &lt;code&gt;datetime.date&lt;/code&gt; 类型，可以记录年月日。在映射到数据库中也是 &lt;code&gt;date&lt;/code&gt; 类型。使用这个 &lt;code&gt;Field&lt;/code&gt; 可以传递以下几个参数：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;auto_now&lt;/code&gt; ：在每次这个数据保存的时候，都使用当前的时间。比如作为一个记录修改日期的字段，可以将这个属性设置为 &lt;code&gt;True&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;auto_now_add&lt;/code&gt; ：在每次数据第一次被添加进去的时候，都使用当前的时间。比如作为一个记录第一次入库的字段，可以将这个属性设置为 &lt;code&gt;True&lt;/code&gt; 。&lt;/p&gt;
&lt;h4&gt;DateTimeField：&lt;/h4&gt;
&lt;p&gt;日期时间类型，类似于 &lt;code&gt;DateField &lt;/code&gt;。不仅仅可以存储日期，还可以存储时间。映射到数据库中是&lt;code&gt;datetime&lt;/code&gt; 类型。这个 &lt;code&gt;Field&lt;/code&gt; 也可以使用 &lt;code&gt;auto_now&lt;/code&gt; 和 &lt;code&gt;auto_now_add&lt;/code&gt; 两个属性。&lt;/p&gt;
&lt;h4&gt;TimeField：&lt;/h4&gt;
&lt;p&gt;时间类型。在数据库中是 &lt;code&gt;time&lt;/code&gt; 类型。在 Python 中是 &lt;code&gt;datetime.time&lt;/code&gt; 类型。&lt;/p&gt;
&lt;h4&gt;EmailField：&lt;/h4&gt;
&lt;p&gt;类似于 &lt;code&gt;CharField&lt;/code&gt; 。在数据库底层也是一个 &lt;code&gt;varchar&lt;/code&gt; 类型。最大长度是254个字符。&lt;/p&gt;
&lt;h4&gt;FileField：&lt;/h4&gt;
&lt;p&gt;用来存储文件的&lt;/p&gt;
&lt;h4&gt;ImageField：&lt;/h4&gt;
&lt;p&gt;用来存储图片文件的&lt;/p&gt;
&lt;h4&gt;FloatField：&lt;/h4&gt;
&lt;p&gt;浮点类型。映射到数据库中是 &lt;code&gt;float&lt;/code&gt; 类型。&lt;/p&gt;
&lt;h4&gt;IntegerField：&lt;/h4&gt;
&lt;p&gt;整形。值的区间是 -2147483648—2147483647 。&lt;/p&gt;
&lt;h4&gt;BigIntegerField&lt;/h4&gt;
&lt;p&gt;大整形。值的区间是 -9223372036854775808—9223372036854775807 。&lt;/p&gt;
&lt;h4&gt;PositiveIntegerField：&lt;/h4&gt;
&lt;p&gt;正整形。值的区间是 0—2147483647 。&lt;/p&gt;
&lt;h4&gt;SmallIntegerField：&lt;/h4&gt;
&lt;p&gt;小整形。值的区间是 -32768—32767 。&lt;/p&gt;
&lt;h4&gt;PositiveSmallIntegerField：&lt;/h4&gt;
&lt;p&gt;正小整形。值的区间是 0—32767 。&lt;/p&gt;
&lt;h4&gt;TextField：&lt;/h4&gt;
&lt;p&gt;大量的文本类型。映射到数据库中是&lt;code&gt;longtext&lt;/code&gt;类型。&lt;/p&gt;
&lt;h4&gt;UUIDField：&lt;/h4&gt;
&lt;p&gt;只能存储 &lt;code&gt;uuid&lt;/code&gt; 格式的字符串。 &lt;code&gt;uuid&lt;/code&gt; 是一个&lt;code&gt;32&lt;/code&gt;位的全球唯一的字符串，一般用来作为主键。&lt;/p&gt;
&lt;h4&gt;URLField：&lt;/h4&gt;
&lt;p&gt;类似于 &lt;code&gt;CharField&lt;/code&gt; ，只不过只能用来存储 &lt;code&gt;url&lt;/code&gt; 格式的字符串。并且默认的 &lt;code&gt;max_length&lt;/code&gt; 是&lt;code&gt;200&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;Field的常用参数&lt;/h3&gt;
&lt;p&gt;在Django模型中初始化字段时，可以使用各种参数来自定义字段的行为。每个参数都有特定的目的，并允许您定义字段的特性和约束。&lt;/p&gt;
&lt;p&gt;以下是初始化字段时使用的一些常见参数：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.db import models

# max_length：指定字段的最大长度
# min_length：指定字段的最低长度
class Book(models.Model):
    title = models.CharField(max_length=100, min_length=1)

# null：确定字段是否可以存储NULL值
class Student(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField(null=True)

# blank：指示字段是否允许为空
class Article(models.Model):
    title = models.CharField(max_length=100, blank=True)

# default：为字段设置默认值
class Order(models.Model):
    order_number = models.CharField(max_length=10, default=&amp;quot;0000&amp;quot;)

# choices：为字段提供选项列表
GENDER_CHOICES = [
    (&amp;#039;M&amp;#039;, &amp;#039;Male&amp;#039;),
    (&amp;#039;F&amp;#039;, &amp;#039;Female&amp;#039;),
    (&amp;#039;O&amp;#039;, &amp;#039;Other&amp;#039;),
]
class Person(models.Model):
    name = models.CharField(max_length=100)
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES)

# primary_key：指示字段是否为模型的主键
class UserProfile(models.Model):
    user_id = models.AutoField(primary_key=True)
    username = models.CharField(max_length=100)

# unique：指定字段的值必须在所有模型实例中唯一
class Product(models.Model):
    product_code = models.CharField(max_length=10, unique=True)

# verbose_name：为字段设置一个人类可读的名称
class Car(models.Model):
    make = models.CharField(max_length=100, verbose_name=&amp;quot;Car Make&amp;quot;)

# help_text：为字段提供额外的描述性文本
class Employee(models.Model):
    name = models.CharField(max_length=100, help_text=&amp;quot;Employee&amp;#039;s full name&amp;quot;)

# validators：允许您为字段指定验证器列表
from django.core.validators import MinValueValidator, MaxValueValidator
class Score(models.Model):
    score = models.IntegerField(validators=[MinValueValidator(0), MaxValueValidator(100)])

# upload_to：与ImageField一起使用，指定上传文件的目录
class UserProfile(models.Model):
    name = models.CharField(max_length=100)
    profile_pic = models.ImageField(upload_to=&amp;#039;profile_pics/&amp;#039;)

# db_index：指示字段是否应该有数据库索引以加快查询速度
class Person(models.Model):
    name = models.CharField(max_length=100, db_index=True)

# editable：确定字段在表单和admin接口中是否可编辑
class Task(models.Model):
    task_name = models.CharField(max_length=100, editable=False)

# db_column: 重命名当前字段，保存到数据时不使用name，而使用tag_name作为表的字段名    
class Tag(models.Model):    
    name = models.CharField(max_length=20,db_column=&amp;quot;tag_name&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;max_length&lt;/strong&gt;：指定字段的最大长度。这个参数适用于如&lt;code&gt;CharField&lt;/code&gt;和&lt;code&gt;CommaSeparatedIntegerField&lt;/code&gt;这样的字段。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;null&lt;/strong&gt;：确定字段是否可以在数据库中存储&lt;code&gt;NULL&lt;/code&gt;值。如果设置为&lt;code&gt;True&lt;/code&gt;，则字段可以是&lt;code&gt;NULL&lt;/code&gt;的；如果设置为&lt;code&gt;False&lt;/code&gt;，则字段将有一个必填值。在使用字符串相关的Field （&lt;code&gt;CharField&lt;/code&gt; / &lt;code&gt;TextField&lt;/code&gt;）的时候，官方推荐尽量不要使用这个参数，也就是保持默认值 &lt;code&gt;False&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;blank&lt;/strong&gt;：指示字段是否允许为空（即，包含一个空值）。如果设置为&lt;code&gt;True&lt;/code&gt;，则字段可以为空；如果设置为&lt;code&gt;False&lt;/code&gt;，则字段必须有一个值。这个和 &lt;code&gt;null&lt;/code&gt; 是有区别的， &lt;code&gt;null&lt;/code&gt; 是一个纯数据库级别的。而 &lt;code&gt;blank&lt;/code&gt; 是表单验证级别的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;default&lt;/strong&gt;：为字段设置默认值。如果在创建对象时没有提供值，则将使用默认值。可以为一个值，或者是一个函数，但是不支持 &lt;code&gt;lambda&lt;/code&gt; 表达式。并且不支持列表/字典/集合等可变的数据结构。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;choices&lt;/strong&gt;：为字段提供选项列表。这个参数与如&lt;code&gt;CharField&lt;/code&gt;和&lt;code&gt;IntegerField&lt;/code&gt;这样的字段一起使用，以限制可能的值。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;primary_key&lt;/strong&gt;：指示字段是否为模型的主键。只能有一个字段被设置为主键。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;unique&lt;/strong&gt;：指定字段的值必须在所有模型实例中唯一。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;verbose_name&lt;/strong&gt;：为字段设置一个人类可读的名称。这在表单或admin接口中显示字段时用作标签。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;help_text&lt;/strong&gt;：为字段提供额外的描述性文本。当用户与字段交互时，此文本显示为工具提示或提示。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;validators&lt;/strong&gt;：允许您为字段指定验证器列表。验证器是验证字段值的函数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;upload_to&lt;/strong&gt;：与&lt;code&gt;ImageField&lt;/code&gt;一起使用，以指定上传文件应存储的目录。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;db_index&lt;/strong&gt;：指示字段是否应该有数据库索引以加快&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;editable&lt;/strong&gt;：确定字段在表单和admin接口中是否可编辑。这对于不应该在admin界面中更改的字段（如自动生成的字段）很有用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;db_column&lt;/strong&gt;：这个字段在数据库中是表下的字段的名字。如果没有设置这个参数，那么将会使用模型中属性的名字。&lt;/p&gt;
&lt;p&gt;这些参数为Django模型中的字段行为提供了灵活性和控制。通过适当使用这些参数，您可以根据特定要求和约束定制字段。&lt;/p&gt;
&lt;p&gt;更多 Field 参数详情可以参考官方文档：&lt;a href=&quot;https://docs.djangoproject.com/zh-hans/5.0/ref/models/fields/&quot;&gt;https://docs.djangoproject.com/zh-hans/5.0/ref/models/fields/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;模型中Meta配置&lt;/h2&gt;
&lt;p&gt;对于一些模型级别的配置。我们可以在模型中定义一个类，叫做 Meta 。然后在这个类中添加一些类属性来控制模型的作用。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;class Book(models.Model):
    name = models.CharField(max_length=20,null=False)
    desc = models.CharField(max_length=100,name=&amp;#039;description&amp;#039;,db_column=&amp;quot;description1&amp;quot;)     
    pub_date = models.DateTimeField(auto_now_add=True)

    class Meta:         
        db_table = &amp;#039;book_model&amp;#039;         
        ordering = [&amp;#039;pub_date&amp;#039;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;db_table&lt;/strong&gt;：这个模型映射到数据库中的表名。如果没有指定这个参数，那么在映射的时候将会使用模型名来作为默认的表名&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ordering&lt;/strong&gt;：设置在提取数据的排序方式，比如我想在查找数据的时候根据添加的时间排序&lt;/p&gt;
&lt;p&gt;模型 &lt;code&gt;Meta&lt;/code&gt; 选项官方文档：&lt;a href=&quot;https://docs.djangoproject.com/zh-hans/5.0/ref/models/options/&quot;&gt;https://docs.djangoproject.com/zh-hans/5.0/ref/models/options/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;外键和表关系&lt;/h2&gt;
&lt;h3&gt;外键&lt;/h3&gt;
&lt;p&gt;在 MySQL 中，表有两种引擎，一种是 &lt;code&gt;InnoDB&lt;/code&gt; ，另外一种是 &lt;code&gt;myisam&lt;/code&gt; 。如果使用的是 &lt;code&gt;InnoDB&lt;/code&gt; 引擎，是支持外键约束的。外键的存在使得 &lt;code&gt;ORM&lt;/code&gt; 框架在处理表关系的时候异常的强大。&lt;/p&gt;
&lt;p&gt;外键在 Django 中的使用，类定义为 &lt;code&gt;class ForeignKey(to,on_delete,**options) &lt;/code&gt;。第一个参数是引用的是哪个模型，第二个参数是在使用外键引用的模型数据被删除了，这个字段该如何处理，比如有 &lt;code&gt;CASCADE&lt;/code&gt; 、 &lt;code&gt;SET_NULL&lt;/code&gt;等。&lt;/p&gt;
&lt;p&gt;这里以一个实际案例来说明。比如有一个 &lt;code&gt;User&lt;/code&gt; 和一个 &lt;code&gt;Article&lt;/code&gt; 两个模型。一个 &lt;code&gt;User&lt;/code&gt;可以发表多篇文章，一个 &lt;code&gt;Article&lt;/code&gt; 只能有一个 &lt;code&gt;Author&lt;/code&gt;，并且通过外键进行引用。那么相关的示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;class User(models.Model):
    username = models.CharField(max_length=20)     
    password = models.CharField(max_length=100)

class Article(models.Model):     
    title = models.CharField(max_length=100)     
    content = models.TextField()

    author = models.ForeignKey(&amp;quot;User&amp;quot;,on_delete=models.CASCADE)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上使用 &lt;code&gt;ForeignKey&lt;/code&gt; 来定义模型之间的关系。即在 &lt;code&gt;article&lt;/code&gt; 的实例中可以通过 &lt;code&gt;author&lt;/code&gt; 属性来操作对应的 &lt;code&gt;User&lt;/code&gt; 模型。这样使用起来非常的方便。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;article = Article(title=&amp;#039;abc&amp;#039;,content=&amp;#039;123&amp;#039;) 
author = User(username=&amp;#039;张三&amp;#039;,password=&amp;#039;111111&amp;#039;) 
article.author = author 
article.save()

# 修改article.author上的值
article.author.username = &amp;#039;李四&amp;#039;
article.save()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用了 &lt;code&gt;ForeignKey&lt;/code&gt; 后，就能通过 &lt;code&gt;author&lt;/code&gt; 访问到对应的 &lt;code&gt;user&lt;/code&gt; 对象的原因，是因为在底层， Django 为&lt;code&gt;Article&lt;/code&gt; 表添加了一个 属性名&lt;code&gt;_id&lt;/code&gt; 的字段（比如&lt;code&gt;author&lt;/code&gt;的字段名称是&lt;code&gt;author_id&lt;/code&gt;），这个字段是一个外
键，记录着对应的作者的主键。以后通过 &lt;code&gt;article.author&lt;/code&gt; 访问的时候，实际上是先通过 &lt;code&gt;author_id&lt;/code&gt; 找到对应的数据，然后再提取 &lt;code&gt;User&lt;/code&gt; 表中的这条数据，形成一个模型。
如果想要引用另外一个 &lt;code&gt;app&lt;/code&gt; 的模型，那么应该在传递 &lt;code&gt;to&lt;/code&gt; 参数的时候，使用 &lt;code&gt;app.model_name&lt;/code&gt; 进行指定。以上例为例，如果 &lt;code&gt;User&lt;/code&gt; 和 &lt;code&gt;Article&lt;/code&gt; 不是在同一个 &lt;code&gt;app&lt;/code&gt; 中，那么在引用的时候的示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# User模型在user这个app中
class User(models.Model):
    username = models.CharField(max_length=20)     
    password = models.CharField(max_length=100)

# Article模型在article这个app中
class Article(models.Model):     
    title = models.CharField(max_length=100)     
    content = models.TextField()

    author = models.ForeignKey(&amp;quot;user.User&amp;quot;,on_delete=models.CASCADE)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果模型的外键引用的是本身自己这个模型，那么 &lt;code&gt;to&lt;/code&gt; 参数可以为 &lt;code&gt;&amp;#039;self&amp;#039;&lt;/code&gt; ，或者是这个模型的名字。在论坛开发中，一般评论都可以进行二级评论，即可以针对另外一个评论进行评论，那么在定义模型的时
候就需要使用外键来引用自身。示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;class Comment(models.Model):
    content = models.TextField()
    origin_comment = models.ForeignKey(&amp;#039;self&amp;#039;,on_delete=models.CASCADE,null=True)
    # 或者
    # origin_comment = models.ForeignKey(&amp;#039;Comment&amp;#039;,on_delete=models.CASCADE,null=True)&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;外键删除操作&lt;/h3&gt;
&lt;p&gt;如果一个模型使用了外键。那么在对方那个模型被删掉后，该进行什么样的操作。可以通过 on_delete 来指定。可以指定的类型如下：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CASCADE&lt;/strong&gt; ：级联操作。如果外键对应的那条数据被删除了，那么这条数据也会被删除。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PROTECT&lt;/strong&gt; ：受保护。即只要这条数据引用了外键的那条数据，那么就不能删除外键的那条数据。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SET_NULL&lt;/strong&gt; ：设置为空。如果外键的那条数据被删除了，那么在本条数据上就将这个字段设置为空。如果设置这个选项，前提是要指定这个字段可以为空。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SET_DEFAULT&lt;/strong&gt; ：设置默认值。如果外键的那条数据被删除了，那么本条数据上就将这个字段设置为默认值。如果设置这个选项，前提是要指定这个字段一个默认值。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SET()&lt;/strong&gt; ：如果外键的那条数据被删除了。那么将会获取 SET 函数中的值来作为这个外键的值。 SET函数可以接收一个可以调用的对象（比如函数或者方法），如果是可以调用的对象，那么会将这个对象调用后的结果作为值返回回去。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DO_NOTHING&lt;/strong&gt; ：不采取任何行为。一切全看数据库级别的约束。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;以上这些选项只是Django级别的，数据级别依旧是RESTRICT！&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;表关系&lt;/h3&gt;
&lt;p&gt;表之间的关系都是通过外键来进行关联的。而表之间的关系，无非就是三种关系：一对一、一对多（多对一）、多对多等。&lt;/p&gt;
&lt;h3&gt;一对多&lt;/h3&gt;
&lt;p&gt;应用场景：比如文章和作者之间的关系。一个文章只能由一个作者编写，但是一个作者可以写多篇文章。文章和作者之间的关系就是典型的多对一的关系。&lt;/p&gt;
&lt;p&gt;实现方式：一对多或者多对一，都是通过 ForeignKey 来实现的。&lt;/p&gt;
&lt;p&gt;还是以文章和作者的案例进行记录。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;class User(models.Model):      
    username = models.CharField(max_length=20)      
    password = models.CharField(max_length=100)

class Article(models.Model):
     title = models.CharField(max_length=100)      
     content = models.TextField()
     author = models.ForeignKey(&amp;quot;User&amp;quot;,on_delete=models.CASCADE)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么以后在给 &lt;code&gt;Article&lt;/code&gt; 对象指定 &lt;code&gt;author&lt;/code&gt; ，就可以使用以下代码来完成：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;article = Article(title=&amp;#039;abc&amp;#039;,content=&amp;#039;123&amp;#039;) 
author = User(username=&amp;#039;zhiliao&amp;#039;,password=&amp;#039;111111&amp;#039;)
# 要先保存到数据库中
author.save()
article.author = author 
article.save()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;并且以后如果想要获取某个用户下所有的文章，可以通过 article_set 来实现。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;user = User.objects.first()

# 获取第一个用户写的所有文章
articles = user.article_set.all() 
for article in articles:     
    print(article)&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;一对一&lt;/h3&gt;
&lt;p&gt;应用场景：比如一个用户表和一个用户信息表。在实际网站中，可能需要保存用户的许多信息，但是有些信息是不经常用的。如果把所有信息都存放到一张表中可能会影响查询效率，因此可以把用户的一些不常用的信息存放到另外一张表中我们叫做 &lt;code&gt;UserExtension&lt;/code&gt; 。但是用户表 &lt;code&gt;User&lt;/code&gt; 和用户信息表 &lt;code&gt;UserExtension&lt;/code&gt; 就是典型的一对一了。&lt;/p&gt;
&lt;p&gt;实现方式： Django 为一对一提供了一个专门的 &lt;code&gt;Field&lt;/code&gt; 叫做 &lt;code&gt;OneToOneField&lt;/code&gt; 来实现一对一操作。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;class User(models.Model):      
    username = models.CharField(max_length=20)      
    password = models.CharField(max_length=100)
class UserExtension(models.Model):  
     birthday = models.DateTimeField(null=True)        
     school = models.CharField(blank=True,max_length=50)        
     user = models.OneToOneField(&amp;quot;User&amp;quot;, on_delete=models.CASCADE)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 &lt;code&gt;UserExtension&lt;/code&gt; 模型上增加了一个一对一的关系映射。其实底层是在 &lt;code&gt;UserExtension&lt;/code&gt; 这个表上增加了一个 &lt;code&gt;user_id&lt;/code&gt; ，来和 &lt;code&gt;user&lt;/code&gt; 表进行关联，并且这个外键数据在表中必须是唯一的，来保证一对一。&lt;/p&gt;
&lt;h3&gt;多对多&lt;/h3&gt;
&lt;p&gt;应用场景：比如文章和标签的关系。一篇文章可以有多个标签，一个标签可以被多个文章所引用。因此标签和文章的关系是典型的多对多的关系。&lt;/p&gt;
&lt;p&gt;实现方式： Django 为这种多对多的实现提供了专门的 &lt;code&gt;Field&lt;/code&gt; 。叫做 &lt;code&gt;ManyToManyField&lt;/code&gt; 。还是拿文章和标签为例进行讲解。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;class Article(models.Model):
    title = models.CharField(max_length=100)      
    content = models.TextField()
    tags = models.ManyToManyField(&amp;quot;Tag&amp;quot;,related_name=&amp;quot;articles&amp;quot;)

class Tag(models.Model):      
    name = models.CharField(max_length=50)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在数据库层面，实际上 Django 是为这种多对多的关系建立了一个中间表。这个中间表分别定义了两个外键，引用到 &lt;code&gt;article&lt;/code&gt; 和 &lt;code&gt;tag&lt;/code&gt; 两张表的主键。&lt;/p&gt;
&lt;h3&gt;related_name和related_query_name&lt;/h3&gt;
&lt;h4&gt;related_name&lt;/h4&gt;
&lt;p&gt;还是以 &lt;code&gt;User&lt;/code&gt; 和 &lt;code&gt;Article&lt;/code&gt; 为例来进行。如果一个 &lt;code&gt;article&lt;/code&gt; 想要访问对应的作者，那么可以通过&lt;code&gt;author&lt;/code&gt; 来进行访问。&lt;/p&gt;
&lt;p&gt;但是如果有一个 &lt;code&gt;user&lt;/code&gt; 对象，想要通过这个 &lt;code&gt;user&lt;/code&gt; 对象获取所有的文章，这时候可以通过 &lt;code&gt;user.article_set&lt;/code&gt; 来访问，这个名字的规律是 &lt;code&gt;模型名字小写_set&lt;/code&gt; 。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;user = User.objects.get(name=&amp;#039;张三&amp;#039;) 
user.article_set.all()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果不想使用 &lt;code&gt;模型名字小写_set&lt;/code&gt; 的方式，想要使用其他的名字，那么可以在定义模型的时候指定&lt;code&gt;related_name&lt;/code&gt; &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;class Article(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    # 传递related_name参数，以后在方向引用的时候使用articles进行访问
    author = models.ForeignKey(&amp;quot;User&amp;quot;,on_delete=models.SET_NULL,null=True,related_name=&amp;#039;articles&amp;#039;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以后在反向引用的时候。使用 articles 可以访问到这个作者的文章模型。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;user = User.objects.get(name=&amp;#039;张三&amp;#039;) 
user.articles.all()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果不想使用反向引用，那么可以指定 &lt;code&gt;related_name=&amp;#039;+&amp;#039; &lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;class Article(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    # 传递related_name参数，以后在方向引用的时候使用articles进行访问
    author = models.ForeignKey(&amp;quot;User&amp;quot;,on_delete=models.SET_NULL,null=True,related_name=&amp;#039;+&amp;#039;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以后将不能通过 &lt;code&gt;user.article_set&lt;/code&gt; 来访问文章模型了&lt;/p&gt;
&lt;h4&gt;related_query_name&lt;/h4&gt;
&lt;p&gt;在查找数据的时候，可以使用 &lt;code&gt;filter&lt;/code&gt; 进行过滤。使用 &lt;code&gt;filter&lt;/code&gt; 过滤的时候，不仅仅可以指定本模型上的某个属性要满足什么条件，还可以指定相关联的模型满足什么属性。比如现在想要获取写过标题为 &lt;code&gt;abc&lt;/code&gt; 的所有用户，那么可以这样写：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;users = User.objects.filter(article__title=&amp;#039;abc&amp;#039;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果设置了 &lt;code&gt;related_name&lt;/code&gt; 为 &lt;code&gt;articles&lt;/code&gt; ，因为反转的过滤器的名字将使用 &lt;code&gt;related_name&lt;/code&gt; 的名字，那么上例代码将改成如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;users = User.objects.filter(articles__title=&amp;#039;abc&amp;#039;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以通过 &lt;code&gt;related_query_name&lt;/code&gt; 将查询的反转名字修改成其他的名字。比如 &lt;code&gt;article&lt;/code&gt; 。示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;class Article(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    # 传递related_name参数，以后在方向引用的时候使用articles进行访问
    author = models.ForeignKey(&amp;quot;User&amp;quot;,on_delete=models.SET_NULL,null=True,related_name=&amp;#039;articl es&amp;#039;,related_query_name=&amp;#039;article&amp;#039;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么在做反向过滤查找的时候就可以使用以下代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;users = User.objects.filter(article__title=&amp;#039;abc&amp;#039;)&lt;/code&gt;&lt;/pre&gt;</content></entry><entry><title>Django  DTL 模板</title><link href="https://www.moshanghua.net/archives/django-dtl-%E6%A8%A1%E6%9D%BF.html" /><id>https://www.moshanghua.net/archives/django-dtl-%E6%A8%A1%E6%9D%BF.html</id><updated>2024-07-27T12:32:22.000Z</updated><summary></summary><content type="html">&lt;p&gt;目前市面上有非常多的模板系统，其中最知名最好用的就是&lt;code&gt;DTL&lt;/code&gt;和&lt;code&gt;Jinja2&lt;/code&gt;。 &lt;code&gt;DTL&lt;/code&gt; 是 &lt;code&gt;Django Template Language&lt;/code&gt; 三个单词的缩写，也就是Django自带的模板语言。当然也可以配置Django支持Jinja2等其他模板引擎，但是作为Django内置的模板语言，和Django可以达到无缝衔接而不会产生一些不兼容的情况。&lt;/p&gt;
&lt;h2&gt;DTL与普通的HTML文件的区别&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;DTL&lt;/code&gt;模板是一种带有特殊语法的&lt;code&gt;HTML&lt;/code&gt;文件，这个&lt;code&gt;HTML&lt;/code&gt;文件可以被&lt;code&gt;Django&lt;/code&gt;编译，可以传递参数进去，实现数据动态化。在编译完成后，生成一个普通的HTML文件，然后发送给客户端。&lt;/p&gt;
&lt;h2&gt;渲染模板&lt;/h2&gt;
&lt;p&gt;渲染模板有多种方式。列举两种常用的方式。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;render_to_string&lt;/code&gt; ：找到模板，然后将模板编译后渲染成&lt;code&gt;Python&lt;/code&gt;的字符串格式。最后再通过&lt;code&gt;HttpResponse&lt;/code&gt; 类包装成一个 &lt;code&gt;HttpResponse&lt;/code&gt; 对象返回回去。示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.template.loader import render_to_string 
from django.http import HttpResponse 

def book_detail(request,book_id):      
    html = render_to_string(&amp;quot;detail.html&amp;quot;)      
    return HttpResponse(html)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;django还提供了一个更加简便的方式，直接将模板渲染成字符串和包装成 &lt;code&gt;HttpResponse&lt;/code&gt; 对象一步到位完成。示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.shortcuts import render 
def book_list(request):      
    return render(request,&amp;#039;list.html&amp;#039;)&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;模板查找路径配置：&lt;/h2&gt;
&lt;p&gt;在项目的 settings.py 文件中。有一个 &lt;code&gt;TEMPLATES&lt;/code&gt; 配置，这个配置包含了模板引擎的配置，模板查找路径的配置，模板上下文的配置等。&lt;/p&gt;
&lt;p&gt;模板路径可以在两个地方配置。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;DIRS&lt;/code&gt; ：这是一个列表，在这个列表中可以存放所有的模板路径，以后在视图中使用 render 或者render_to_string 渲染模板的时候，会在这个列表的路径中查找模板。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;APP_DIRS&lt;/code&gt; ：默认为 True ，这个设置为 True 后，会在 INSTALLED_APPS 的安装了的 APP 下的templates 文件夹中查找模板。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;TEMPLATES = [
    {
        ....
        # 定义存放模板的目录，这里使用 templates 目录
        &amp;quot;DIRS&amp;quot;: [BASE_DIR / &amp;quot;templates&amp;quot;],
        &amp;quot;APP_DIRS&amp;quot;: True,
        &amp;quot;OPTIONS&amp;quot;: {
        ...
    },
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查找顺序：比如代码 &lt;code&gt;render(&amp;#039;list.html&amp;#039;)&lt;/code&gt; 。先会在 &lt;code&gt;DIRS&lt;/code&gt; 这个列表中依次查找路径下有没有这个模板，如果有，就返回。&lt;/p&gt;
&lt;p&gt;如果 &lt;code&gt;DIRS&lt;/code&gt; 列表中所有的路径都没有找到，那么会先检查当前这个视图所处的 &lt;code&gt;app&lt;/code&gt; 是否已经安装，如果已经安装了，那么就先在当前这个 &lt;code&gt;app&lt;/code&gt; 下的 &lt;code&gt;templates&lt;/code&gt; 文件夹中查找模板，如果没有找到，那么会在其他已经安装了的 &lt;code&gt;app&lt;/code&gt; 中查找。如果所有路径下都没有找到，那么会抛出一个 &lt;code&gt;TemplateDoesNotExist&lt;/code&gt; 的异常。&lt;/p&gt;
&lt;h2&gt;DTL模板语法&lt;/h2&gt;
&lt;h3&gt;变量：&lt;/h3&gt;
&lt;p&gt;模板中可以包含变量， Django 在渲染模板的时候，可以传递变量对应的值过去进行替换。变量的命名规范和 Python 非常类似，只能是阿拉伯数字和英文字符以及下划线的组合，不能出现标点符号等特殊字符。&lt;/p&gt;
&lt;p&gt;变量需要通过视图函数渲染，视图函数在使用 &lt;code&gt;render&lt;/code&gt; 或者 &lt;code&gt;render_to_string&lt;/code&gt; 的时候可以传递一个&lt;code&gt;context&lt;/code&gt; 的参数，这个参数是一个字典类型。以后在模板中的变量就从这个字典中读取值的。示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# views.py代码
def profile(request):
    return render(request,&amp;#039;profile.html&amp;#039;,context={&amp;#039;username&amp;#039;:&amp;#039;陌上花&amp;#039;})

# profile.html模板代码
&amp;lt;p&amp;gt;{{ username }}&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;除了变量，还可以是字典，列表以及对象。模板中的变量同样也支持 点(.) 的形式。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# views.py代码
def info(request):
    # 1. 普通的变量
    username = &amp;quot;悦来小陌&amp;quot;
    # 2. 字典类型
    book = {&amp;quot;firm&amp;quot;: &amp;quot;悦来集团&amp;quot;, &amp;quot;name&amp;quot;: &amp;quot;henry&amp;quot;}
    # 3. 列表
    books = [
        {&amp;quot;name&amp;quot;: &amp;quot;全职高手&amp;quot;, &amp;quot;author&amp;quot;: &amp;quot;蝴蝶蓝&amp;quot;},
        {&amp;quot;name&amp;quot;: &amp;quot;斗破苍穹&amp;quot;, &amp;quot;author&amp;quot;: &amp;quot;天蚕土豆&amp;quot;},
    ]

    # 4. 对象
    class Person:
        def __init__(self, realname):
            self.realname = realname

    context = {
        &amp;quot;username&amp;quot;: username,
        &amp;quot;book&amp;quot;: book,
        &amp;quot;books&amp;quot;: books,
        &amp;quot;Person&amp;quot;: Person(&amp;quot;陌上花&amp;quot;),
    }
    return render(request, &amp;quot;info.html&amp;quot;, context=context)

# infp.html模板代码
&amp;lt;!-- 变量 --&amp;gt;
&amp;lt;p&amp;gt;{{username}}&amp;lt;/p&amp;gt;

&amp;lt;!-- 字典 --&amp;gt;
&amp;lt;p&amp;gt;公司名称:{{book.firm}}, CEO: {{book.name}}&amp;lt;/p&amp;gt;

&amp;lt;!-- 列表 --&amp;gt;
&amp;lt;p&amp;gt;下标为 0 的小说作者是: {{books.0.author}}&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;下标为 1 的小说是: {{books.1.name}}&amp;lt;/p&amp;gt;

&amp;lt;!-- 对象 --&amp;gt;
&amp;lt;p&amp;gt;姓名为: {{Person.realname}}&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在出现了点的情况，比如&lt;code&gt;book.firm&lt;/code&gt; ，模板是按照以下方式进行解析的：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如果 &lt;code&gt;book&lt;/code&gt; 是一个字典，那么就会查找这个字典的 &lt;code&gt;firm&lt;/code&gt; 这个 &lt;code&gt;key&lt;/code&gt; 对应的值。&lt;/li&gt;
&lt;li&gt;如果 &lt;code&gt;person&lt;/code&gt; 是一个对象，那么就会查找这个对象的 &lt;code&gt;realname&lt;/code&gt; 属性，或者是 &lt;code&gt;realname&lt;/code&gt; 这个方法。&lt;/li&gt;
&lt;li&gt;如果出现的是 &lt;code&gt;books.1&lt;/code&gt; ，会判断 &lt;code&gt;books&lt;/code&gt; 是否是一个列表或者元组或者任意的可以通过下标访问的对象，如果是的话就取这个列表的第1个值。如果不是就获取到的是一个空的字符串。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;有以下几点需要注意：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;不能通过中括号的形式访问字典和列表中的值，比如&lt;code&gt;dict[&amp;#039;key&amp;#039;]&lt;/code&gt;和&lt;code&gt;list[1]&lt;/code&gt;是不支持的！DTL模板语法里改为点（&lt;code&gt;.&lt;/code&gt;）来访问，对应的应该是&lt;code&gt;dict.key&lt;/code&gt; 和&lt;code&gt;list.1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;因为使用点（&lt;code&gt;.&lt;/code&gt;）语法获取对象值的时候，可以获取这个对象的属性，如果这个对象是一个字典，也可以获取这个字典的值。所以在给这个字典添加key的时候，千万不能和字典中的一些属性重复。比如items，因为items是字典的方法，那么如果给这个字典添加一个items作为key，那么以后就不能再通过item来访问这个字典的键值对了。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;常用的模板标签&lt;/h3&gt;
&lt;h4&gt;if 标签&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;if&lt;/code&gt; 标签相当于 Python 中的 &lt;code&gt;if&lt;/code&gt; 语句，有 &lt;code&gt;elif&lt;/code&gt; 和 &lt;code&gt;else&lt;/code&gt; 相对应，但是所有的标签都需要用标签符号（ &lt;code&gt;{%%}&lt;/code&gt; ）进行包裹。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;if&lt;/code&gt; 标签中可以使用 &lt;code&gt;==&lt;/code&gt;、&lt;code&gt;!=&lt;/code&gt;、&lt;code&gt;&amp;lt;&lt;/code&gt;、&lt;code&gt;&amp;lt;=&lt;/code&gt;、&lt;code&gt;&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;gt;=&lt;/code&gt;、&lt;code&gt;in&lt;/code&gt;、&lt;code&gt;not in&lt;/code&gt;、&lt;code&gt;is&lt;/code&gt;、&lt;code&gt;is not&lt;/code&gt; 等判断运算符。&lt;/p&gt;
&lt;p&gt;还有注意的是，使用if时有起始标签&lt;code&gt;{% if %}&lt;/code&gt;，就要有结束标签&lt;code&gt;{% endif %}&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;{% if num &amp;gt; 18 %}
  &amp;lt;p&amp;gt;数字大于 18&amp;lt;/p&amp;gt;
{% elif num == 18 %}
  &amp;lt;p&amp;gt;数字等于 18&amp;lt;/p&amp;gt;
{% else %}
  &amp;lt;p&amp;gt;数字小于 18&amp;lt;/p&amp;gt;
{% endif %}&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;for...in... 标签&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;for...in...&lt;/code&gt; 类似于 Python 中的 &lt;code&gt;for...in...&lt;/code&gt; 。可以遍历列表、元组、字符串、字典等一切可以遍历的对象。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;{% for person in persons %}      
  &amp;lt;p&amp;gt;{{ person.name }}&amp;lt;/p&amp;gt; 
{% endfor %}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果想要反向遍历，那么在遍历的时候就加上一个 &lt;code&gt;reversed&lt;/code&gt; 。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;{% for person in persons reversed %}      
  &amp;lt;p&amp;gt;{{ person.name }}&amp;lt;/p&amp;gt; 
{% endfor %}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;遍历字典的时候，需要使用 &lt;code&gt;items&lt;/code&gt; 、 &lt;code&gt;keys&lt;/code&gt; 和 &lt;code&gt;values &lt;/code&gt;等方法。在 DTL 中，执行一个方法不能使用圆括号的形式。遍历字典示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-HTML&quot;&gt; {% for key,value in person.items %}      
   &amp;lt;p&amp;gt;key：{{ key }}&amp;lt;/p&amp;gt;      
   &amp;lt;p&amp;gt;value：{{ value }}&amp;lt;/p&amp;gt; 
 {% endfor %}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 &lt;code&gt;for&lt;/code&gt; 循环中， DTL 提供了一些变量可供使用。这些变量如下：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;forloop.counter&lt;/code&gt; ：当前循环的下标。以1作为起始值。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;forloop.counter0&lt;/code&gt; ：当前循环的下标。以0作为起始值。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;forloop.revcounter&lt;/code&gt; ：当前循环的反向下标值。比如列表有5个元素，那么第一次遍历这个属性是等于5，第二次是4，以此类推。并且是以1作为最后一个元素的下标。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;forloop.revcounter0&lt;/code&gt; ：类似于 forloop.revcounter 。不同的是最后一个元素的下标是从0开始。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;forloop.first&lt;/code&gt; ：是否是第一次遍历。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;forloop.last&lt;/code&gt; ：是否是最后一次遍历。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;forloop.parentloop&lt;/code&gt; ：如果有多个循环嵌套，那么这个属性代表的是上一级的for循环。&lt;/p&gt;
&lt;h4&gt;for...in...empty 标签&lt;/h4&gt;
&lt;p&gt;这个标签使用跟 for...in... 是一样的，只不过是在遍历的对象如果没有元素的情况下，会执行 empty 中的内容。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;{% for person in persons %}      
&amp;lt;li&amp;gt;{{ person }}&amp;lt;/li&amp;gt; 
{% empty %}      
暂时还没有任何人
{% endfor %}&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;with 标签&lt;/h4&gt;
&lt;p&gt;在模版中定义变量。有时候一个变量访问的时候比较复杂，那么可以先把这个复杂的变量缓存到一个变量上，以后就可以直接使用这个变量就可以了。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;context = {      
    &amp;quot;persons&amp;quot;: [&amp;quot;xiaomo&amp;quot;,&amp;quot;henry&amp;quot;]
}

{% with lisi=persons.1 %}      
  &amp;lt;p&amp;gt;{{ lisi }}&amp;lt;/p&amp;gt; 
{% endwith %}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;有几点需要强烈的注意：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;with&lt;/code&gt; 语句中定义的变量，只能在 &lt;code&gt;{%with%}{%endwith%}&lt;/code&gt; 中使用，不能在这个标签外面使用。&lt;/p&gt;
&lt;p&gt;定义变量的时候，不能在等号左右两边留有空格。比如 &lt;code&gt;{% with lisi = persons.1%}&lt;/code&gt; 是错误的。&lt;/p&gt;
&lt;p&gt;还有另外一种写法同样也是支持的：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;  {% with persons.1 as lisi %}       
    &amp;lt;p&amp;gt;{{ lisi }}&amp;lt;/p&amp;gt;   
  {% endwith %}&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;url 标签&lt;/h4&gt;
&lt;p&gt;在模版中，经常要写一些 &lt;code&gt;url&lt;/code&gt; ，比如某个&lt;code&gt;a&lt;/code&gt;标签中需要定义 &lt;code&gt;href&lt;/code&gt; 属性。当然如果通过硬编码的方式直接将这个 &lt;code&gt;url&lt;/code&gt; 写死在里面也是可以的。但是这样对于以后项目维护可能不是一件好事。&lt;/p&gt;
&lt;p&gt;因此建议使用这种反转的方式来实现，类似于 django 中的 reverse 一样。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;lt;a href=&amp;quot;{% url &amp;#039;book:list&amp;#039; %}&amp;quot;&amp;gt;图书列表页面&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 url 反转的时候需要传递参数，那么可以在后面传递。但是参数分位置参数和关键字参数。&lt;strong&gt;位置参数和关键字参数不能同时使用。&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# path部分
 path(&amp;#039;detail/&amp;lt;book_id&amp;gt;/&amp;#039;,views.book_detail,name=&amp;#039;detail&amp;#039;)

 # url反转，使用位置参数
 &amp;lt;a href=&amp;quot;{% url &amp;#039;book:detail&amp;#039; 1 %}&amp;quot;&amp;gt;图书详情页面&amp;lt;/a&amp;gt;

 # url反转，使用关键字参数
 &amp;lt;a href=&amp;quot;{% url &amp;#039;book:detail&amp;#039; book_id=1 %}&amp;quot;&amp;gt;图书详情页面&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;spaceless 标签&lt;/h4&gt;
&lt;p&gt;移除html标签中的空白字符。包括空格、tab键、换行等。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt; {% spaceless %}      
     &amp;lt;p&amp;gt;
         &amp;lt;a href=&amp;quot;foo/&amp;quot;&amp;gt;Foo&amp;lt;/a&amp;gt;      
     &amp;lt;/p&amp;gt; 
 {% endspaceless %}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么在渲染完成后，会变成以下的代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-HTML&quot;&gt;&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;foo/&amp;quot;&amp;gt;Foo&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;aceless 只会移除html标签之间的空白字符。而不会移除标签与文本之间的空白字符。&lt;/p&gt;
&lt;h4&gt;autoescape 标签&lt;/h4&gt;
&lt;p&gt;开启和关闭这个标签内元素的自动转义功能。自动转义是可以将一些特殊的字符。比如&lt;code&gt;&amp;lt;&lt;/code&gt;转义成 html 语法能识别的字符，会被转义成&lt;code&gt;&amp;lt;&lt;/code&gt;，而&lt;code&gt;&amp;gt;&lt;/code&gt;会被自动转义成 &lt;code&gt;&amp;gt;&lt;/code&gt;。模板中默认是已经开启了自动转义的。 &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# 传递的上下文信息
context = {
     &amp;quot;info&amp;quot;:&amp;quot;&amp;lt;a href=&amp;#039;www.baidu.com&amp;#039;&amp;gt;百度&amp;lt;/a&amp;gt;&amp;quot;
 }

# 模板中关闭自动转义
{% autoescape off %}      
  {{ info }} 
{% endautoescape %}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么就会显示百度的一个超链接。如果把 off 改成 on ，那么就会显示成一个普通的字符串。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;{% autoescape on %}      
  {{ info }} 
{% endautoescape %}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更多标签可以查看官方文档：&lt;a href=&quot;https://docs.djangoproject.com/zh-hans/5.0/ref/templates/builtins/&quot;&gt;https://docs.djangoproject.com/zh-hans/5.0/ref/templates/builtins/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;模板常用过滤器&lt;/h2&gt;
&lt;p&gt;在模版中，有时候需要对一些数据进行处理以后才能使用，一般在 Python 中是通过函数的形式来完成的。&lt;/p&gt;
&lt;p&gt;而在模版中，则是通过过滤器来实现的，过滤器使用的是&lt;code&gt;|&lt;/code&gt;来使用。&lt;/p&gt;
&lt;p&gt;比如使用 add 过滤器，那么示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;{{ value|add:&amp;quot;2&amp;quot; }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;开发中常用的过滤器&lt;/p&gt;
&lt;h3&gt;cut&lt;/h3&gt;
&lt;p&gt;移除值中所有指定的字符串。类似于 python 中的 replace(args,&amp;quot;&amp;quot;) ，语法：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;{{ value|cut:&amp;quot; &amp;quot; }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;示例&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt; # 数据
 greet = &amp;quot;Hello World, Hello Python, Hello Django&amp;quot;

# 模板
{{greet}}
&gt; Hello World, Hello Python, Hello Django

# 移除空格
{{greet|cut:&amp;quot; &amp;quot;}}
&gt; HelloWorld,HelloPython,HelloDjango

# 移除逗号
{{greet|cut:&amp;quot;,&amp;quot;}}
&gt;Hello World Hello Python Hello Django
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;date&lt;/h3&gt;
&lt;p&gt;将一个日期按照指定的格式，格式化成字符串。示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# 数据
context = {
    &amp;quot;birthday&amp;quot;: datetime.now() 
    }

# 模版
{{ birthday|date:&amp;quot;Y/m/d&amp;quot; }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么将会输出 &lt;code&gt;2024/07/27&lt;/code&gt; 。其中&lt;code&gt;Y&lt;/code&gt;代表的是四位数字的年份，&lt;code&gt;m&lt;/code&gt;代表的是两位数字的月份，&lt;code&gt;d&lt;/code&gt;代表的是两位数字的日。
还有更多时间格式化的方式。见下表。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Y&lt;/code&gt;：四位数字的年份 （2024）&lt;/p&gt;
&lt;p&gt;&lt;code&gt;m&lt;/code&gt; ：两位数字的月份（01-12）
&lt;code&gt;n&lt;/code&gt; ：月份，1-9前面没有0前缀（1-12）
&lt;code&gt;d&lt;/code&gt; ：两位数字的天（01-31）
&lt;code&gt;j&lt;/code&gt; ：天，但是1-9前面没有0前缀（1-31）
&lt;code&gt;g&lt;/code&gt; ：小时，12小时格式的，1-9前面没有0前缀（1-12）
&lt;code&gt;h&lt;/code&gt; ：小时，12小时格式的，1-9前面有0前缀（01-12）
&lt;code&gt;G&lt;/code&gt; ：小时，24小时格式的，1-9前面没有0前缀（1-23）
&lt;code&gt;H&lt;/code&gt; ：小时，24小时格式的，1-9前面有0前缀（01-23）
&lt;code&gt;i&lt;/code&gt; ：分钟，1-9前面有0前缀（00-59）
&lt;code&gt;s&lt;/code&gt; ：秒，1-9前面有0前缀（00-59）&lt;/p&gt;
&lt;h3&gt;default&lt;/h3&gt;
&lt;p&gt;如果值被评估为 &lt;code&gt;False&lt;/code&gt; 。比如 &lt;code&gt;[]&lt;/code&gt; ， &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; ， &lt;code&gt;None&lt;/code&gt; ， &lt;code&gt;{} &lt;/code&gt;等这些在 &lt;code&gt;if&lt;/code&gt; 判断中为 &lt;code&gt;False&lt;/code&gt; 的值，都会使用default 过滤器提供的默认值。&lt;/p&gt;
&lt;p&gt;语法&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-TypeScript&quot;&gt;{{ value|default:&amp;quot;nothing&amp;quot; }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 value 是等于一个空的字符串。比如 &amp;quot;&amp;quot; &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# 数据
context = {
    &amp;quot;profile&amp;quot;: &amp;quot;&amp;quot;, 
    }

# 空字符就不会显示
{{profile_none}}

# 由于是空字符，就会显示 default里定义的文字 这个家伙很懒,什么都没留下.
{{profile_none|default:&amp;quot;这个家伙很懒,什么都没留下.&amp;quot;}}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;default_if_none&lt;/h3&gt;
&lt;p&gt;如果值是 None ，那么将会使用 default_if_none 提供的默认值。&lt;/p&gt;
&lt;p&gt;这个和 default 有区别， default 是所有被评估为 False 的都会使用默认值。&lt;/p&gt;
&lt;p&gt;而 default_if_none 则只有这个值是等于 None 的时候才会使用默认值。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;{{ value|default_if_none:&amp;quot;nothing&amp;quot; }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 &lt;code&gt;value&lt;/code&gt; 是等于 &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; 也即空字符串，那么以上会输出空字符串。&lt;/p&gt;
&lt;p&gt;如果 &lt;code&gt;value&lt;/code&gt; 是一个 &lt;code&gt;None&lt;/code&gt; 值，才会输出 nothing 。&lt;/p&gt;
&lt;h3&gt;first&lt;/h3&gt;
&lt;p&gt;返回列表/元组/字符串中的第一个元素。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;{{ value|first }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 &lt;code&gt;value&lt;/code&gt; 是等于 &lt;code&gt;[&amp;#039;a&amp;#039;,&amp;#039;b&amp;#039;,&amp;#039;c&amp;#039;]&lt;/code&gt; ，那么输出将会是&lt;code&gt;a&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;last&lt;/h3&gt;
&lt;p&gt;返回列表/元组/字符串中的最后一个元素。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;{{ value|last }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 &lt;code&gt;value&lt;/code&gt; 是等于 &lt;code&gt;[&amp;#039;a&amp;#039;,&amp;#039;b&amp;#039;,&amp;#039;c&amp;#039;]&lt;/code&gt; ，那么输出将会是&lt;code&gt;c&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;floatformat&lt;/h3&gt;
&lt;p&gt;使用四舍五入的方式格式化一个浮点类型。&lt;/p&gt;
&lt;p&gt;如果这个过滤器没有传递任何参数，那么只会在小数点后保留一个小数。&lt;/p&gt;
&lt;p&gt;如果小数后面全是0，那么只会保留整数。也可以传递一个参数，标识具体要保留几个小数。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# 数据
context = {
    &amp;quot;num&amp;quot;: [34.45678, 18.000, 5.17],
    }

不传参数:{{num.0|floatformat}}
&gt;不传参数:34.5

传参数保留3位:{{num.0|floatformat:3}}
&gt;传参数保留3位:34.457
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;join&lt;/h3&gt;
&lt;p&gt;类似与 Python 中的 join ，将列表/元组/字符串用指定的字符进行拼接。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;{{ value|join:&amp;quot;/&amp;quot; }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 &lt;code&gt;value&lt;/code&gt; 是等于 &lt;code&gt;[&amp;#039;a&amp;#039;,&amp;#039;b&amp;#039;,&amp;#039;c&amp;#039;]&lt;/code&gt; ，那么以上代码将输出 &lt;code&gt;a/b/c &lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;length&lt;/h3&gt;
&lt;p&gt;获取一个列表/元组/字符串/字典的长度。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-TypeScript&quot;&gt;{{ value|length }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 &lt;code&gt;value&lt;/code&gt; 是等于&lt;code&gt; [&amp;#039;a&amp;#039;,&amp;#039;b&amp;#039;,&amp;#039;c&amp;#039;] &lt;/code&gt;，那么以上代码将输出&lt;code&gt;3&lt;/code&gt;
如果 &lt;code&gt;value &lt;/code&gt;为 &lt;code&gt;None&lt;/code&gt; ，那么以上将返回&lt;code&gt;0&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;random&lt;/h3&gt;
&lt;p&gt;在被给的列表/字符串/元组中随机的选择一个值。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-TypeScript&quot;&gt;{{ value|random }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 &lt;code&gt;value&lt;/code&gt; 是等于 &lt;code&gt;[&amp;#039;a&amp;#039;,&amp;#039;b&amp;#039;,&amp;#039;c&amp;#039;]&lt;/code&gt; ，那么以上代码会在列表中随机选择一个&lt;/p&gt;
&lt;h3&gt;safe&lt;/h3&gt;
&lt;p&gt;标记一个字符串是安全的。也即会关掉这个字符串的自动转义。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;{{value|safe}}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 value 是一个不包含任何特殊字符的字符串，比如 &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; 这种，那么以上代码就会把字符串正常的输入。&lt;/p&gt;
&lt;p&gt;如果 value 是一串 html 代码，那么以上代码将会把这个 html 代码渲染到浏览器中。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# 数据
context = {
    &amp;quot;html&amp;quot;: &amp;quot;&amp;lt;h2&amp;gt;欢迎来到悦来集团!&amp;lt;/h2&amp;gt;&amp;quot;,
    }

# 只会原封不动的带标签渲染显示出来
{{html}}
&gt;&amp;lt;h2&amp;gt;欢迎来到悦来集团!&amp;lt;/h2&amp;gt;

# 会解析标签的作用，然后渲染显示
{{html|safe}}
&gt;欢迎来到悦来集团!&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;slice&lt;/h3&gt;
&lt;p&gt;类似于 Python 中的切片操作&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;{{ some_list|slice:&amp;quot;2:&amp;quot; }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将会给 some_list 从2开始做切片操作&lt;/p&gt;
&lt;h3&gt;stringtags&lt;/h3&gt;
&lt;p&gt;删除字符串中所有的 html 标签&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;{{ value|striptags }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 &lt;code&gt;value&lt;/code&gt; 是 &lt;code&gt;&amp;lt;strong&amp;gt;hello world&amp;lt;/strong&amp;gt;&lt;/code&gt; ，那么以上代码将会输出 &lt;code&gt;hello world&lt;/code&gt; 。&lt;/p&gt;
&lt;h3&gt;truncatechars&lt;/h3&gt;
&lt;p&gt;如果给定的字符串长度超过了过滤器指定的长度。那么就会进行切割，并且会拼接三个点来作为省略号。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;{{ value|truncatechars:5 }}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 &lt;code&gt;value&lt;/code&gt; 是等于 &lt;code&gt;abcdef&lt;/code&gt; ，那么输出的结果是 &lt;code&gt;abcd…&lt;/code&gt; ，只有四个字母是因为三个点也占了一个字符&lt;/p&gt;
&lt;h2&gt;模版结构&lt;/h2&gt;
&lt;h3&gt;include模版&lt;/h3&gt;
&lt;p&gt;有时候一些代码是在许多模版中都用到的。如果每次都重复的去拷贝代码那肯定不符合项目的规范。&lt;/p&gt;
&lt;p&gt;一般可以把这些重复性的代码抽取出来，就类似于Python中的函数一样，以后想要使用这些代码的时候，就通过 include 包含进来。这个标签就是 include 。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-HTML&quot;&gt;# header.html 
&amp;lt;p&amp;gt;我是header&amp;lt;/p&amp;gt;

# footer.html 
&amp;lt;p&amp;gt;我是footer&amp;lt;/p&amp;gt;

# main.html 
{% include &amp;#039;header.html&amp;#039; %}
&amp;lt;p&amp;gt;我是main内容&amp;lt;/p&amp;gt;
{% include &amp;#039;footer.html&amp;#039; %}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;include 标签寻找路径的方式。也是跟 render 渲染模板的函数是一样的。&lt;/p&gt;
&lt;p&gt;默认 include 标签包含模版，会自动的使用主模版中的上下文，也即可以自动的使用主模版中的变量。&lt;/p&gt;
&lt;h3&gt;模板继承&lt;/h3&gt;
&lt;p&gt;在前端页面开发中。有些代码是需要重复使用的。&lt;/p&gt;
&lt;p&gt;这种情况可以使用 include 标签来实现，也可以使用另外一个比较强大的方式来实现，那就是模版继承。&lt;/p&gt;
&lt;p&gt;模版继承类似于 Python 中的类，在父类中可以先定义好一些变量和方法，然后在子类中实现。&lt;/p&gt;
&lt;p&gt;模版继承也可以在父模版中先定义好一些子模版需要用到的代码，然后子模版直接继承就可以了。并且因为子模版肯定有自己的不同代码，因此可以在父模版中定义一个block接口，然后子模版再去实现。&lt;/p&gt;
&lt;p&gt;以下是父模版的代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-HTML&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, initial-scale=1&amp;quot;&amp;gt;
    &amp;lt;title&amp;gt;{% block title %}{% endblock %} - 陌上花&amp;lt;/title&amp;gt;
    {% block head %}{% endblock %}
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;hender&amp;gt;
      &amp;lt;ul&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;/&amp;quot;&amp;gt;首页&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;/&amp;quot;&amp;gt;留言&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
      &amp;lt;/ul&amp;gt;
    &amp;lt;/hender&amp;gt;

    {% block body %}{% endblock %}

    &amp;lt;footer&amp;gt;Copyright © Blog All Rights Reserved. 2016-&amp;lt;/footer&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个模版，取名叫做 &lt;code&gt;base.html&lt;/code&gt; ，定义好一个简单的 html 骨架。&lt;/p&gt;
&lt;p&gt;然后定义好 &lt;code&gt;block&lt;/code&gt; 接口，让子模版来根据具体需求来实现。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;block&lt;/code&gt; 接口的定义和模板标签一样，需要有起始标签&lt;code&gt;{% block 自定义名称 %}&lt;/code&gt;，就要有结束标签 &lt;code&gt;{% endblock %}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hotarticle.html&lt;/code&gt;文件的内容&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-HTML&quot;&gt;&amp;lt;div&amp;gt;
  &amp;lt;h2&amp;gt;热门文章&amp;lt;/h2&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;文章&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;文章&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;文章&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;文章&amp;lt;/li&amp;gt;
    {% for article in articles %}
    &amp;lt;li&amp;gt;{{article}}&amp;lt;/li&amp;gt;
    {% endfor%}
  &amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;子模板然后通过 extends 标签来实现，示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-HTML&quot;&gt;{% extends &amp;quot;cc_base.html&amp;quot; %}

{% block title %}首页{% endblock %}

{% block head %}
&amp;lt;style&amp;gt;
  body {background-color: pink;}
&amp;lt;/style&amp;gt;
{% endblock %}

{% block body %}
  {% include &amp;quot;hotarticle.html&amp;quot;%}
{% endblock%}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上代码保存后解析的代码会成这样，框起来的地方就是三个 &lt;code&gt;block&lt;/code&gt; 传入的数据&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://assets.moshanghua.net/images/2024/07/msh-3329-01.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;具体效果&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://assets.moshanghua.net/images/2024/07/msh-3329-02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;需要注意的是：extends标签必须放在模版的第一行。子模板中的代码必须放在block中，否则将不会被渲染。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果在某个 &lt;code&gt;block&lt;/code&gt; 中需要使用父模版的内容，那么可以使用 &lt;code&gt;{{block.super}} &lt;/code&gt;来继承。比如上例，&lt;code&gt;{%block title%}&lt;/code&gt; ，如果想要使用父模版的 &lt;code&gt;title &lt;/code&gt;，那么可以在子模版的 &lt;code&gt;title block&lt;/code&gt; 中使用 &lt;code&gt;{{ block.super }}&lt;/code&gt; 来实现。&lt;/p&gt;
&lt;p&gt;在定义 &lt;code&gt;block&lt;/code&gt; 的时候，除了在 &lt;code&gt;block&lt;/code&gt; 开始的地方定义这个 &lt;code&gt;block&lt;/code&gt; 的名字，还可以在 &lt;code&gt;block&lt;/code&gt; 结束的时候定义名字。比如 &lt;code&gt;{% block title %}{% endblock title %}&lt;/code&gt; 。这在大型模版中显得尤其有用，能让你快速的看到 block 包含在哪里。&lt;/p&gt;</content></entry><entry><title>Django 基础</title><link href="https://www.moshanghua.net/archives/django-%E5%9F%BA%E7%A1%80.html" /><id>https://www.moshanghua.net/archives/django-%E5%9F%BA%E7%A1%80.html</id><updated>2024-07-27T09:08:47.000Z</updated><summary></summary><content type="html">&lt;h2&gt;Django5 入门&lt;/h2&gt;
&lt;h3&gt;Django相关的网址&lt;/h3&gt;
&lt;p&gt;Github源代码：&lt;a href=&quot;https://github.com/django/django&quot;&gt;https://github.com/django/django&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Django官网：&lt;a href=&quot;https://www.djangoproject.com/&quot;&gt;https://www.djangoproject.com/&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;安装Django&lt;/h3&gt;
&lt;p&gt;通过 &lt;code&gt;pip install django&lt;/code&gt; 安装 &lt;code&gt;django&lt;/code&gt; ，本文以 &lt;code&gt;Django 5.0.3&lt;/code&gt; 版本进行记录。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;pip install django
#如需要指定版本用这个命令
pip install django==5.0.3
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;初始化 Django 项目&lt;/h3&gt;
&lt;p&gt;创建项目使用命令： &lt;code&gt;django-admin startproject [项目名称]&lt;/code&gt; 即可创建。 &lt;/p&gt;
&lt;p&gt;初始化一个新的 Django 项目，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;django-admin startproject startdjango
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建应用（app）：一个项目类似于是一个架子，但是真正起作用的还是 &lt;code&gt;app&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;在终端进入到项目所在的路径，然后执行 &lt;code&gt;python manage.py startapp [app名称]&lt;/code&gt; 创建一个app。&lt;/p&gt;
&lt;h3&gt;运行Django项目&lt;/h3&gt;
&lt;p&gt;进入项目，通过命令行的方式： &lt;code&gt;python manage.py runserver&lt;/code&gt; &lt;/p&gt;
&lt;p&gt;这样可以在本地访问项目网站，默认端口号是 &lt;code&gt;8000&lt;/code&gt; ，在浏览器中通过 &lt;code&gt;http://127.0.0.1:8000/&lt;/code&gt; 来访问&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;cd startdjango
python manage.py runserver&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果想要修改端口号，那么在运行的时候可以指定端口号，&lt;code&gt;python manage.py runserver 9000&lt;/code&gt;这样就可以通过9000端口来访问&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;python manage.py runserver 9000&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;项目结构介绍&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;manage.py&lt;/code&gt;：以后和项目交互基本上都是基于这个文件。一般都是在终端输入&lt;code&gt;python manage.py [子命令]&lt;/code&gt;。可以输入&lt;code&gt;python manage.py help&lt;/code&gt;看下能做什么事情。除非你知道你自己在做什么，一般情况下不应该编辑这个文件。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;settings.py&lt;/code&gt;：本项目的设置项，以后所有和项目相关的配置都是放在这个里面。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;urls.py&lt;/code&gt;：这个文件是用来配置URL路由的。比如访问&lt;code&gt;http://127.0.0.1/news/&lt;/code&gt;是访问新闻列表页，这些东西就需要在这个文件中完成。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wsgi.py&lt;/code&gt;：项目与WSGI工协议兼容的web服务器入口，部署的时候需要用到的，一般情况下也是不需要修改的。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;project和app的关系&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;app&lt;/code&gt;是&lt;code&gt;django&lt;/code&gt;项目的组成部分。一个&lt;code&gt;app&lt;/code&gt;代表项目中的一个模块，所有&lt;code&gt;URL&lt;/code&gt;请求的响应都是由&lt;code&gt;app&lt;/code&gt;来处理。比如豆瓣，里面有图书，电影，音乐，同城等许许多多的模块，如果站在&lt;code&gt;django&lt;/code&gt;的角度来看，图书，电影这些模块就是&lt;code&gt;app&lt;/code&gt;，图书，电影这些&lt;code&gt;app&lt;/code&gt;共同组成豆瓣这个项目。因此这里要有一个概念，&lt;code&gt;django&lt;/code&gt;项目由许多 &lt;code&gt;app&lt;/code&gt;组成，一个&lt;code&gt;app&lt;/code&gt;可以被用到其他项目，&lt;code&gt;django&lt;/code&gt;也能拥有不同的&lt;code&gt;app&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;通过命令：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Markdown&quot;&gt;python manage.py startapp book&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;URL分发器&lt;/h2&gt;
&lt;h3&gt;一、视图：&lt;/h3&gt;
&lt;p&gt;视图一般都写在 &lt;code&gt;app&lt;/code&gt; 的 &lt;code&gt;views.py&lt;/code&gt; 中。并且视图的第一个参数永远都是 &lt;code&gt;request&lt;/code&gt; （一个&lt;code&gt;HttpRequest&lt;/code&gt;）对象。这个对象存储了请求过来的所有信息，包括携带的参数以及一些头部信息等。在视图中，一般是完成逻辑相关的操作。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;def book_list(request):     
    return HttpResponse(&amp;quot;书籍列表！&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;视图可以是函数，也可以是类。&lt;/p&gt;
&lt;h3&gt;二、URL映射：&lt;/h3&gt;
&lt;p&gt;视图写完后，要与URL进行映射，即用户在浏览器中输入什么 &lt;code&gt;url&lt;/code&gt; 的时候可以请求到这个视图函数。&lt;/p&gt;
&lt;p&gt;在用户输入了某个 &lt;code&gt;url &lt;/code&gt;，请求到我们的网站的时候， &lt;code&gt;django&lt;/code&gt; 会从项目的 &lt;code&gt;urls.py&lt;/code&gt; 文件中寻找对应的视图。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;urls.py&lt;/code&gt; 文件中有一个 &lt;code&gt;urlpatterns&lt;/code&gt; 变量，以后 &lt;code&gt;django&lt;/code&gt; 就会从这个变量中读取所有的匹配规则。&lt;/p&gt;
&lt;p&gt;匹配规则需要使用 &lt;code&gt;django.urls.path&lt;/code&gt; 函数进行包裹，这个函数会根据传入的参数返回&lt;code&gt;URLPattern&lt;/code&gt; 或者是 &lt;code&gt;URLResolver&lt;/code&gt; 的对象。示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;from django.contrib import admin 
from django.urls import path 
from book import views

urlpatterns = [
    path(&amp;#039;admin/&amp;#039;, admin.site.urls),     
    path(&amp;#039;book/&amp;#039;,views.book_list) 
]&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;URL中添加参数：&lt;/h4&gt;
&lt;p&gt;有时候， url 中包含了一些参数需要动态调整。&lt;/p&gt;
&lt;p&gt;比如博客某篇文章的详情页的url，是&lt;code&gt;https://moshanghua.net/details/3276&lt;/code&gt; 后面的 &lt;code&gt;3276&lt;/code&gt; 就是这篇文章的 &lt;code&gt;id&lt;/code&gt; ，那么文章详情页面的&lt;code&gt;url&lt;/code&gt;就可以写成 &lt;code&gt;https://moshanghua.net/details/&amp;lt;id&amp;gt; &lt;/code&gt;，其中id就是文章的id。&lt;/p&gt;
&lt;p&gt;在django 中实现这种需求。可以在 &lt;code&gt;path&lt;/code&gt; 函数中，使用尖括号的形式来定义一个参数。比如我现在想要获取一本书籍的详细信息，那么应该在 url 中指定这个参数。示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Markdown&quot;&gt;from django.contrib import admin 
from django.urls import path 
from book import views

urlpatterns = [
    path(&amp;#039;admin/&amp;#039;, admin.site.urls),     
    path(&amp;#039;book/&amp;#039;,views.book_list),     
    path(&amp;#039;book/&amp;lt;book_id&amp;gt;&amp;#039;,views.book_detail) 
]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而 &lt;code&gt;views.py&lt;/code&gt; 中的代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;def book_detail(request, book_id):
    return HttpResponse(f&amp;quot;您查询的图书 id 是: {book_id}&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在指定参数时，也可以指定参数的类型，比如以上 &lt;code&gt;book_id&lt;/code&gt; 为整形，那么在定义 &lt;code&gt;URL&lt;/code&gt; 的时候，就可以使用以下语法实现：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;...
path(&amp;#039;book/&amp;lt;int:book_id&amp;gt;&amp;#039;,views.book_detail) 
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;除了 &lt;code&gt;int&lt;/code&gt; 类型， django 的 &lt;code&gt;path&lt;/code&gt; 部分还支持 &lt;code&gt;str&lt;/code&gt; 、 &lt;code&gt;slug&lt;/code&gt; 、 &lt;code&gt;uuid&lt;/code&gt; 、 &lt;code&gt;path&lt;/code&gt; 类型。&lt;/p&gt;
&lt;p&gt;也可以通过&lt;strong&gt;查询字符串&lt;/strong&gt;的方式传递一个参数过去。示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;urlpatterns = [
    path(&amp;#039;admin/&amp;#039;, admin.site.urls),     
    path(&amp;#039;book/&amp;#039;,views.book_list),     
    path(&amp;#039;book/detail&amp;#039;,views.book_detail) 
]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 &lt;code&gt;views.py&lt;/code&gt; 中的代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;def book_detail(request):
    book_id = request.GET.get(&amp;quot;id&amp;quot;)
    name = request.GET.get(&amp;quot;name&amp;quot;)
    return HttpResponse(f&amp;quot;您查询的图书 id 是: {book_id}，图书的名称是:《{name}》&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在访问的时候就是通过 &lt;code&gt;/book/detail?id=1&amp;amp;name=xx&lt;/code&gt; 即可将参数传递过去。&lt;/p&gt;
&lt;h4&gt;path函数详解&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;path&lt;/code&gt; 函数的定义为： &lt;code&gt;path(route,view,name=None,kwargs=None)&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;route&lt;/code&gt; 参数： &lt;code&gt;url&lt;/code&gt; 的匹配规则。&lt;/p&gt;
&lt;p&gt;这个参数中可以指定 &lt;code&gt;url&lt;/code&gt; 中需要传递的参数，比如在访问文章详情页的时候，可以传递一个&lt;code&gt; id &lt;/code&gt;。传递参数是通过 &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt; 尖括号来进行指定的。并且在传递参数的时候，可以指定这个参数的数据类型，比如文章的 &lt;code&gt;id&lt;/code&gt; 都是 &lt;code&gt;int&lt;/code&gt; 类型，那么可以这样写 &lt;code&gt;&amp;lt;int:id&amp;gt;&lt;/code&gt; ，以后匹配的时候，就只会匹配到  &lt;code&gt;id&lt;/code&gt;  为  &lt;code&gt;int&lt;/code&gt; 类型的 &lt;code&gt;url&lt;/code&gt;，而不会匹配其他的 &lt;code&gt;url&lt;/code&gt; ，并且在视图函数中获取这个参数的时候，就已经被转换成一个 1.&lt;code&gt;int&lt;/code&gt; 类型了。其中还有几种常用的类型：&lt;/p&gt;
&lt;p&gt;2.&lt;code&gt;str&lt;/code&gt; ：非空的字符串类型。默认的转换器。但是不能包含斜杠。&lt;/p&gt;
&lt;p&gt;3.&lt;code&gt;int&lt;/code&gt; ：匹配任意的零或者正数的整形。到视图函数中就是一个&lt;code&gt;int&lt;/code&gt;类型。&lt;/p&gt;
&lt;p&gt;4.&lt;code&gt;slug&lt;/code&gt; ：由英文中的横杠 &lt;code&gt;-&lt;/code&gt; 或者下划线 &lt;code&gt;_&lt;/code&gt; 连接英文字符或者数字而成的字符串。&lt;/p&gt;
&lt;p&gt;5.&lt;code&gt;uuid&lt;/code&gt; ：匹配 &lt;code&gt;uuid&lt;/code&gt; 字符串。&lt;/p&gt;
&lt;p&gt;6.&lt;code&gt;path&lt;/code&gt; ：匹配非空的英文字符串，可以包含斜杠 &lt;code&gt;/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;view&lt;/code&gt; 参数：可以为一个视图函数或者是 &lt;code&gt;类视图.as_view()&lt;/code&gt; 或者是 &lt;code&gt;django.urls.include()&lt;/code&gt; 函数的返回值。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;name&lt;/code&gt; 参数：这个参数是给这个 &lt;code&gt;url &lt;/code&gt;取个名字的，在项目比较大， url 比较多的时候用处很大。&lt;/p&gt;
&lt;h4&gt;URL中包含另外一个urls模块（路由模块化）：&lt;/h4&gt;
&lt;p&gt;在项目中，不可能只有一个 &lt;code&gt;app&lt;/code&gt; ，如果把所有的 &lt;code&gt;app&lt;/code&gt; 的 &lt;code&gt;views&lt;/code&gt; 中的视图都放在 &lt;code&gt;urls.py&lt;/code&gt; 中进行映射，肯定会让代码显得非常乱。&lt;/p&gt;
&lt;p&gt;因此 django 给提供了一个方法，可以在 &lt;code&gt;app&lt;/code&gt; 内部包含自己的 &lt;code&gt;url&lt;/code&gt; 匹配规则，而在项目的 &lt;code&gt;urls.py&lt;/code&gt; 中再统一包含这个 &lt;code&gt;app&lt;/code&gt; 的 &lt;code&gt;urls &lt;/code&gt;。使用这个技术需要借助 include 函数。示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# startdjango/urls.py文件：
from django.contrib import admin 
from django.urls import path,include

urlpatterns = [
    path(&amp;#039;admin/&amp;#039;, admin.site.urls),     
    path(&amp;#039;book/&amp;#039;,include(&amp;quot;book.urls&amp;quot;)) 
]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 &lt;code&gt;urls.py&lt;/code&gt; 文件中把所有的和 &lt;code&gt;book&lt;/code&gt; 这个 &lt;code&gt;app&lt;/code&gt; 相关的 &lt;code&gt;url&lt;/code&gt; 都移动到 &lt;code&gt;app/urls.py&lt;/code&gt; 中了，然后在&lt;code&gt;startdjango/urls.py&lt;/code&gt; 中，通过 &lt;code&gt;include&lt;/code&gt; 函数包含 &lt;code&gt;book.urls&lt;/code&gt; ，以后在请求&lt;code&gt; book&lt;/code&gt; 相关的&lt;code&gt;url&lt;/code&gt;的时候都需要加一个 &lt;code&gt;book&lt;/code&gt; 的前缀。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# book/urls.py文件：
from django.urls import path 
from . import views

urlpatterns = [
    path(&amp;#039;list/&amp;#039;,views.book_list),     
    path(&amp;#039;detail/&amp;lt;book_id&amp;gt;/&amp;#039;,views.book_detail) 
]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;访问书的列表的 &lt;code&gt;url&lt;/code&gt; 的时候，就通过 &lt;code&gt;/book/list/&lt;/code&gt; 来访问，访问书籍详情页面的 url 的时候就通过&lt;code&gt;book/detail/&amp;lt;id&amp;gt;&lt;/code&gt; 来访问。为了避免多个模块的 &lt;code&gt;urls.py&lt;/code&gt; 中包含同名的&lt;code&gt; url&lt;/code&gt; ，可以指定一个应用命名空间：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# book/urls.py文件：
from django.urls import path 
from . import views

# 指定应用命名空间
app_name=&amp;#039;book&amp;#039;

urlpatterns = [
    path(&amp;#039;list/&amp;#039;,views.book_list),     
    path(&amp;#039;detail/&amp;lt;book_id&amp;gt;/&amp;#039;,views.book_detail) 
]&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;url反转（路由反转）&lt;/h4&gt;
&lt;p&gt;一般是通过&lt;code&gt;url&lt;/code&gt;来访问视图函数。有时候知道这个视图函数，但是想反转回它的&lt;code&gt;url&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这时候就可以通过 &lt;code&gt;reverse&lt;/code&gt; 来实现。示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;print(reverse(&amp;quot;list&amp;quot;)) 

&gt; /book/list/&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果有应用命名空间或者有实例命名空间，那么应该在反转的时候加上命名空间。示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;print（reverse(&amp;#039;book:list&amp;#039;)） 

&gt; /book/list/&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果这个&lt;code&gt;url&lt;/code&gt;中需要传递参数，那么可以通过 &lt;code&gt;kwargs&lt;/code&gt; 来传递参数。示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;print(reverse(&amp;quot;book:detail&amp;quot;,kwargs={&amp;quot;book_id&amp;quot;:1}))

&gt; /book/detail/1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;因为 django 中的 &lt;code&gt;reverse&lt;/code&gt; 反转 &lt;code&gt;url&lt;/code&gt; 的时候不区分 &lt;code&gt;GET&lt;/code&gt; 请求和 &lt;code&gt;POST&lt;/code&gt; 请求，因此不能在反转的时候添加查询字符串的参数。如果想要添加查询字符串的参数，只能手动的添加。示例代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;login_url = reverse(&amp;#039;login&amp;#039;) + &amp;quot;?next=/&amp;quot;

print(login_url)&lt;/code&gt;&lt;/pre&gt;</content></entry><entry><title>用 Python 操作 Excel 文档（基础）</title><link href="https://www.moshanghua.net/archives/%E7%94%A8-python-%E6%93%8D%E4%BD%9C-excel-%E6%96%87%E6%A1%A3-%E5%9F%BA%E7%A1%80.html" /><id>https://www.moshanghua.net/archives/%E7%94%A8-python-%E6%93%8D%E4%BD%9C-excel-%E6%96%87%E6%A1%A3-%E5%9F%BA%E7%A1%80.html</id><updated>2024-06-30T14:48:26.000Z</updated><summary></summary><content type="html">&lt;h2&gt;Excel表格的基本结构&lt;/h2&gt;
&lt;p&gt;一个Excel表格文件，又叫做一个&lt;strong&gt;工作簿（Workbook）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;一个工作簿中包含一个或多个&lt;strong&gt;工作表（Worksheet）&lt;/strong&gt;。  &lt;/p&gt;
&lt;p&gt;在工作薄页面的左下方可以进行工作表的切换和增删。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/06/msh-3297-01.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;一个工作表由&lt;strong&gt;单元格（Cell）&lt;/strong&gt;组成。Excel的数据存储在单元格中。  &lt;/p&gt;
&lt;p&gt;我们可以通过&lt;strong&gt;列号（Column）&lt;/strong&gt;和&lt;strong&gt;行号（Row）&lt;/strong&gt;对单元格进行定位。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/06/msh-3297-02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;行号默认从数字1开始，并依次递增。  &lt;/p&gt;
&lt;p&gt;列号默认从字母A开始，依次递增。超过字母Z后，以AA，AB的方式继续计数。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/06/msh-3297-03.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;至此，就是Excel表格的基本结构，总结如图所示。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/06/msh-3297-04.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;openpyxl 模块&lt;/h2&gt;
&lt;p&gt;要使用Python对Excel表格进行读取，我们需要安装一个用于读取数据的工具 &lt;code&gt;openpyxl&lt;/code&gt; 。openpyxl 是一个用于读、写Excel文件的开源模块。&lt;/p&gt;
&lt;h2&gt;Excel表格读取&lt;/h2&gt;
&lt;h3&gt;读取工作簿&lt;/h3&gt;
&lt;p&gt;读取指定路径的工作簿需要使用函数：&lt;code&gt;openpyxl.load_workbook()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;openpyxl.load_workbook()函数读取成功后，会返回一个工作簿对象，本例中将这个对象赋值给了变量wb。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 导入openpyxl模块
import openpyxl
#读取工作目录里名为&amp;quot;2019年1月销售订单.xlsx&amp;quot;的工作簿并赋值给变量wb
wb = openpyxl.load_workbook(&amp;quot;2019年1月销售订单.xlsx&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;读取指定工作表&lt;/h3&gt;
&lt;p&gt;如果事先不知道工作簿内有哪些工作表，可以通过访问工作簿的 &lt;code&gt;.sheetnames&lt;/code&gt;  属性来获取一个包含所有工作表名称的列表。  &lt;/p&gt;
&lt;p&gt;具体操作为在变量wb之后添加代码 &lt;code&gt;.sheetnames&lt;/code&gt; 。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;import openpyxl
wb = openpyxl.load_workbook(&amp;quot;2019年1月销售订单.xlsx&amp;quot;)

# 使用print输出工作簿中所有的工作表名称
print(wb.sheetnames) # [&amp;#039;销售商品&amp;#039;, &amp;#039;销售订单数据&amp;#039;]

# 通过工作簿对象wb获取名为“销售商品”的工作表对象，
orderSheet = wb[&amp;quot;销售商品&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;读取指定单元格&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/06/msh-3297-05.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;要获取工作表中指定的单元格对象，我们可以通过在中括号 &lt;code&gt;[ ]&lt;/code&gt; 内填入&lt;code&gt;列号和行号&lt;/code&gt;的方式去获取。&lt;/p&gt;
&lt;p&gt;单元格对象除了包含具体的值，还包含相关的函数和属性。 &lt;/p&gt;
&lt;p&gt;要访问单元格里的值，可以在单元格对象后加一个  &lt;code&gt;.value&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;import openpyxl
wb = openpyxl.load_workbook(&amp;quot;sample.xlsx&amp;quot;)
print(wb.sheetnames) # [&amp;#039;sheet1&amp;#039;, &amp;#039;sheet2&amp;#039;]
orderSheet = wb[&amp;quot;销售商品&amp;quot;]

# 使用print输出 orderSheet 的C5单元格对象
print (orderSheet[&amp;quot;C5&amp;quot;]) # &amp;lt; Cell &amp;#039;销售商品&amp;#039;.C5 &amp;gt;

# 使用 orderSheet[&amp;quot;C5&amp;quot;].value 输出orderSheet的C5单元格的值
print(orderSheet[&amp;quot;C5&amp;quot;].value)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;若单元格中包含&lt;strong&gt;公式&lt;/strong&gt;，现有方式读取出的值是公式本身。  &lt;/p&gt;
&lt;p&gt;若需要读取公式计算后的值，要在读取工作簿的代码部分，传入一个参数： &lt;code&gt;data_only=True&lt;/code&gt; ，便可以得出公式计算后的值了。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 导入openpyxl模块
import openpyxl
#  原打开方式，直接读取公式本身
wb = openpyxl.load_workbook(&amp;quot;2019年1月销售订单.xlsx&amp;quot;)
orderSheet = wb[&amp;quot;销售订单数据&amp;quot;]

# 输出公式本身
print(orderSheet[&amp;quot;I3&amp;quot;].value)

#  添加data_only=True打开工作簿，获取公式计算后的值
wb2 = openpyxl.load_workbook(&amp;quot;2019年1月销售订单.xlsx&amp;quot;, data_only=True)
orderSheet2 = wb2[&amp;quot;销售订单数据&amp;quot;]

# 输出公式计算后的值
print(orderSheet2[&amp;quot;I3&amp;quot;].value)&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;工作表行数据的遍历&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/06/msh-3297-06.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;要对整个工作表的每一行数据进行浏览查询，可以使用for循环对工作表对象的行属性（rows）进行遍历。具体代码为 &lt;code&gt;for rowData in orderSheet.rows&lt;/code&gt; &lt;/p&gt;
&lt;p&gt;这样程序就会以从上到下的顺序，逐个获取到“销售订单数据”工作表内的每一行数据，读取出的每一行数据是由单元格对象组成的元组。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;import openpyxl

wb = openpyxl.load_workbook(&amp;quot;2019年1月销售订单.xlsx&amp;quot;, data_only=True)
orderSheet = wb[&amp;quot;销售订单数据&amp;quot;]

#  遍历工作表的所有行数据
for rowData in orderSheet.rows:
    # 输出行数据
    print(rowData)
    # (&amp;lt;Cell &amp;#039;销售订单数据&amp;#039;.A1&amp;gt;, &amp;lt;Cell &amp;#039;销售订单数据&amp;#039;.B1&amp;gt;, &amp;lt;Cell &amp;#039;销售订单数据&amp;#039;.C1&amp;gt;, &amp;lt;Cell &amp;#039;销售订单数据&amp;#039;.D1&amp;gt;, &amp;lt;Cell &amp;#039;销售订单数据&amp;#039;.E1&amp;gt;, &amp;lt;Cell &amp;#039;销售订单数据&amp;#039;.F1&amp;gt;, &amp;lt;Cell &amp;#039;销售订单数据&amp;#039;.G1&amp;gt;, &amp;lt;Cell &amp;#039;销售订单数据&amp;#039;.H1&amp;gt;, &amp;lt;Cell &amp;#039;销售订单数据&amp;#039;.I1&amp;gt;, &amp;lt;Cell &amp;#039;销售订单数据&amp;#039;.J1&amp;gt;)
    # 通过索引2获取第3列数据，也就是商品名
    productName = rowData[2].value
    # 输出商品名
    print(productName)&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;列号转数字&lt;/h3&gt;
&lt;p&gt;使用函数&lt;code&gt;openpyxl.utils.cell.column_index_from_string()&lt;/code&gt;来获取工作表列号对应的数字。&lt;/p&gt;
&lt;p&gt;遍历行数据时，如果要定位的列数字比较大，比如订单的总价在第 Z 列，列号太大不太容易数的时候就可以使用函数：&lt;code&gt;openpyxl.utils.cell.column_index_from_string()&lt;/code&gt;，来获取列号对应的数字.&lt;/p&gt;
&lt;p&gt;比如传入参数“I”就会获取到数字9，表示“I”列是第9列。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这个数字减一即可得到对应的索引。因为索引是从0开始的，所以需要减一&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;import openpyxl

wb = openpyxl.load_workbook(&amp;quot;./doc/2019年1月销售订单.xlsx&amp;quot;, data_only=True)
orderSheet = wb[&amp;quot;销售订单数据&amp;quot;]

for rowData in orderSheet.rows:
    productName = rowData[2].value
    # print(productName)
    priceIndex = openpyxl.utils.cell.column_index_from_string(&amp;quot;I&amp;quot;) - 1
    # print(priceIndex)
    price = rowData[priceIndex].value
    print(price)
# 总价
# 5
# 20
# 40
# ...&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Excel表格写入&lt;/h2&gt;
&lt;h3&gt;创建工作簿&lt;/h3&gt;
&lt;p&gt;使用&lt;code&gt;openpyxl.Workbook()&lt;/code&gt;函数即可创建一个新工作簿。  &lt;/p&gt;
&lt;p&gt;创建成功后，新创建的工作簿对象会被返回。为了方便之后对这个工作簿进行操作，将这个对象赋值给一个变量newWb。&lt;/p&gt;
&lt;p&gt;可以访问&lt;code&gt;sheetnames&lt;/code&gt;字段来获取工作簿内所有的工作表名称，使用&lt;code&gt;openpyxl.Workbook()&lt;/code&gt;创建的工作簿里面，都有一张默认的工作表，名称为Sheet。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;import openpyxl

# 创建一个新工作簿并赋值给变量newWb
newWb = openpyxl.Workbook()

# 输出新工作簿内所有的工作表名称
print(newWb.sheetnames) # [&amp;#039;Sheet&amp;#039;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;修改工作表名称&lt;/h3&gt;
&lt;p&gt;先通过变量newWb使用&lt;strong&gt;中括号 + 工作表名称&lt;/strong&gt;获取这个工作表对象，然后把这个对象赋值给变量&lt;strong&gt;aSheet&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;通过对工作表对象的 &lt;code&gt;.title&lt;/code&gt;属性进行赋值，即可修改工作表的名称。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;import openpyxl

newWb = openpyxl.Workbook()

# 将名为Sheet的默认工作表赋值给aSheet变量
aSheet = newWb[&amp;quot;Sheet&amp;quot;]
# 将aSheet工作表名称修改为“A平台”
aSheet.title = &amp;quot;A平台&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;创建工作表&lt;/h3&gt;
&lt;p&gt;通过工作簿对象使用&lt;code&gt;create_sheet()&lt;/code&gt;函数可以创建一个名称为Sheet的工作表。  &lt;/p&gt;
&lt;p&gt;若名为Sheet工作表已经存在，则会在Sheet后依次添加数字，比如&lt;strong&gt;Sheet1&lt;/strong&gt;，&lt;strong&gt;Sheet2&lt;/strong&gt;。  &lt;/p&gt;
&lt;p&gt;在创建时如需要指定工作表名称，可以将需要指定的工作表名称作为参数传入create_sheet()函数。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;import openpyxl

newWb = openpyxl.Workbook()

# 不指定名称创建工作表
newWb.create_sheet()

# 指定创建的新工作表名称为&amp;quot;陌上花&amp;quot;
newWb.create_sheet(&amp;quot;陌上花&amp;quot;)

# 输出所有的工作表名称以检查是否创建成功
print(newWb.sheetnames) # [&amp;#039;Sheet&amp;#039;, &amp;#039;Sheet1&amp;#039;, &amp;#039;陌上花&amp;#039;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;新创建的工作表对象会在函数调用后返回，在这里也可以直接分别赋值给变量bSheet和cSheet，方便之后操作使用&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 创建 B平台 的工作表并赋值给变量bSheet
bSheet = newWb.create_sheet(&amp;quot;B平台&amp;quot;)

# 创建 C平台 的工作表并赋值给变量cSheet
cSheet = newWb.create_sheet(&amp;quot;C平台&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Excel设置单元格的值&lt;/h3&gt;
&lt;p&gt;每一个工作表都有一个表头，分别是“&lt;strong&gt;商品名&lt;/strong&gt;”、“&lt;strong&gt;月份&lt;/strong&gt;”和“&lt;strong&gt;销售额&lt;/strong&gt;”。  &lt;/p&gt;
&lt;p&gt;本质上，每一个表头也就是一个一个单元格组成的。要修改每个工作表的表头，就需要用到“&lt;strong&gt;设置单元格的值&lt;/strong&gt;”这个知识点。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/06/msh-3297-07.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;可以通过“&lt;code&gt;工作表对象[&amp;quot;列号行号&amp;quot;].value&lt;/code&gt;”这种方式来获取指定的单元格的值。  &lt;/p&gt;
&lt;p&gt;而直接把要设置的值赋值给.value属性，就可以设置或修改这个单元格的值了。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# 设置aSheet里A1单元格的值为“编号”
aSheet[&amp;quot;A1&amp;quot;].value = &amp;quot;编号&amp;quot;
aSheet[&amp;quot;B1&amp;quot;].value = &amp;quot;月份&amp;quot;
aSheet[&amp;quot;C1&amp;quot;].value = &amp;quot;销售额&amp;quot;

# 输出A1单元格的值以检查是否设置成功
print(aSheet[&amp;quot;A1&amp;quot;].value)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以使用for循环对工作簿对象内的&lt;code&gt;worksheets&lt;/code&gt;属性进行遍历，以达到逐个访问所有&lt;code&gt;工作表&lt;/code&gt;并设置表头的目的&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# 使用for循环遍历工作簿对象的worksheets属性
for sheet in newWb.worksheets:
    # 给每一个工作表设置表头
    sheet[&amp;quot;A1&amp;quot;].value = &amp;quot;商品名&amp;quot;
    sheet[&amp;quot;B1&amp;quot;].value = &amp;quot;月份&amp;quot;
    sheet[&amp;quot;C1&amp;quot;].value = &amp;quot;销售额&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;保存工作簿文件&lt;/h3&gt;
&lt;p&gt;通过工作簿对象使用&lt;code&gt;save()&lt;/code&gt; 函数，将文件保存路径作为参数，即可将工作簿保存到指定的文件路径。 一般将工作簿存储成后缀名为&lt;code&gt;.xlsx&lt;/code&gt;的文件。  &lt;/p&gt;
&lt;p&gt;如果指定路径的文件已经存在，使用&lt;code&gt;save()&lt;/code&gt;函数会&lt;strong&gt;覆盖原有文件&lt;/strong&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;# 将工作簿保存到指定路径
newWb.save(&amp;quot;/Users/chixm/data/汇总.xlsx&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Excel添加行数据&lt;/h3&gt;
&lt;p&gt;想要添加一整行数据可以通过工作表对象使用&lt;code&gt;append()&lt;/code&gt;函数。  &lt;/p&gt;
&lt;p&gt;&lt;code&gt;append()&lt;/code&gt;函数会在现有工作表内数据的最后一行之后再添加一行数据。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;append()&lt;/code&gt;函数只有一个参数，该参数是一个列表或者元组。  &lt;/p&gt;
&lt;p&gt;使用函数后，列表或元组内的数据会按照顺序逐个添加到目标行中。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;import openpyxl

# 读取工作簿和工作表
wb = openpyxl.load_workbook(&amp;quot;怪物数值.xlsx&amp;quot;)
sheet = wb[&amp;quot;东胜神州&amp;quot;]

# 通过append()函数传入一个元组添加一行数据
sheet.append((&amp;quot;D10002&amp;quot;, &amp;quot;白鼠&amp;quot;, 600))

# 保存工作簿到原路径
wb.save(&amp;quot;怪物数值.xlsx&amp;quot;)&lt;/code&gt;&lt;/pre&gt;</content></entry><entry><title>管理 Python 环境</title><link href="https://www.moshanghua.net/archives/%E7%AE%A1%E7%90%86-python-%E7%8E%AF%E5%A2%83.html" /><id>https://www.moshanghua.net/archives/%E7%AE%A1%E7%90%86-python-%E7%8E%AF%E5%A2%83.html</id><updated>2024-06-22T14:07:00.000Z</updated><summary></summary><content type="html">&lt;h2&gt;pyenv 来管理 Python 版本&lt;/h2&gt;
&lt;p&gt;pyenv 是一个强大 Python 包管理工具，可以灵活地切换各种 Python 版本，使用 pyenv 来管理我们的 Python 版本，优雅高效且不会破坏掉系统自带的 Python 环境：&lt;/p&gt;
&lt;h3&gt;macOS 安装 pyenv&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;➜ brew install pyenv&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;接着为 pyenv 配置 shell 环境，提高工作效率，可自动联想 Tab 补全我们本地安装的 Python 版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;echo &amp;#039;eval &amp;quot;$(pyenv init -)&amp;quot;&amp;#039; &amp;gt;&amp;gt; ~/.zshrc&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;pyenv 安装 Python&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 查看已经安装的Python版本
➜ pyenv versions

# 查看当前的 Python 版本
➜ pyenv version

# 查看可安装的版本
➜ pyenv install -l

# 安装与卸载 pypy3.8-7.3.11
➜ pyenv install pypy3.8-7.3.11
➜ pyenv uninstall pypy3.8-7.3.11&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;版本切换确实很方便，所安装的版本都在 &lt;code&gt;~/.pyenv/versions&lt;/code&gt; 目录下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# global 全局设置 一般不建议改变全局设置
➜ pyenv global &amp;lt;python版本&amp;gt;

# shell 会话设置 只影响当前的shell会话
➜ pyenv shell &amp;lt;python版本&amp;gt;
# 取消 shell 会话的设置
➜ pyenv shell --unset

# local 本地设置 只影响所在文件夹
➜ pyenv local &amp;lt;python版本&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;pyenv 的 global、local、shell 的优先级关系是：shell &amp;gt; local &amp;gt; global&lt;/p&gt;
&lt;h2&gt;Python 的 pip 管理工具&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pipenv&lt;/code&gt; 是一个强大的工具，用于简化 Python 项目中的依赖管理和虚拟环境管理。以下是一些常见的 &lt;code&gt;pipenv&lt;/code&gt; 用法示例：&lt;/p&gt;
&lt;p&gt;更多关于  &lt;code&gt;pipenv&lt;/code&gt;  的信息，可以查看它的官方文档：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://pipenv.pypa.io/en/latest/&quot;&gt;pipenv 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;安装 &lt;code&gt;pipenv&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;首先，你需要确保已经安装了 &lt;code&gt;pipenv&lt;/code&gt;。你可以通过以下命令安装它：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;pip install pipenv&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;创建和管理虚拟环境&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;创建一个新项目并初始化 **&lt;/strong&gt;&lt;code&gt;pipenv&lt;/code&gt;&lt;strong&gt;** 环境&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;mkdir my_project
cd my_project
pipenv install&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;安装一个新的包&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pipenv&lt;/code&gt; 会自动创建一个虚拟环境（如果还没有创建），并将包安装到该虚拟环境中。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;pipenv install requests&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;安装一个开发依赖包&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;开发依赖包只在开发环境中需要，比如测试工具。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;pipenv install --dev pytest&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;卸载一个包&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;pipenv uninstall requests&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;激活虚拟环境&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;激活虚拟环境后，你可以在其中运行 Python 命令和脚本。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;pipenv shell&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;要退出虚拟环境，使用 &lt;code&gt;exit&lt;/code&gt; 命令。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;运行脚本而不激活虚拟环境&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;如果你不想手动激活虚拟环境，可以使用以下命令直接在虚拟环境中运行脚本。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;pipenv run python your_script.py&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;管理依赖文件&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;生成 &lt;code&gt;Pipfile.lock&lt;/code&gt;&lt;/strong&gt;：
&lt;code&gt;Pipfile.lock&lt;/code&gt; 文件记录了所有包的精确版本，保证项目的一致性。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;pipenv lock&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;安装 &lt;code&gt;Pipfile&lt;/code&gt; 中的所有依赖&lt;/strong&gt;：
如果你克隆了一个包含 &lt;code&gt;Pipfile&lt;/code&gt; 的项目，可以使用以下命令安装所有依赖。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;pipenv install&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;检查包的安全性&lt;/strong&gt;：
&lt;code&gt;pipenv&lt;/code&gt; 提供了一个方便的命令来检查已安装的包是否有已知的安全漏洞。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;pipenv check&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;其他有用的命令&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;查看已安装包列表&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;pipenv graph&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;更新包&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;pipenv update requests&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或更新所有包：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;pipenv update&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;清理未使用的包&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;pipenv clean&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;查看虚拟环境路径&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;pipenv --venv&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;查看 Python 解释器路径&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;pipenv --py&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些命令和用法应该可以帮助你更有效地管理 Python 项目的依赖和虚拟环境。如果你需要更多信息和详细的用法，可以查看 &lt;a href=&quot;https://pipenv.pypa.io/en/latest/&quot;&gt;pipenv 的官方文档&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 安装 pipenv
pip install pipenv

mkdir my_project

cd my_project

# 初始化 pipenv 环境
pipenv install

# 安装模块 openpyxl
pipenv install openpyxl

# 激活虚拟环境，运行python，使用 exit 命令退出环境
pipenv shell

# 直接在虚拟环境中运行脚本
pipenv run python your_script.py
&lt;/code&gt;&lt;/pre&gt;</content></entry><entry><title>【深谷Shintani】画了天依～</title><link href="https://www.moshanghua.net/archives/%E9%A2%84%E7%95%99-7.html" /><id>https://www.moshanghua.net/archives/%E9%A2%84%E7%95%99-7.html</id><updated>2024-06-17T14:06:29.000Z</updated><summary></summary><content type="html">&lt;p&gt;分享图片
&lt;img src=&quot;http://assets.moshanghua.net/tianyi/Shintani/cca555ae2b20d558be6e9d8be3a821fc3557283.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;画师id&lt;/h2&gt;
&lt;p&gt;感谢深谷老师的画作~ 并允许使用~
B站id：&lt;a href=&quot;https://space.bilibili.com/3557283&quot;&gt;@深谷Shintani&lt;/a&gt;
微博id：&lt;a href=&quot;https://weibo.com/u/3875024604&quot;&gt;@深谷-shintani&lt;/a&gt;&lt;/p&gt;</content></entry><entry><title>Monthly | 闲话二三</title><link href="https://www.moshanghua.net/archives/april-%E9%97%B2%E8%AF%9D%E4%BA%8C%E4%B8%89.html" /><id>https://www.moshanghua.net/archives/april-%E9%97%B2%E8%AF%9D%E4%BA%8C%E4%B8%89.html</id><updated>2024-05-05T16:18:13.000Z</updated><summary></summary><content type="html">&lt;h2&gt;网上冲浪&lt;/h2&gt;
&lt;h3&gt;博客&lt;/h3&gt;
&lt;p&gt;一个有点意思的 vuepress 主题：&lt;a href=&quot;https://80shuo.com/&quot;&gt;https://80shuo.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;一个长得像 vscode 的博客主题：&lt;a href=&quot;https://vscode.kamtao.com/&quot;&gt;https://vscode.kamtao.com/&lt;/a&gt;
&lt;img src=&quot;http://assets.moshanghua.net/images/2024/05/msh-3175-01.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;网站&lt;/h3&gt;
&lt;h4&gt;云看小米 SU7&lt;/h4&gt;
&lt;p&gt;项目体验地址：&lt;a href=&quot;https://gamemcu.com/su7/&quot; title=&quot;https://gamemcu.com/su7/&quot;&gt;https://gamemcu.com/su7/&lt;/a&gt;
关于项目：&lt;a href=&quot;https://www.bilibili.com/video/BV18x4y1m7Km&quot; title=&quot;让所有人都能上手体验小米SU7！&quot;&gt;让所有人都能上手体验小米SU7！&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;GameMCU官网：&lt;a href=&quot;https://gamemcu.com/&quot;&gt;https://gamemcu.com/&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;还原云看小米 SU7&lt;/h4&gt;
&lt;p&gt;来自 alphardex 的创作。
还原过程：&lt;a href=&quot;https://juejin.cn/post/7352762271003017252&quot; title=&quot;SU7，启动！尝试还原了 SU7 网页的炫酷特效&quot;&gt;SU7，启动！尝试还原了 SU7 网页的炫酷特效&lt;/a&gt;
效果地址：&lt;a href=&quot;https://su7-replica.netlify.app/&quot; title=&quot;su7-replica.netlify.app&quot;&gt;su7-replica.netlify.app&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;灵境至维&lt;/h4&gt;
&lt;p&gt;灵境至维，用3D技术重塑数字世界
灵境至维 既明科技官网：&lt;a href=&quot;https://ljzw.net/#/home&quot; title=&quot;https://ljzw.net/#/home&quot;&gt;https://ljzw.net/#/home&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;网站&lt;/h3&gt;
&lt;h4&gt;可视化配置 Nginx&lt;/h4&gt;
&lt;p&gt;开源地址：&lt;a href=&quot;https://github.com/digitalocean/nginxconfig.io&quot; title=&quot;github.com/digitalocean/nginxconfig.io&quot;&gt;github.com/digitalocean/nginxconfig.io&lt;/a&gt;
网站：&lt;a href=&quot;https://www.digitalocean.com/community/tools/nginx&quot; title=&quot;digitalocean.com/community/tools/nginx&quot;&gt;digitalocean.com/community/tools/nginx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在线进行配置，只需要打开网站：&lt;a href=&quot;https://nginxconfig.io/&quot;&gt;https://nginxconfig.io/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://assets.moshanghua.net/images/2024/05/msh-3175-06.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;它支持的功能配置：反向代理、HTTPS、HTTP/2、IPv6, 缓存、WordPress、CDN、Node.js 支持、 Python (Django) 服务器等等
按照自己的需求选择场景，填写好参数，系统就会自动生成配置文件。&lt;/p&gt;
&lt;h4&gt;TasteWP - 一键创建免费的WordPress测试站&lt;/h4&gt;
&lt;p&gt;使用 WordPress 难免要经常折腾，试用主题、插件什么的。TasteWP 就是可以解决这个需求，可以不先动刀正常运营的站点，也不用（麻烦的）按建站步骤去新建一个站点，专门做测试。
&lt;img src=&quot;http://assets.moshanghua.net/images/2024/05/msh-3175-08.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;一键就创建免费的WordPress测试站，测试主题和插件功能。新人也可以用来了解学习WordPress后台的操作和功能&lt;/p&gt;
&lt;p&gt;使用上和开临时服务一样，它还可以在无需注册的情况下获取&lt;strong&gt;一个&lt;/strong&gt;安装好的 WordPress临时实例，没注册登录的情况下有效期两天。&lt;/p&gt;
&lt;p&gt;点击高级设置还支持自定义WP版本和PHP版本，高级WP配置以及选择预安装插件和主题来安装WordPress测试环境。
&lt;img src=&quot;http://assets.moshanghua.net/images/2024/05/msh-3175-09.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;免费的版本还是有一些限制，但只是围观（新）主题效果、试用插件的话，应该也够用了把（？&lt;/p&gt;
&lt;p&gt;传送链接：&lt;a href=&quot;https://tastewp.com/&quot;&gt;尝试使用 WordPress  – TasteWP&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;InstallWP&lt;/h4&gt;
&lt;p&gt;TasteWP相似的工具，但要注册&lt;/p&gt;
&lt;p&gt;传送链接：&lt;a href=&quot;https://link.zhihu.com/?target=https://instawp.com/&quot;&gt;https://instawp.com/&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;语言相关的各种测试&lt;/h4&gt;
&lt;p&gt;中文官网：&lt;a href=&quot;https://www.arealme.com/cn&quot; title=&quot;https://www.arealme.com/cn&quot;&gt;https://www.arealme.com/cn&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我们致力于设计并开发原创、高品质、具时效性的各类有趣及有价值的测试产品。其范围包括但不限于心理性格、智力与各类知识、人际关系、影视文学作品角色等。我们希望通过这些测试，您可以感到快乐，收获知识，更可以进一步了解自己。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;贴两个语言类（可以看看认识多少字，词汇量又是如何）
中文识字量测试：&lt;a href=&quot;https://www.arealme.com/how-many-chinese-characters-do-i-know/cn/&quot;&gt;https://www.arealme.com/how-many-chinese-characters-do-i-know/cn/&lt;/a&gt;
中文词汇量测试：&lt;a href=&quot;https://www.arealme.com/chinese-vocabulary-size-test/cn/&quot; title=&quot;https://www.arealme.com/chinese-vocabulary-size-test/cn/&quot;&gt;https://www.arealme.com/chinese-vocabulary-size-test/cn/&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;虚拟ICP备&lt;/h4&gt;
&lt;p&gt;然后就是分享点续虚拟备案萌备后的各种衍生版，是最近冲浪捅到的虚拟备案的窝发现的
&lt;img src=&quot;https://assets.moshanghua.net/images/2024/05/msh-3175-16.png&quot; alt=&quot;&quot; /&gt;
&lt;a href=&quot;http://beian.miit.cn.com/&quot; title=&quot;MIIT ICP 备案：https://beian.miit.cn.com&quot;&gt;MIIT ICP 备案：https://beian.miit.cn.com&lt;/a&gt;
&lt;a href=&quot;https://guan.ma/&quot; title=&quot;官码：https://guan.ma/&quot;&gt;官码：https://guan.ma&lt;/a&gt;
&lt;a href=&quot;https://icp.18z.fun/&quot; title=&quot;梵ICP备：https://icp.18z.fun&quot;&gt;梵ICP备：https://icp.18z.fun&lt;/a&gt;
&lt;a href=&quot;https://icp.programapps.top/&quot; title=&quot;元ICP备：https://icp.programapps.top/&quot;&gt;元ICP备：https://icp.programapps.top&lt;/a&gt;
&lt;a href=&quot;https://icp.dns163.cn/&quot; title=&quot;易ICP备：https://icp.dns163.cn/&quot;&gt;易ICP备：https://icp.dns163.cn&lt;/a&gt;
&lt;a href=&quot;https://icp.kldhsh.top&quot; title=&quot;开朗ICP备：https://icp.kldhsh.top&quot;&gt;开朗ICP备：https://icp.kldhsh.top&lt;/a&gt;
&lt;a href=&quot;https://icp.k9b.cn/&quot; title=&quot;喵喵ICP备案：https://icp.k9b.cn&quot;&gt;喵喵ICP备案：https://icp.k9b.cn&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这一个个挂底部，花里胡哨的一长串，想着就得劲啊。&lt;/p&gt;
&lt;h2&gt;演唱会&lt;/h2&gt;
&lt;h3&gt;银临「山色有无中」巡演 - 上海站&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1Wt421E7HH&quot; title=&quot;【银临】上海站壹「山色有无中」完整版第一排视角&quot;&gt;【银临】上海站壹「山色有无中」完整版第一排视角&lt;/a&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV1yr421V7qA&quot; title=&quot;【银临】上海站贰「山色有无中」完整版第一排视角&quot;&gt;【银临】上海站贰「山色有无中」完整版第一排视角&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;凤凰传奇吉祥如意演唱会&lt;/h3&gt;
&lt;p&gt;最近刷到凤凰传奇演唱会相关片段后，就有点一发不可收拾了，每天都想去听一天，上头....&lt;/p&gt;
&lt;h4&gt;常州站&lt;/h4&gt;
&lt;p&gt;以下两个链接是B 站 UP  &lt;a href=&quot;https://space.bilibili.com/89255080&quot; title=&quot;B站UP兰珩LH&quot;&gt;兰珩LH&lt;/a&gt; 拍摄的音乐现场，没有机会去感受一下巡演现场，那就云听一下
&lt;a href=&quot;https://www.bilibili.com/video/BV1zi42127aB&quot;&gt;凤凰传奇演唱会常州站｜召唤全站云主唱！&lt;/a&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV1rm421x7Lf&quot; title=&quot;凤凰传奇演唱会常州站2｜比上一场状态好&quot;&gt;凤凰传奇演唱会常州站 2｜比上一场状态好&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV19i42127Ka&quot; title=&quot;凤凰传奇巡演首站常州！(4k完整版)&quot;&gt;凤凰传奇巡演首站常州！(4k 完整版)（分 P）&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;以及不同视角：
&lt;a href=&quot;https://search.bilibili.com/all?keyword=%E5%87%A4%E5%87%B0%E4%BC%A0%E5%A5%87%E6%BC%94%E5%94%B1%E4%BC%9A&quot; title=&quot;凤凰传奇演唱会&quot;&gt;凤凰传奇演唱会&lt;/a&gt;
整齐的前后抡荧光棒：&lt;a href=&quot;https://www.bilibili.com/video/BV18142197py&quot; title=&quot;从未见过如此整齐划一的荧光棒Ⅰ凤凰传奇 绿旋风Ⅰ吉祥如意演唱会常州首站&quot;&gt;从未见过如此整齐划一的荧光棒Ⅰ凤凰传奇 绿旋风Ⅰ吉祥如意演唱会常州首站&lt;/a&gt;
合唱《郎的诱惑》：&lt;a href=&quot;https://www.bilibili.com/video/BV11r421g73o&quot; title=&quot;凤凰传奇2024吉祥如意演唱会首站～常州站之郎的诱惑！毅哥一声娘子，台下万千娘子来应！&quot;&gt;凤凰传奇 2024 吉祥如意演唱会首站～常州站之郎的诱惑！毅哥一声娘子，台下万千娘子来应！&lt;/a&gt;
合唱《全是爱》：&lt;a href=&quot;https://www.bilibili.com/video/BV1f1421d7rz&quot; title=&quot;凤凰传奇常州21号｜《全是爱》第一次体验男女对歌，体验感拉爆！&quot;&gt;凤凰传奇常州 21 号｜《全是爱》第一次体验男女对歌，体验感拉爆！&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;北京站&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1Yz421U7N2&quot; title=&quot;凤凰传奇演唱会北京站｜六万人见证凤凰还巢！&quot;&gt;凤凰传奇演唱会北京站｜六万人见证凤凰还巢！&lt;/a&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV15x4y1q77M&quot; title=&quot;鸟巢首场山顶视角&quot;&gt;鸟巢首场山顶视角&lt;/a&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV18r421J7Je&quot; title=&quot;【凤凰传奇】“吉祥如意”巡回演唱会北京鸟巢2024.5.5&quot;&gt;【凤凰传奇】“吉祥如意”巡回演唱会北京鸟巢 2024.5.5 （山顶视角）&lt;/a&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV11f421U7Uc&quot; title=&quot;【凤凰传奇】20240504北京鸟巢演唱会第一场&quot;&gt;【凤凰传奇】20240504北京鸟巢演唱会第一场&lt;/a&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV12m411C7Go&quot; title=&quot;【凤凰传奇】20240505北京鸟巢演唱会第二场&quot;&gt;【凤凰传奇】20240505北京鸟巢演唱会第二场&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;时隔三年，又听到凤凰传奇唱海底了，演唱会首唱。
21 年版：&lt;a href=&quot;https://www.bilibili.com/video/BV1qp4y1t7DJ&quot; title=&quot;凤凰传奇翻唱《海底》&quot;&gt;凤凰传奇翻唱《海底》&lt;/a&gt;
演唱会版本（不同视角）：
&lt;a href=&quot;https://www.bilibili.com/video/BV19Z42177Sb&quot; title=&quot;多少人的入坑曲啊｜凤凰传奇北京演唱会《海底》&quot;&gt;多少人的入坑曲啊｜凤凰传奇北京演唱会《海底》&lt;/a&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV15x4y1q77M?p=2&quot; title=&quot;海底 鸟巢首场山顶视角&quot;&gt;海底 鸟巢首场山顶视角&lt;/a&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV1DE42157Yv&quot; title=&quot;唱哭自己唱哭我｜凤凰传奇｜海底&quot;&gt;唱哭自己唱哭我｜凤凰传奇｜海底&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;动漫&lt;/h2&gt;
&lt;h3&gt;诛仙鬼厉篇&lt;/h3&gt;
&lt;p&gt;又多了一部可看的动漫！&lt;a href=&quot;https://v.qq.com/x/cover/mzc00200kwy29cd/r0048fdxget.html&quot; title=&quot;诛仙第2季：定档3月30日 &quot;&gt;诛仙第 2 季：定档 3 月 30 日 &lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;凡人修仙传动画&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;凡人修仙传播放量破 22 亿！&lt;/strong&gt;
&lt;a href=&quot;https://www.bilibili.com/opus/922826981145313320&quot; title=&quot;来自 凡人修仙传动画连续剧 动态&quot;&gt;来自 凡人修仙传动画连续剧 动态&lt;/a&gt;
&lt;img src=&quot;http://assets.moshanghua.net/images/2024/05/msh-3175-13.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;百集上新祝福回顾集合！&lt;/strong&gt;
百集动画里程碑达成：&lt;a href=&quot;https://www.bilibili.com/bangumi/play/ep823133&quot; title=&quot;《凡人修仙传》动画百集里程碑达成！&quot;&gt;《凡人修仙传》动画百集里程碑达成！&lt;/a&gt;
动画百集编年史回顾：&lt;a href=&quot;https://www.bilibili.com/bangumi/play/ep823141&quot; title=&quot;回顾凡人百集精彩，共赴修仙之路！&quot;&gt;回顾凡人百集精彩，共赴修仙之路！&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;最近折腾的东西&lt;/h2&gt;
&lt;p&gt;原服务器系统用的是 CentOS 7,PHP 服务环境也是 7.0 的，在部署一些只支持较新技术的东西时只能退而求其次了，之前是没太多时间去大动环境捣鼓，自己也不想折腾，主打的就是一个能跑就行。&lt;/p&gt;
&lt;p&gt;这次折腾的原因是目前自己正好有点时间，一开始是在测试服务器上尝试着在 Ubuntu22.04 安装部署着一些服务，然后搭建部署成功了！然后尘封已久的换系统升级服务的念头就这样又给唤醒了，也就在四月中旬花了点时间迁移更改了下服务器系统也顺便升级了博客服务环境。&lt;/p&gt;
&lt;p&gt;顺手记录下流程，然后整理下水了几篇文章
&lt;a href=&quot;https://moshanghua.net/details/3055&quot; title=&quot;Ubuntu22.04下安装 Nginx + PHP + MySQL&quot;&gt;Ubuntu22.04下安装 Nginx + PHP + MySQL&lt;/a&gt;（这篇一开始是想整理补充成教程的，写写改改，然后放弃了，最后呈现的是一篇半教程半个人记录的文章）
&lt;a href=&quot;https://moshanghua.net/details/3073&quot; title=&quot;Ubuntu22.04上搭建 WordPress 以及部署主题 Nuxtjs + WordPress 流程&quot;&gt;Ubuntu22.04上搭建 WordPress 以及部署主题 Nuxtjs + WordPress 流程&lt;/a&gt;（这篇是纯个人记录，但整体下来也算十分之一篇教程吧，23333）&lt;/p&gt;
&lt;h2&gt;App付费&lt;/h2&gt;
&lt;p&gt;不知道从什么时候开始，定期付费App都成习惯了……
谈不上资深用户，就有时候需要，月付费价格高的离谱，付的几个月就够遇上活动折扣的年费价格了，但另一方面，就算是活动付费的年费，一年下来其实又没用多少，纯纯送钱…
粗想了一下自己，常用的一些软件好像都开了个遍…B站，爱奇艺，腾讯视频，QQ音乐，百度网盘……&lt;/p&gt;
&lt;h2&gt;碎碎叨叨&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;调整作息，&lt;/strong&gt;最近一个月以来，发现自己没有熬夜后，洗头发，吹头发，以及枕头边都不会遗落大把的头发了！！！咱也不知道是不是这回事，之前工作一个月有十五六天都在都在通宵，每次注意以上三个地方就是一捡一大把头发...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;人生第一次面基，&lt;/strong&gt;四月中旬，面基了认识七年的 &lt;a href=&quot;https://www.bytecho.net&quot; title=&quot;大肥&quot;&gt;大肥&lt;/a&gt;。也喝上了人生中第一杯咖啡 luckin coffee! 想不到有生之年也还能踏进大学里。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;吐槽，&lt;/strong&gt;腾讯视频什么时候也把爱奇艺的视频暂停塞全屏广告给学过来了....，本来有时暂停就是为了看下画面里的东西，这下好了，点了暂停后还要多点一下才能看...。这么看，VIP 的免广告特权这不就只免视频开头广告了，开屏，各页面下的广告是一点不少，现在还有个暂停塞全屏广告（部分）...&lt;/p&gt;
&lt;h2&gt;反思&lt;/h2&gt;
&lt;p&gt;社交幽灵，已读不回。&lt;/p&gt;
&lt;p&gt;提醒自己珍惜现在的精力，童年时光那种不知疲倦的状态随着年岁渐进离我们越来越远了。&lt;/p&gt;</content></entry><entry><title>Ubuntu22.04安装Docker</title><link href="https://www.moshanghua.net/archives/ubuntu22-04%E5%AE%89%E8%A3%85docker.html" /><id>https://www.moshanghua.net/archives/ubuntu22-04%E5%AE%89%E8%A3%85docker.html</id><updated>2024-04-28T15:58:54.000Z</updated><summary></summary><content type="html">&lt;h2&gt;准备&lt;/h2&gt;
&lt;p&gt;在 Ubuntu22.04 上安装 Docker，本文基于阿里云镜像仓库安装docker。&lt;/p&gt;
&lt;h2&gt;导入 Docker 的官方 GPG 公钥和添加 Docker CE 的阿里云镜像源&lt;/h2&gt;
&lt;p&gt;step 1: 安装必要的一些系统工具&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo apt update
sudo apt -y install apt-transport-https ca-certificates curl software-properties-common
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;step 2: 安装GPG证书&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;trusted.gpg.d&lt;/code&gt; 目录导入 Docker 的官方 GPG 公钥&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;下载 GPG 密钥&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;配置 APT 以信任新的密钥&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;配置 APT 以信任刚刚下载的 GPG 密钥。这涉及到修改或创建一个 &lt;code&gt;/etc/apt/trusted.gpg.d/&lt;/code&gt; 目录下的文件。通常，这个文件会与您要添加的仓库相关联。&lt;/p&gt;
&lt;p&gt;step 3:添加 Docker 的存储库：&lt;/p&gt;
&lt;p&gt;添加 Docker 的 APT 仓库以便于安装 Docker。&lt;/p&gt;
&lt;p&gt;添加 Docker CE 的阿里云镜像源到您的 &lt;code&gt;/etc/apt/sources.list.d/&lt;/code&gt; 目录下的 &lt;code&gt;docker.list&lt;/code&gt; 文件中，并且确保它引用了您刚刚创建的 &lt;code&gt;keyring&lt;/code&gt; 文件：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# Ubuntu22.04
echo &amp;quot;deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu jammy stable&amp;quot; | sudo tee /etc/apt/sources.list.d/docker.list

# Ubuntu 其他版本可以执行此条
echo &amp;quot;deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable&amp;quot; | sudo tee /etc/apt/sources.list.d/docker.list&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Step 4: 更新Docker-CE镜像源&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;apt update&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;安装指定版本的Docker-CE&lt;/h2&gt;
&lt;p&gt;Step 5: 查找Docker-CE的版本&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;apt-cache madison docker-ce

 docker-ce | 5:26.1.0-1~ubuntu.22.04~jammy | https://mirrors.aliyun.com/docker-ce/linux/ubuntu jammy/stable amd64 Packages
 docker-ce | 5:26.0.2-1~ubuntu.22.04~jammy | https://mirrors.aliyun.com/docker-ce/linux/ubuntu jammy/stable amd64 Packages
 docker-ce | 5:26.0.1-1~ubuntu.22.04~jammy | https://mirrors.aliyun.com/docker-ce/linux/ubuntu jammy/stable amd64 Packages
 docker-ce | 5:26.0.0-1~ubuntu.22.04~jammy | https://mirrors.aliyun.com/docker-ce/linux/ubuntu jammy/stable amd64 Packages
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Step 6: 安装指定版本的Docker-CE: (VERSION例如上面的5:26.1.0-1~ubuntu.22.04~jammy)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;apt -y install docker-ce=5:26.1.0-1~ubuntu.22.04~jammy docker-ce-cli=5:26.1.0-1~ubuntu.22.04~jammy&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Step7: 把Docker服务设为开机启动，并立即启动服务&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;systemctl enable --now docker&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看docker版本&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;docker version

# 查看docker信息
docker info

# 查看docker相关文件
dpkg -L docker-ce
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;安装docker-compose&lt;/h2&gt;
&lt;h3&gt;apt安装&lt;/h3&gt;
&lt;p&gt;使用&lt;code&gt;sudo apt  install docker-compose&lt;/code&gt; 安装之前，可以使用 &lt;code&gt;apt-cache policy docker-compose&lt;/code&gt; 命令可以显示 &lt;code&gt;docker-compose&lt;/code&gt; 包在系统中没有安装，因为apt 大部分情况下安装的都是较老版本。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;apt-cache policy docker-compose&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如下信息：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;root@moshanghua:~# apt-cache policy docker-compose
docker-compose:
  Installed: (none)
  Candidate: 1.29.2-1
  Version table:
     1.29.2-1 500
        500 http://mirrors.cloud.aliyuncs.com/ubuntu jammy/universe amd64 Packages&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但有一个候选版本 &lt;code&gt;1.29.2-1&lt;/code&gt; 可用。这个候选版本位于 &lt;code&gt;http://mirrors.cloud.aliyuncs.com/ubuntu jammy/universe&lt;/code&gt; 这个仓库中。&lt;/p&gt;
&lt;h3&gt;下载预编译的二进制文件并安装&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;下载特定版本的 docker-compose&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;首先，需要找到对应版本的 &lt;code&gt;docker-compose&lt;/code&gt; 的下载链接。&lt;/p&gt;
&lt;p&gt;可以在 &lt;a href=&quot;https://github.com/docker/compose/releases&quot;&gt;Docker Compose 的 GitHub 发布页面&lt;/a&gt; 中找到历史版本。&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;curl&lt;/code&gt; 命令下载&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# Ubuntu22.04 64位
curl -SL https://github.com/docker/compose/releases/download/v2.27.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose

# Ubuntu 其他版本可以执行此条
curl -L &amp;quot;https://github.com/docker/compose/releases/download/2.27.0/docker-compose-$(uname -s)-$(uname -m)&amp;quot; -o /usr/local/bin/docker-compose&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里的 &lt;code&gt;uname -s&lt;/code&gt; 和 &lt;code&gt;uname -m&lt;/code&gt; 分别代表操作系统名称和架构，它们会被替换为 &lt;code&gt;Linux x86_64&lt;/code&gt;，从而下载对应的版本。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用执行权限&lt;/strong&gt;： &lt;/p&gt;
&lt;p&gt;下载后，给 &lt;code&gt;docker-compose&lt;/code&gt; 文件应用执行权限&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo chmod +x /usr/local/bin/docker-compose&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;验证安装&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;验证 &lt;code&gt;docker-compose&lt;/code&gt; 是否安装成功，并检查安装的版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;docker-compose --version&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出应显示 &lt;code&gt;docker-compose version 2.27.0&lt;/code&gt;&lt;/p&gt;</content></entry><entry><title>Ubuntu22.04上搭建 WordPress 以及部署主题 Nuxtjs + WordPress 流程</title><link href="https://www.moshanghua.net/archives/ubuntu22-04%E4%B8%8A%E6%90%AD%E5%BB%BA-wordpress-%E4%BB%A5%E5%8F%8A%E9%83%A8%E7%BD%B2%E4%B8%BB%E9%A2%98-nuxtjs-wordpress-%E6%B5%81%E7%A8%8B.html" /><id>https://www.moshanghua.net/archives/ubuntu22-04%E4%B8%8A%E6%90%AD%E5%BB%BA-wordpress-%E4%BB%A5%E5%8F%8A%E9%83%A8%E7%BD%B2%E4%B8%BB%E9%A2%98-nuxtjs-wordpress-%E6%B5%81%E7%A8%8B.html</id><updated>2024-04-19T07:08:21.000Z</updated><summary></summary><content type="html">&lt;h1&gt;手动部署LNMP环境（Ubuntu）&lt;/h1&gt;
&lt;p&gt;LNMP分别代表Linux、Nginx、MySQL和PHP。安装步骤见文章&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;本文章仅用作记录，只描述了大概流程，非正经教程。&lt;/strong&gt;
&lt;strong&gt;毫无经验的小伙伴或者想搭建博客的都不建议浪费时间的往下看了&lt;/strong&gt;，标签页右边的×可以点一下了，&lt;/p&gt;
&lt;h3&gt;准备工作 一 创建一个数据库&lt;/h3&gt;
&lt;p&gt;进入数据库创建一个数据库用来存储WordPress的数据。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;登录 MySQL&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo mysql -uroot -p&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;创建数据库&lt;/strong&gt;，在这里，&lt;code&gt;database_name&lt;/code&gt; 是您想要创建的数据库名称。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;CREATE DATABASE database_name;

# 例如，创建一个名为 wp_blog 的数据库
CREATE DATABASE wp_blog;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建后也可以使用 &lt;code&gt;SHOW DATABASES&lt;/code&gt;; 查看数据库，这将列出所有可用的数据库。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 创建数据库
mysql&amp;gt; CREATE DATABASE wp_blog;
Query OK, 1 row affected (0.01 sec)

# 查看数据库
mysql&amp;gt; SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| wp_blog            |
+--------------------+
5 rows in set (0.00 sec)

mysql&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;准备工作 一 配置SSL 证书&lt;/h3&gt;
&lt;p&gt;申请一个ssl 证书，就可以使用https 协议访问网站。&lt;/p&gt;
&lt;p&gt;免费证书腾讯云或者阿里云以及其他地方都有提供申请渠道，申请过程略过。&lt;/p&gt;
&lt;p&gt;然后把以&lt;code&gt;.key&lt;/code&gt; &lt;code&gt;.pem&lt;/code&gt;两个后缀结尾的文字上传到服务器的目录下，什么路径都行，本教程使用的路径是 &lt;code&gt;/etc/nginx/&lt;/code&gt;，然后打开修改 nginx 配置文件&lt;code&gt;/etc/nginx/conf.d/default.conf&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;server {
  listen 443 ssl http2; #监听443端口，用于处理加密的HTTPS请求，并启用HTTP/2协议。

  # 引入证书文件开始
  ssl_certificate   /etc/nginx/xm.moshanghua.net.pem; #指定SSL证书文件路径。
  ssl_certificate_key  /etc/nginx/xm.moshanghua.net.key; # 指定SSL证书密钥文件路径。
  ssl_session_timeout 5m;
  ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
  ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1;
  ssl_prefer_server_ciphers on;
  # 引入证书文件结束 
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再定义一个服务器块，将所有HTTP请求重定向到HTTPS。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;server {
  listen 80;
  server_name xm.moshanghua.net ;
  rewrite ^/(.*) https://xm.moshanghua.net/$1 permanent;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完整的配置:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;server {
  listen 80; # 监听80端口，用于处理未加密的HTTP请求。
  listen 443 ssl http2; # 监听443端口，用于处理加密的HTTPS请求，并启用HTTP/2协议。
  server_name localhost;
  root /usr/share/nginx/html/wpblog; # 设置Web服务器的根目录。

  location / {
    index index.php index.html index.htm; # 设置默认的索引文件。
    # 尝试直接访问请求的文件或目录，如果找不到，则重定向到index.php。
    try_files $uri $uri/ /index.php?q=$uri&amp;amp;$args;
  }

  # 配置PHP请求的处理
  location ~ \.php$ {
    # 尝试直接访问请求的PHP文件，如果文件不存在，则返回404错误
    try_files $uri =404;
    include fastcgi_params; # 包含FastCGI参数文件
    fastcgi_pass 127.0.0.1:9000; # 设置FastCGI服务器地址和端口
    # 设置FastCGI脚本文件路径
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  }

  # SSL基础配置
  # 引入证书文件开始
  # 指定SSL证书文件路径，.pem前面一串字符改为自己的，路径也确认一下
  ssl_certificate   /etc/nginx/xm.moshanghua.net.pem;
  # 指定SSL证书密钥文件路径，.key前面一串字符改为自己的，路径也确认一下
  ssl_certificate_key  /etc/nginx/xm.moshanghua.net.key;
  # 设置SSL会话超时时间为5分钟
  ssl_session_timeout 5m;
  # 指定允许的SSL加密算法
  ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
  # 指定允许的SSL协议版本
  ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1;
  # 设置服务器加密算法优先
  ssl_prefer_server_ciphers on;
  # 引入证书文件结束
}

server {
  # 监听80端口，即HTTP请求的默认端口
  listen 80;
  # 指定了服务器的名称，nginx配置里多站点时建议指向一下具体的域名请求
  # 这里配置为xm.moshanghua.net，意味着它将响应所有指向该域名的请求。
  server_name xm.moshanghua.net ;
  # 这是一条rewrite规则，它将所有请求重定向到HTTPS
  # permanent标志表示这是一个永久重定向，HTTP状态码为301
  rewrite ^/(.*) https://xm.moshanghua.net/$1 permanent;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改Nginx配置后，重启一下：&lt;code&gt;sudo systemctl restart nginx&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;准备工作 一 源码相关&lt;/h3&gt;
&lt;p&gt;建议直接 clone 一份源码在本地，修改之后先上传到自己的GitHub仓库，再推到服务器。&lt;/p&gt;
&lt;p&gt;这样做方便后续主题更新，可以在本地先改好，能正常运行跑一下流程，确认没问题了再拉取更新，不然直接拉取的话，安装依赖出点问题线上环境也就打不开了。&lt;/p&gt;
&lt;p&gt;（本文章本部部分略过，线上直接跑项目）&lt;/p&gt;
&lt;p&gt;源码地址：&lt;a href=&quot;https://github.com/D-xuanmo/Nuxtjs-Wordpress&quot;&gt;https://github.com/D-xuanmo/Nuxtjs-Wordpress&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;准备工作 一 端口放行&lt;/h2&gt;
&lt;p&gt;务器配置放行端口 &lt;code&gt;3000&lt;/code&gt;，&lt;code&gt;3002&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;下面介绍如何在Ubuntu 22.04搭建wordpress 以及部署主题Nuxtjs + WordPress。&lt;/p&gt;
&lt;h2&gt;安装 WordPress&lt;/h2&gt;
&lt;p&gt;首先进入网站根目录，不一定是非得在 /usr/share/nginx/html 目录下，也可以自己接着套文件夹或者另起文件夹，记得去Nginx 配置里同步修改。
本文演示目录为 &lt;code&gt;/usr/share/nginx/html/wpblog&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;cd /usr/share/nginx/html/wpblog&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用wget 下载WordPress 程序，此链接默认下载最新版本&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;wget https://cn.wordpress.org/latest-zh_CN.zip&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果不要最新版，也可以前往&lt;a href=&quot;https://cn.wordpress.org/download/releases/&quot;&gt;https://cn.wordpress.org/download/releases/&lt;/a&gt; ，这是为 WordPress 提供的每个记录版本的归档。&lt;/p&gt;
&lt;p&gt;下载好后就解压文件&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 新环境，如果没有 unzip 解压工具可以安装一下
sudo apt install unzip

# unzip 命令解压
unzip latest-zh_CN.zip
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解压后，文件默认是一起放在 wordpress 目录下，如果不是以此目录作为根目录，就用 mv 命令移动一下，演示的根目录是 &lt;code&gt;/usr/share/nginx/html/wpblog&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 将 wordpress 目录下的所有文件和文件夹移动到 /usr/share/nginx/html/wpblog 目录下
mv wordpress/* /usr/share/nginx/html/wpblog&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后就可以访问解析的域名进行程序引导安装了，点击现在就开始。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-01.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;数据库名填写前面用命令创建的&lt;code&gt;wp_blog&lt;/code&gt;，用户名为MySQL的用户名&lt;code&gt;root&lt;/code&gt;,密码为MySQL的登录密码，数据库主机不用改，表前缀改不改都行。&lt;/p&gt;
&lt;p&gt;然后提交。
&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如果出现以下界面，权限不够，无法写入。
您可以使用 chmod 命令来设置权限&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 设置权限
sudo chmod 755 /usr/share/nginx/html/wpblog

# 设置所有者
sudo chown www-data:www-data /usr/share/nginx/html/wpblog&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;点击运行安装程序就能下一步了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-03.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;来到这一步，站点标题和邮箱地址后面都是可以改的，无所谓怎么写。&lt;/p&gt;
&lt;p&gt;用户名和密码要认真填写并记住，等下登录后台要用的。&lt;/p&gt;
&lt;p&gt;用户名可以自定义字符&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-04.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;点击安装WordPress，就可以看到安装成功的页面。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-05.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;到这里，WordPress就安装完成了。&lt;/p&gt;
&lt;p&gt;输入  &lt;a href=&quot;https://域名/wp-login.php&quot;&gt;https://域名/wp-login.php&lt;/a&gt; 就可以访问博客后台了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-06.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;设置里可以设置博客的配置，略过.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-07.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;主题部署&lt;/h2&gt;
&lt;h3&gt;所需环境准备&lt;/h3&gt;
&lt;p&gt;Nodejs 版本推荐 16.10.x或往上，低于16.10.x会报错模块不兼容。&lt;/p&gt;
&lt;h3&gt;安装 Nodejs 环境&lt;/h3&gt;
&lt;p&gt;需要在服务器安装 node 环境，需要大于 16.10.0。&lt;/p&gt;
&lt;p&gt;本文章 node 版本为&lt;code&gt;16.17.0&lt;/code&gt;，使用 wget 命令下载 Node.js 安装包，文件可以放在 &lt;code&gt;root&lt;/code&gt; 目录，具体随意。本文档存放目录为 &lt;code&gt;root&lt;/code&gt;目录&lt;/p&gt;
&lt;p&gt;该方式使用的安装包是已编译好的二进制文件。解压文件之后，在bin文件夹中就已存在node和npm，无需重复编译。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;wget https://nodejs.org/dist/v16.17.0/node-v16.17.0-linux-x64.tar.xz&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 将当前目录更改到根目录
cd ~

# 显示当前工作目录的绝对路径
pwd
/root

wget https://nodejs.org/dist/v16.17.0/node-v16.17.0-linux-x64.tar.xz
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;该安装包是编译好的文件，解压之后，在 bin 文件夹中就已存在 node 和 npm，无需重复编译。&lt;/p&gt;
&lt;p&gt;解压文件 &lt;code&gt;tar xvf node-v16.17.0-linux-x64.tar.xz&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;创建软链接，使 node 和 npm 命令全局有效。通过创建软链接的方法，使得在任意目录下都可以直接使用 node 和 npm 命令。&lt;/p&gt;
&lt;p&gt;语法：&lt;/p&gt;
&lt;p&gt;在执行这个命令之前，需要确保有足够的权限来在 &lt;code&gt;/usr/local/bin&lt;/code&gt; 目录下创建链接。如果当前登录的用户账户没有足够的权限，可能需要使用 &lt;code&gt;sudo&lt;/code&gt; 来执行这个命令&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注：如果在下载Node.js 安装包时，不是在 **&lt;/strong&gt;&lt;code&gt;/root&lt;/code&gt;&lt;strong&gt;**目录下，那创建软链接时的源文件路径也要做相应更改&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;ln -s /root/node-v16.17.0-linux-x64/bin/node /usr/local/bin/node
ln -s /root/node-v16.17.0-linux-x64/bin/npm /usr/local/bin/npm&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;到此已经安装完成，使用 &lt;code&gt;node -v&lt;/code&gt; 查看 node 版本，使用 &lt;code&gt;npm -v&lt;/code&gt; 查看版本号，如果出现正确版本号则安装成功。&lt;/p&gt;
&lt;h3&gt;使用 npm 安装其他的全局命令&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;npm i -g yarn pm2&lt;/code&gt; 这条命令是全局安装 yarn 和 pm2。&lt;/p&gt;
&lt;p&gt;如果安装比较慢，可以使用淘宝镜像安装，&lt;code&gt;npm i -g yarn pm2 --registry=https://registry.npmmirror.com&lt;/code&gt;，后续的安装都可以加上这个。&lt;/p&gt;
&lt;p&gt;如果执行了这一步操作，提示 &lt;code&gt;Command &amp;#039;yarn&amp;#039; not found&lt;/code&gt; 或者 &lt;code&gt;Command &amp;#039;pm2&amp;#039; not found&lt;/code&gt; ，可以使用下边两条命令：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;ln -s /root/node-v16.17.0-linux-x64/bin/yarn /usr/local/bin/yarn
ln -s /root/node-v16.17.0-linux-x64/bin/pm2 /usr/local/bin/pm2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上命令和前面一样的效果，创建一个名为 &lt;code&gt;/usr/local/bin/yarn&lt;/code&gt; 的符号链接，它指向 &lt;code&gt;/root/node-v16.17.0-linux-x64/bin/yarn&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这样做的目的是为了方便在任意目录下都能通过 &lt;code&gt;yarn&lt;/code&gt; 命令来运行 &lt;code&gt;/root/node-v16.17.0-linux-x64/bin/yarn&lt;/code&gt; 这个Yarn的包管理器，而无需每次都输入完整的路径。&lt;/p&gt;
&lt;p&gt;完整步骤演示：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 将当前目录更改到根目录
cd ~

# 显示当前工作目录的绝对路径
pwd
/root

# 下载指定版本nodejs
wget https://nodejs.org/dist/v16.17.0/node-v16.17.0-linux-x64.tar.xz

# 解压文件
tar xvf node-v16.17.0-linux-x64.tar.xz

# 创建软链接，使 node 和 npm 命令全局有效
ln -s /root/node-v16.17.0-linux-x64/bin/node /usr/local/bin/node
ln -s /root/node-v16.17.0-linux-x64/bin/npm /usr/local/bin/npm

# 全局安装 yarn 和 pm2
npm i -g yarn pm2 --registry=https://registry.npmmirror.com

#创建软链接，使 yarn 和 pm2 命令全局有效
ln -s /root/node-v16.17.0-linux-x64/bin/yarn /usr/local/bin/yarn
ln -s /root/node-v16.17.0-linux-x64/bin/pm2 /usr/local/bin/pm2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;运行项目&lt;/h3&gt;
&lt;p&gt;下载主题到网站根目录&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;cd /usr/share/nginx/html/wpblog

# 下载源码
wget https://github.com/D-xuanmo/Nuxtjs-Wordpress/archive/refs/heads/master.zip

#解压文件
unzip master.zip
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将源码目录下的 service 放入 WordPress 主题目录 wp-content/theme/ 下，并启用此主题&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 进入源码目录
cd Nuxtjs-Wordpress-master/

# 复制目录到主题目录下
cp -r service/ /usr/share/nginx/html/wpblog/wp-content/themes/

# ls命令确认下文件
ls /usr/share/nginx/html/wpblog/wp-content/themes/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-08.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;进入 &lt;code&gt;Nuxtjs主题设置&lt;/code&gt; ，启用本主题之后，会在外观菜单下加入一个子菜单，将站点前端域名设置为 WordPress 访问地址，确保 &lt;code&gt;http://{domain}/wp-json&lt;/code&gt; 能有正确的数据，所有 WordPress 接口都是在这个虚拟目录下；如果访问报错可以尝试在 &lt;code&gt;后台设置=&amp;gt;固定链接&lt;/code&gt; 设置为数字型；&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-09.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;访问地址，确保 &lt;a href=&quot;http://{domain}/wp-json&quot;&gt;http://{domain}/wp-json&lt;/a&gt; 能有正确的数据。&lt;a href=&quot;https://xm.moshanghua.net/wp-json&quot;&gt;https://xm.moshanghua.net/wp-json&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-10.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;打开目录下&lt;code&gt;Nuxtjs-Wordpress-master/nuxt.config.js&lt;/code&gt;文件，修改项目的一些配置，改为自己的信息，如下截图，这一步不是必选的，可以安装完成之后在修改&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-11.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;改完之后再继续往下翻到最后，将下图2个地址改为自己的域名&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-12.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;确认此时是在Nuxtjs-Wordpress-master这个目录，执行 &lt;code&gt;yarn&lt;/code&gt; 命令，这一步是安装项目所需要的依赖文件。（warning信息无视就好）&lt;/p&gt;
&lt;p&gt;如果比较慢可以使用这个命令 &lt;code&gt;yarn --registry=https://registry.npmmirror.com&lt;/code&gt;；&lt;/p&gt;
&lt;p&gt;依赖安装完成之后，执行 &lt;code&gt;yarn dev&lt;/code&gt;，如果能出现以下截图代表能够正常运行项目。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;到这里，访问上还是有问题，可以先跳到下面的Nginx 反向代理部分，把配置设置好。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;遇到的问题：&lt;/p&gt;
&lt;p&gt;但这会通过自己的域名或者 IP 访问 3000 端口还是无响应状态。&lt;/p&gt;
&lt;p&gt;在Nginx配置文件里的根目录的请求处理配置部分加入proxy_pass &lt;a href=&quot;http://127.0.0.1:3000&quot;&gt;http://127.0.0.1:3000&lt;/a&gt;后，&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;  location / {
    # 这里是每次访问域名将请求转发到3000端口
    proxy_pass http://127.0.0.1:3000;
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这下能通过主域名&lt;a href=&quot;https://xm.moshanghua.net/&quot;&gt;https://xm.moshanghua.net&lt;/a&gt; 访问到部分数据，大部分文件请求还是失败的&lt;/p&gt;
&lt;h2&gt;使用 Nginx 反向代理&lt;/h2&gt;
&lt;p&gt;需要的是用 80 或者 443 去访问，所以需要用 nginx 做代理，&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Tips:&lt;/code&gt; 先到数据库找到WordPress的表 &lt;code&gt;wp_options&lt;/code&gt; ，修改 &lt;code&gt;siteurl&lt;/code&gt; 和 &lt;code&gt;home&lt;/code&gt; 字段，值改为 &lt;code&gt;http://{你的域名}:3002&lt;/code&gt; 端口，因为后续WordPress只会作为一个CMS管理系统&lt;/p&gt;
&lt;p&gt;登录数据库，切换到WordPress数据库的表 wp_options ，修改 siteurl 和 home 字段&lt;/p&gt;
&lt;p&gt;登录和切换数据库&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;#登录
mysql -u username -p

# 选择数据库，database_name 是想要选择的数据库名称
USE database_name;

# 列出数据库中的所有表
SHOW TABLES;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改 siteurl 和 home 字段。&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;UPDATE&lt;/code&gt; 语句来修改 wp_options 表中 option_name 字段下 home 的内容&lt;/p&gt;
&lt;p&gt;以下是一个示例 SQL 语句，用于将 &lt;code&gt;home&lt;/code&gt; 的内容修改为 &lt;code&gt;http://xm.moshanghua.net:3002&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 修改 home 字段
UPDATE wp_options
SET option_value = &amp;#039;http://xm.moshanghua.net:3002&amp;#039;
WHERE option_name = &amp;#039;home&amp;#039;;

# 修改 siteurl 字段
UPDATE wp_options
SET option_value = &amp;#039;http://xm.moshanghua.net:3002&amp;#039;
WHERE option_name = &amp;#039;siteurl&amp;#039;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完整演示：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;mysql&amp;gt; SHOW DATABASES;

mysql&amp;gt; USE wp_blog;

mysql&amp;gt; SHOW TABLES;

mysql&amp;gt; DESCRIBE wp_options;

mysql&amp;gt; SELECT option_value FROM wp_options WHERE option_name = &amp;#039;home&amp;#039;;
+---------------------------+
| option_value              |
+---------------------------+
| https://xm.moshanghua.net |
+---------------------------+
1 row in set (0.00 sec)

mysql&amp;gt; SELECT option_value FROM wp_options WHERE option_name = &amp;#039;siteurl&amp;#039;;

mysql&amp;gt; UPDATE wp_options SET option_value = &amp;#039;http://xm.moshanghua.net:3002&amp;#039; WHERE option_name = &amp;#039;home&amp;#039;;

mysql&amp;gt; UPDATE wp_options SET option_value = &amp;#039;http://xm.moshanghua.net:3002&amp;#039; WHERE option_name = &amp;#039;siteurl&amp;#039;;

mysql&amp;gt; SELECT option_value FROM wp_options WHERE option_name = &amp;#039;home&amp;#039;;
+-------------------------------+
| option_value                  |
+-------------------------------+
| http://xm.moshanghua.net:3002 |
+-------------------------------+
1 row in set (0.00 sec)

mysql&amp;gt; SELECT option_value FROM wp_options WHERE option_name = &amp;#039;siteurl&amp;#039;;

mysql&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-13.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-14.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-15.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;数据库字段修改完后，就再配置下规则：&lt;/p&gt;
&lt;p&gt;以下是我的配置文件说明，这一步更多配置需要自己了解一下 nginx 配置：&lt;/p&gt;
&lt;p&gt;配置分为两段&lt;/p&gt;
&lt;p&gt;第一段，设置了一个监听3002端口的虚拟服务器，专门用于服务WordPress应用程序，用于代替之前的 WordPress 访问端口&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# wordpress
server {
  # 这告诉Nginx监听3002端口，并将这个服务器块设置为默认服务器
  # 这意味着如果请求没有指定服务器块，将会由这个服务器块处理
  listen 3002 default_server;
  server_name xm.moshanghua.net;
  root   /usr/share/nginx/html/wpblog;

  location / {
    index index.php index.html index.htm;
    try_files $uri $uri/ /index.php?q=$uri&amp;amp;$args;
  }

  location ~ \.php$ {
    try_files $uri =404;
    include fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第二段，设置一个服务器块，它同时监听80和443端口去代理 Nuxt 服务。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;server {
  listen 80;
  # 听443端口，用于处理加密的HTTPS请求，并启用HTTP/2协议
  listen 443 ssl http2;
  server_name xm.moshanghua.net;
  root   /usr/share/nginx/html/wpblog;

  # 引入证书文件开始
  ssl_certificate   /etc/nginx/xxx.pem; # 指定SSL证书文件路径
  ssl_certificate_key  /etc/nginx/xxx.key; # 指定SSL证书密钥文件路径
  ssl_session_timeout 5m;
  ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
  ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1;
  ssl_prefer_server_ciphers on;

  location / {
    # 这里是每次访问域名将请求转发到3000端口
    proxy_pass http://127.0.0.1:3000;
  }

  # 下边两个是代理wordpress的一些服务
  # 配置对/wp-json路径的请求处理
  location /wp-json {
    # 将对/wp-json的请求代理到本地的3002端口
    proxy_pass http://127.0.0.1:3002/wp-json;
  }
  # 配置对/wp-content路径的请求处理
  location /wp-content {
    # 将对/wp-content的请求代理到本地的3002端口
    proxy_pass http://127.0.0.1:3002/wp-content;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完整的配置：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# wordpress
server {
  listen 3002 default_server;
  server_name xm.moshanghua.net;
  root   /usr/share/nginx/html/wpblog;

  location / {
    index index.php index.html index.htm;
    try_files $uri $uri/ /index.php?q=$uri&amp;amp;$args;
  }

  location ~ \.php$ {
    try_files $uri =404;
    include fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  }
}

server {
  listen 80;
  server_name xm.moshanghua.net ;
  rewrite ^/(.*) https://xm.moshanghua.net/$1 permanent;
}

server {
  listen 80;
  listen 443 ssl http2;
  server_name xm.moshanghua.net;
  root   /usr/share/nginx/html/wpblog;

  ssl_certificate   /etc/nginx/xm.moshanghua.net.pem;
  ssl_certificate_key  /etc/nginx/xm.moshanghua.net.key;
  ssl_session_timeout 5m;
  ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
  ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1;
  ssl_prefer_server_ciphers on;

  location / {
    proxy_pass http://127.0.0.1:3000;
  }

  # 下边两个是代理wordpress的一些服务
  location /wp-json {
    proxy_pass http://127.0.0.1:3002/wp-json;
  }

  location /wp-content {
    proxy_pass http://127.0.0.1:3002/wp-content;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果成功配置就到这里结束了。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo nginx -t&lt;/code&gt;测试一下配置，然后重启&lt;code&gt;sudo systemctl restart nginx&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;再次运行项目&lt;/h3&gt;
&lt;p&gt;执行 &lt;code&gt;yarn dev&lt;/code&gt;，如果能出现以下截图代表能够正常运行项目，&lt;/p&gt;
&lt;p&gt;然后用自己的域名访问，如果能够正常访问按&lt;code&gt;ctrl+c&lt;/code&gt; 退出即可；&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-16.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;yarn pm2&lt;/code&gt; 这条命令去运行项目并开启文件更改自动重载项目，pm2 是 Nodejs 的一个守护进程，使用 &lt;code&gt;pm2 logs&lt;/code&gt; 可查看日志。&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;pm2 save&lt;/code&gt; 保存当前的应用列表，使用 &lt;code&gt;pm2 startup&lt;/code&gt; 开机自动启动&lt;/p&gt;
&lt;p&gt;运行项目完整流程：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt; # 安装项目所需要的依赖文件
 yarn --registry=https://registry.npmmirror.com

 # 运行开发环境下的脚本
 yarn dev

 # 运行项目
 yarn pm2

 # 查看运行日志
 pm2 logs

 # 保存当前的应用列表
 pm2 save

 # 开机自动启动
 pm2 startup
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;至此通过域名&lt;a href=&quot;https://xm.moshanghua.net/&quot;&gt;https://xm.moshanghua.net/&lt;/a&gt;就能正常访问了&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-17.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;博客后台&lt;a href=&quot;http://xm.moshanghua.net:3002/admin&quot;&gt;xm.moshanghua.net:3002/admin&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-18.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3073-19.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;博客后台如果不想带端口去访问，也可以NGINX配置下的WordPress一个服务器块里修改下规则反代到指定域名，也可以顺便加上 SSL，走HTTPS访问。&lt;/p&gt;
&lt;h2&gt;主题设置&lt;/h2&gt;
&lt;p&gt;Nuxtjs + WordPress主题使用说明请访问&lt;a href=&quot;https://xuanmo.xin/details/2987&quot;&gt;https://xuanmo.xin/details/2987&lt;/a&gt;&lt;/p&gt;</content></entry><entry><title>SQL指令备忘录</title><link href="https://www.moshanghua.net/archives/mysql%E9%83%A8%E5%88%86%E5%B8%B8%E7%94%A8%E7%9A%84%E6%8C%87%E4%BB%A4-2.html" /><id>https://www.moshanghua.net/archives/mysql%E9%83%A8%E5%88%86%E5%B8%B8%E7%94%A8%E7%9A%84%E6%8C%87%E4%BB%A4-2.html</id><updated>2024-04-18T04:21:26.000Z</updated><summary></summary><content type="html">&lt;p&gt;SQL的一些常用命令，使用环境MySQL8.0，个人使用记录，非教程。&lt;/p&gt;
&lt;h2&gt;部分常用指令&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;登录 MySQL&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo mysql -uroot -p&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;创建数据库&lt;/strong&gt;在这里，&lt;code&gt;database_name&lt;/code&gt; 是您想要创建的数据库名称。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;CREATE DATABASE database_name;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;查看数据库&lt;/strong&gt;，这将列出所有可用的数据库。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;SHOW DATABASES;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;选择数据库&lt;/strong&gt;，在这里，&lt;code&gt;database_name&lt;/code&gt; 是您想要选择的数据库名称。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;USE database_name;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;列出数据库中的所有表&lt;/strong&gt;，可以使用 &lt;code&gt;SHOW TABLES&lt;/code&gt; 。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;SHOW TABLES;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;查看表的结构数据&lt;/strong&gt;，使用 &lt;code&gt;DESCRIBE&lt;/code&gt; ，在这里，&lt;code&gt;datasheets&lt;/code&gt; 是您想要选择的数据表名称。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;DESCRIBE datasheets;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者，使用 &lt;code&gt;SHOW COLUMNS&lt;/code&gt; 命令&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;SHOW COLUMNS FROM datasheets;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;示例 SQL 语句，查看 &lt;code&gt;wp_options&lt;/code&gt; 表的结构：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;DESCRIBE wp_options;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;查看修改某个表中某字段下的内容&lt;/h2&gt;
&lt;h3&gt;一&lt;/h3&gt;
&lt;p&gt;查看表 wp_users 下 user_pass 的内容&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;SELECT user_pass FROM wp_users;

# 这个查询将显示所有用户的用户名（user_login）和加密后的密码（user_pass）
SELECT user_login, user_pass FROM wp_users;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改表 wp_users 下 user_pass 的内容bfa0022e2da2d6ea1dfe8cec00964ba7&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 将your_username替换为您想要更改密码的用户名。
# 这个命令会将指定用户的user_pass字段更新为您提供的哈希值
UPDATE wp_users SET user_pass = &amp;#039;bfa0022e2da2d6ea1dfe8cec00964ba7&amp;#039; WHERE user_login = &amp;#039;your_username&amp;#039;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;二&lt;/h3&gt;
&lt;p&gt;例如在按照教程 &lt;a href=&quot;https://www.xuanmo.xin/details/2987&quot;&gt;https://www.xuanmo.xin/details/2987&lt;/a&gt; 部署主题时，要修改数据库。内容如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tips: 先到数据库找到WordPress的表 wp_options ，修改 siteurl 和 home 字段，值改为 &lt;a href=&quot;http://{你的域名}:3002&quot;&gt;http://{你的域名}:3002&lt;/a&gt; 端口&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;要查看 &lt;code&gt;wp_options&lt;/code&gt; 表中 &lt;code&gt;option_name&lt;/code&gt; 字段下 &lt;code&gt;home&lt;/code&gt; 的内容，可以使用以下 SQL 查询：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-SQL&quot;&gt;SELECT option_value FROM wp_options WHERE option_name = &amp;#039;home&amp;#039;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用 &lt;code&gt;UPDATE&lt;/code&gt; 语句来修改 &lt;code&gt;wp_options&lt;/code&gt; 表中 &lt;code&gt;option_name&lt;/code&gt; 字段下 &lt;code&gt;home&lt;/code&gt; 的内容。以下是一个示例 SQL 语句，用于将 &lt;code&gt;home&lt;/code&gt; 的内容修改为 &lt;code&gt;http://xm.moshanghua.net:3002&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-SQL&quot;&gt;UPDATE wp_options
SET option_value = &amp;#039;http://xm.moshanghua.net:3002&amp;#039;
WHERE option_name = &amp;#039;home&amp;#039;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;MySQL备份与导入&lt;/h2&gt;
&lt;h3&gt;使用mysqldump工具备份&lt;/h3&gt;
&lt;p&gt;mysqldump是MySQL自带的逻辑备份工具，可以备份整个数据库或者其中的部分表。以下是一个基本的备份命令：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mysqldump -u 用户名 -p 数据库名 &amp;gt; 备份文件.sql&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个命令会提示你输入密码，并将指定的数据库备份到一个.sql文件中。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;备份数据库到指定目录&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mysqldump -u username -p database_name &amp;gt; /path/to/backup/directory/backup.sql&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在这个命令中，&lt;code&gt;username&lt;/code&gt;是你的MySQL用户名，&lt;code&gt;database_name&lt;/code&gt; 是要备份的数据库名。&lt;code&gt;/path/to/backup/directory/&lt;/code&gt;是你要保存备份文件的目录，&lt;code&gt;backup.sql&lt;/code&gt;是要保存的备份文件名，名字也可以自己起。
执行这个命令后，会要求你输入密码。输入密码后，等待备份完成。&lt;/p&gt;
&lt;h3&gt;导入备份&lt;/h3&gt;
&lt;p&gt;方法一：直接导入 SQL 文件&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mysql -u username -p database_name &amp;lt; path/to/backup.sql&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个命令会在登录后直接将 backup.sql 文件的内容导入到 database_name 数据库中。&lt;/p&gt;
&lt;p&gt;方法二：登录 MySQL，使用&lt;code&gt;SOURCE&lt;/code&gt; 语句。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mysql -u username -p&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;选择数据库，然后导入文件。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 如果已经知道要导入的 SQL 文件属于哪个数据库，可以使用以下命令选择数据库：
USE database_name;

# 导入 SQL 文件
# path/to/backup.sql 是 SQL 文件所在的路径。
SOURCE path/to/backup.sql;&lt;/code&gt;&lt;/pre&gt;</content></entry><entry><title>迁移博客遇到的几个问题</title><link href="https://www.moshanghua.net/archives/mysql%E9%83%A8%E5%88%86%E5%B8%B8%E7%94%A8%E7%9A%84%E6%8C%87%E4%BB%A4.html" /><id>https://www.moshanghua.net/archives/mysql%E9%83%A8%E5%88%86%E5%B8%B8%E7%94%A8%E7%9A%84%E6%8C%87%E4%BB%A4.html</id><updated>2024-04-18T03:02:09.000Z</updated><summary></summary><content type="html">&lt;h2&gt;博客显示提示建立数据库连接时出错&lt;/h2&gt;
&lt;p&gt;WordPress博客更换环境后，导入数据库访问提示建立数据库连接时出错，但各种信息是没有问题的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3060-01.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;创建一个的PHP脚本test.php，使用&lt;code&gt;wp-config.php&lt;/code&gt;中的数据库连接信息尝试连接到数据库，以检查是否能够成功连接。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;&amp;lt;?php
define(&amp;#039;DB_NAME&amp;#039;, &amp;#039;your_database_name&amp;#039;);
define(&amp;#039;DB_USER&amp;#039;, &amp;#039;your_database_user&amp;#039;);
define(&amp;#039;DB_PASSWORD&amp;#039;, &amp;#039;your_database_password&amp;#039;);
define(&amp;#039;DB_HOST&amp;#039;, &amp;#039;your_database_host&amp;#039;);

$connection = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);

if ($connection) {
    echo &amp;quot;Database connection successful!&amp;quot;;
} else {
    echo &amp;quot;Error: Unable to connect to database.&amp;quot;;
    echo mysqli_connect_error();
}
?&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;显示了Database connection successful! 连接是没问题的。&lt;/p&gt;
&lt;p&gt;解决办法...就删掉了&lt;code&gt;wp-config.php&lt;/code&gt;文件，复制wp-config-sample.php文件里的内容重新填写了下数据库的内容，再保存为&lt;code&gt;wp-config.php&lt;/code&gt;后，就访问正常了.....&lt;/p&gt;
&lt;h2&gt;验证PHP安装提示 502&lt;/h2&gt;
&lt;p&gt;nginx配置如下&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;server {
  listen 80;
  server_name localhost;
  # 网站根目录
  root /usr/share/nginx/html;

  location / {
    index index.php index.html index.htm;
    try_files $uri $uri/ /index.php?q=$uri&amp;amp;$args;
  }

  location ~ \.php$ {
    try_files $uri =404;
    include fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在访问带php文件的页面就显示502&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3060-02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在nginx里的日志看到如下错误信息&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;[error] 10795#10795: *11 connect() failed (111: Connection refused) while connecting to upstream, client: 171.106.160.15, server: localhost, request: &amp;quot;GET /info.php HTTP/1.1&amp;quot;, upstream: &amp;quot;fastcgi://127.0.0.1:9000&amp;quot;, host: &amp;quot;xm.moshanghua.net&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;错误信息了解到的信息，这里的上游服务器是指PHP-FPM。&lt;/p&gt;
&lt;p&gt;错误码111表示连接被拒绝，这意味着Nginx无法与PHP-FPM通信。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo systemctl status php7.4-fpm&lt;/code&gt; 看了下状态，PHP-FPM服务在正常运行。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ps aux | grep php-fpm&lt;/code&gt;命令来查看所有运行中的进程，并且通过grep命令过滤出与php-fpm相关的进程，进程也没问题。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;netstat -ant |grep 9000&lt;/code&gt;来检查端口9000上的网络连接情况。&lt;/p&gt;
&lt;p&gt;这个命令通常用于确认PHP-FPM服务是否正在监听TCP端口9000，因为PHP-FPM默认可能会监听这个端口。&lt;/p&gt;
&lt;p&gt;执行这个命令时，您可能会看到类似以下的输出：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但在输出中看不到任何监听端口9000的行，那么PHP-FPM可能没有配置为监听TCP端口9000，或者服务没有运行。&lt;/p&gt;
&lt;p&gt;在这种情况下，检查PHP-FPM的配置文件（通常位于 /etc/php/7.4/fpm/pool.d/www.conf 或类似路径），确认listen指令是否正确设置为监听端口9000&lt;/p&gt;
&lt;p&gt;不是就修改一下让其指向TCP端口，因为Nginx配置用的也是TCP端口。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;但指向套接字文件好像不行，就算Nginx配置里也用Unix socket，也有问题，不知道是不是路径有问题...具体情况没研究了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一般在 &lt;code&gt;www.conf &lt;/code&gt;文件的30多行的样子，会看到一条listen指令 &lt;code&gt;listen = /run/php/php8.1-fpm.sock&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这里把它修改了或者注释重新起一行，让它指向TCP端口&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;;listen = /run/php/php8.1-fpm.sock
listen = 127.0.0.1:9000&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3060-03.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;保存后重启一下php-fpm &lt;code&gt;sudo systemctl restart php7.4-fpm&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;再次访问应该就能看到展示PHP的所有配置信息了。&lt;/p&gt;
&lt;h2&gt;访问出现An error occurred.&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3060-04.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;访问出现An error occurred.时&lt;/p&gt;
&lt;p&gt;确认Nginx配置里的PHP请求的处理方式部分下&lt;code&gt;fastcgi_param&lt;/code&gt;指令。（大概？&lt;/p&gt;
&lt;p&gt;&lt;code&gt;fastcgi_param&lt;/code&gt;指令用于设置发送到FastCGI服务器的参数&lt;/p&gt;
&lt;h2&gt;访问出现File not found.&lt;/h2&gt;
&lt;p&gt;确认输入的文件名...&lt;/p&gt;</content></entry><entry><title>移除安装编译好的 Node 版本以及卸载安装的 PHP 版本及其相关扩展</title><link href="https://www.moshanghua.net/archives/%E7%A7%BB%E9%99%A4%E5%AE%89%E8%A3%85%E7%BC%96%E8%AF%91%E5%A5%BD%E7%9A%84-node-%E7%89%88%E6%9C%AC.html" /><id>https://www.moshanghua.net/archives/%E7%A7%BB%E9%99%A4%E5%AE%89%E8%A3%85%E7%BC%96%E8%AF%91%E5%A5%BD%E7%9A%84-node-%E7%89%88%E6%9C%AC.html</id><updated>2024-04-18T02:16:38.000Z</updated><summary></summary><content type="html">&lt;p&gt;最近迁移网站，在服务器上安装了指定版本&lt;code&gt;Node&lt;/code&gt; 后，然后 &lt;code&gt;yarn&lt;/code&gt; 项目所需要的依赖文件时，报错模块与版本不兼容，提示版本过低，故而需要换版本。&lt;/p&gt;
&lt;p&gt;安装了编译好的 Node.js 版本，可以按照以下步骤来卸载它：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;找到 Node.js 安装目录&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;首先，需要找到 Node.js 的安装目录。如果是使用编译源代码的方式安装的 Node.js，会安装到 &lt;code&gt;/usr/local/bin&lt;/code&gt; 目录下。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;删除 Node.js 可执行文件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;删除 Node.js 的可执行文件。
这通常是 &lt;code&gt;node&lt;/code&gt; 和 &lt;code&gt;npm&lt;/code&gt;（或 &lt;code&gt;npx&lt;/code&gt;、&lt;code&gt;npm-cli.js&lt;/code&gt; 等）。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo rm /usr/local/bin/node
sudo rm /usr/local/bin/npm
sudo rm /usr/local/bin/npx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;删除 Node.js 替代链接（如果有）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果创建了符号链接到其他目录，如 &lt;code&gt;/usr/bin&lt;/code&gt;，也应该删除这些链接。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo rm /usr/bin/node
sudo rm /usr/bin/npm
sudo rm /usr/bin/npx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;删除 Node.js 的 man 页面（如果有）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果在安装过程中创建了 man 页面，也应该删除它们。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo rm -rf /usr/local/share/man/man1/node.1
sudo rm -rf /usr/local/share/man/man1/npm*.1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;删除 Node.js 的库文件&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;删除 Node.js 的库文件，这些文件通常位于 &lt;code&gt;/usr/local/lib&lt;/code&gt; 或 &lt;code&gt;/usr/lib&lt;/code&gt; 目录下。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo rm -rf /usr/local/lib/node*
sudo rm -rf /usr/lib/node*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;删除 Node.js 的配置文件（如果有）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果你在安装过程中创建了配置文件，也应该删除它们。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo rm -rf /etc/apt/sources.list.d/nodesource.list&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;删除 Node.js 的安装目录&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最后，删除 Node.js 的安装目录，通常是 &lt;code&gt;/usr/local/lib/nodejs&lt;/code&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo rm -rf /usr/local/lib/nodejs&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;清理 npm 缓存（可选）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果你想要彻底清理 Node.js 的痕迹，你也可以清理 npm 的缓存。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;npm cache clean --force&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;请注意，这些步骤假设你是以标准方式安装 Node.js，并且没有使用包管理器。&lt;/p&gt;
&lt;p&gt;清理了node 环境后，也记得把使用 npm 安装其他的全局命令清理一下，不然使用或者创建时会提示没有此类文件或目录存在。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;ln -s /root/node-v16.17.0-linux-x64/bin/yarn /usr/local/bin/yarn
ln: failed to create symbolic link &amp;#039;/usr/local/bin/yarn&amp;#039;: File exists

yarn
-bash: /usr/local/bin/yarn: No such file or directory&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;npm清理&lt;/h3&gt;
&lt;p&gt;如果你确定现有的链接是错误的或者已经过时了，你可以先删除它，然后创建一个新的链接。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;检查现有文件&lt;/strong&gt;：不确定是否应该删除链接，可以检查现有文件是否正确&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;cat /usr/local/bin/yarn&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这将显示文件的内容。如果它是一个有效的 &lt;code&gt;yarn&lt;/code&gt; 可执行文件，你可能不需要做任何事情。如果它不是，你可以删除它，然后创建符号链接。&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt;ls&lt;/code&gt;检查现有的链接更直观&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;ls -l /usr/local/bin/yarn
ls -l /usr/local/bin/pm2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这将显示链接当前指向的位置，打印出来的内容里node-v后面的数字就是版本，对应不上安装的就可以删了。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;ls -l /usr/local/bin/yarn
lrwxrwxrwx 1 root root 37 Apr 17 10:39 /usr/local/bin/yarn -&amp;gt; /root/node-v16.0.0-linux-x64/bin/yarn&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果确定可以安全地这样做，删除链接：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo rm /usr/local/bin/yarn
sudo rm /usr/local/bin/pm2
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;卸载安装的PHP 7.4及其相关扩展&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;列出已安装的PHP相关包&lt;/strong&gt;： 使用&lt;code&gt;apt&lt;/code&gt;命令列出所有与PHP 7.4相关的包：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo apt list --installed | grep php7.4&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;卸载PHP 7.4及其扩展&lt;/strong&gt;： 使用&lt;code&gt;apt&lt;/code&gt;命令卸载列出的所有PHP 7.4相关的包。您可以使用通配符&lt;code&gt;*&lt;/code&gt;来卸载所有相关的包：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo apt purge php7.4*&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者，您可以逐个卸载每个包：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo apt purge php7.4-common php7.4-mysql php7.4-xml php7.4-xmlrpc php7.4-curl php7.4-gd php7.4-imagick php7.4-cli php7.4-dev php7.4-imap php7.4-mbstring php7.4-opcache php7.4-soap php7.4-zip php7.4-fpm
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;删除多余的配置文件&lt;/strong&gt;： 卸载PHP包后，可能会有一些剩余的配置文件留在系统中。您可以使用以下命令来清理这些文件：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo apt autoremove
sudo apt autoclean&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;删除PPA源&lt;/strong&gt;： 如果您想要完全清理系统并且不打算再次使用ondrej/php存储库，您可以删除这个PPA源：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo add-apt-repository --remove ppa:ondrej/php&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;更新包列表&lt;/strong&gt;： 最后，更新您的包列表以确保所有更改都反映在系统中：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo apt update&lt;/code&gt;&lt;/pre&gt;</content></entry><entry><title>Ubuntu22.04下安装 Nginx 、 PHP 、 MySQL等服务</title><link href="https://www.moshanghua.net/archives/ubuntu22-04%E4%B8%8B%E5%AE%89%E8%A3%85-nginx-php-mysql-wordpress.html" /><id>https://www.moshanghua.net/archives/ubuntu22-04%E4%B8%8B%E5%AE%89%E8%A3%85-nginx-php-mysql-wordpress.html</id><updated>2024-04-17T12:28:35.000Z</updated><summary></summary><content type="html">&lt;h2&gt;基础环境&lt;/h2&gt;
&lt;p&gt;Ubuntu22.04&lt;/p&gt;
&lt;h2&gt;安装Nginx&lt;/h2&gt;
&lt;p&gt;如果不想要最新版的 &lt;code&gt;Nginx&lt;/code&gt;，可以直接执行  &lt;code&gt;sudo apt -y install nginx&lt;/code&gt; ,
Ubuntu 22.04使用 &lt;code&gt;apt&lt;/code&gt; 软件包管理器安装默认的是 nginx1.18 版本。&lt;/p&gt;
&lt;p&gt;想用 1.18 版本以上或以下指定版本可用以下方法。&lt;/p&gt;
&lt;h3&gt;通过apt命令安装指定版本&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1.更新Ubuntu系统内的软件包。&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt update&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2.添加 apt 源文件&lt;/strong&gt;
将 Nginx 的主线仓库添加到 &lt;code&gt;/etc/apt/sources.list&lt;/code&gt; 文件&lt;/p&gt;
&lt;p&gt;可以使用&lt;code&gt;tee&lt;/code&gt;命令将文本直接写入文件。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 备份源文件（可选）
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
# 编辑源文件
# 可以使用tee命令将文本直接写入文件
# 这里使用了 tee -a 命令，其中 -a 参数表示将内容追加到文件末尾，而不是覆盖现有文件。
# 添加二进制包仓库：
echo &amp;quot;deb http://nginx.org/packages/mainline/ubuntu/ jammy nginx&amp;quot; | sudo tee -a /etc/apt/sources.list

# 添加源代码仓库
echo &amp;quot;deb-src http://nginx.org/packages/mainline/ubuntu/ jammy nginx&amp;quot; | sudo tee -a /etc/apt/sources.list&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;说明：服务器Ubuntu版本是Ubuntu22.04(LTS)版的,所以系统代号是：jammy
如果要查看系统代号，使用命令 &lt;code&gt;lsb_release -c&lt;/code&gt; 或者 &lt;code&gt;lsb_release -cs&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;root@chixm: # lsb_release -c
Codename:       jammy

root@chixm: # lsb_release -cs
jammy&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3.导入nginx公钥&lt;/strong&gt;
因为在 Ubuntu 22.04 上导入 Nginx 官方公钥时，使用apt-key导入秘钥，会警告apt-key 命令已经不再被推荐使用。
所以可以使用gpg命令和相关的目录来管理密钥。
下载 Nginx 公钥： 可以使用 curl 或 wget 来下载公钥文件。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;## 使用 curl
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor &amp;gt; nginx.gpg

## 使用 wget
wget https://nginx.org/keys/nginx_signing.key -O - | gpg --dearmor &amp;gt; nginx.gpg&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再将公钥导入到 APT 密钥环&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo install -o root -g root -m 644 nginx.gpg /etc/apt/trusted.gpg.d/&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后，更新软件包列表以确保 APT 包管理器使用新的公钥。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt update&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;4.安装Nginx。&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 查看可安装的 nginx 版本
sudo apt-cache show nginx

#安装nginx 1.25.1
sudo apt-get install nginx=1.25.0-1~jammy

# 查看Nginx版本
sudo nginx -v&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;5.然后启动nginx&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo systemctl start nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3055-01.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如果有如下报错的话：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;Job for nginx.service failed because the control process exited with error code.
See &amp;quot;systemctl status nginx.service&amp;quot; and &amp;quot;journalctl -xeu nginx.service&amp;quot; for details.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;多半是内置的Apache抢占了nginx的端口，执行以下命令：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo systemctl stop apache2.service
sudo systemctl restart nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;6.nginx 部分配置与命令&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;使用systemctl命令控制服务：
设置开机启动： &lt;code&gt;sudo systemctl enable nginx&lt;/code&gt;
启动nginx：&lt;code&gt;sudo systemctl start nginx&lt;/code&gt;
停止nginx：&lt;code&gt;sudo systemctl stop nginx&lt;/code&gt;
重启nginx：&lt;code&gt;sudo systemctl restart nginx&lt;/code&gt;
查看状态：&lt;code&gt;sudo systemctl status nginx&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;配置路径：
nginx 配置文件目录: &lt;code&gt;/etc/nginx&lt;/code&gt; ;
配置文件：&lt;code&gt;/etc/nginx/conf.d/default.conf&lt;/code&gt;;
默认存放网站的目录：&lt;code&gt;/usr/share/nginx/html&lt;/code&gt;，如果需要更改目录修改配置文件的内容即可&lt;/p&gt;
&lt;h2&gt;安装 PHP&lt;/h2&gt;
&lt;p&gt;以下是安装不同版本的 PHP 和 一些常用扩展的方法步骤。&lt;/p&gt;
&lt;h3&gt;php7.4&lt;/h3&gt;
&lt;p&gt;使用的版本是7.4，就以这个版本操作。&lt;/p&gt;
&lt;p&gt;1.首先需要安装PHP的仓库：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt install software-properties-common&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2.然后添加ondrej/php存储库，它提供了多个PHP版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo add-apt-repository ppa:ondrej/php&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;出现 Press [ENTER] to continue or Ctrl-c to cancel. 时按回车继续。
注意：（ondrej/php）是第三方仓库，可能会带来一些风险，因为它不是Ubuntu官方维护的。如果介意，请安装 ubuntu 提供的默认版本 。&lt;/p&gt;
&lt;p&gt;3.再次更新安装包：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt update&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;4.然后就可以直接安装php7.4了！&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt install php7.4

# 这里如果需要php7.4-fpm服务，也可以直接用以下命令去安装，
# 该指令会直接安装包含 php 在内的 php7.4 和 php7.4-fpm
sudo apt install php7.4-fpm -y&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;5.安装PHP扩展（可以根据需要删减需要的）。
PHP 扩展的安装通常是以 php 开头，接着是版本号，然后是&lt;code&gt;-&lt;/code&gt;和扩展名称。格式&lt;code&gt;php7.4-[extname]&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;并不是所有 php 扩展都可以通过 apt 命令进行安装，Apt 仓库仅提供常用 PHP 扩展，某些扩展可能需要自己手动编译。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt install -y php7.4-common php7.4-mysql php7.4-xml php7.4-xmlrpc php7.4-curl php7.4-gd php7.4-imagick php7.4-cli php7.4-dev php7.4-imap php7.4-mbstring php7.4-opcache php7.4-soap php7.4-zip&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;6.安装 php-fpm&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;## 安装 PHP-FPM
sudo apt install php7.4-fpm&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在安装PHP扩展之后，重启PHP-FPM服务，否则新的PHP扩展不会加载到PHP-FPM。运行命令 &lt;code&gt;sudo systemctl restart php7.4-fpm&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;使用systemctl命令控制服务：
启动服务 &lt;code&gt; sudo systemctl start php7.4-fpm&lt;/code&gt;
开机自启动 &lt;code&gt;sudo systemctl enable php7.4-fpm&lt;/code&gt;
检查 PHP-FPM 服务状态  &lt;code&gt;sudo systemctl status php7.4-fpm&lt;/code&gt;
重新启动  &lt;code&gt;sudo systemctl restart php7.4-fpm&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;7.创建文件验证PHP安装&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;echo &amp;#039;&amp;lt;?php phpinfo(); ?&amp;gt;&amp;#039; | sudo tee /usr/share/nginx/html/info.php&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;phpinfo()函数会展示PHP的所有配置信息，然后写入到了info.php。(&lt;code&gt;测试完记得删除&lt;/code&gt;)&lt;/p&gt;
&lt;p&gt;再修改 nginx 配置文件以支持PHP，&lt;code&gt;/etc/nginx/conf.d/default.conf&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;server {
  listen 80;
  server_name localhost;
  # 网站根目录
  root /usr/share/nginx/html;

  location / {
    index index.php index.html index.htm;
    try_files $uri $uri/ /index.php?q=$uri&amp;amp;$args;
  }

  location ~ \.php$ {
    try_files $uri =404;
    include fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改Nginx配置文件后可以运行&lt;code&gt;nginx -t&lt;/code&gt;命令测试Nginx配置的语法是否正确。&lt;/p&gt;
&lt;p&gt;如果没有错误nginx会提示&lt;code&gt;nginx: configuration file /etc/nginx/nginx.conf test is successful&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;测试Nginx配置正确之后重启服务 &lt;code&gt;sudo systemctl restart nginx&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意：&lt;/strong&gt;
如果出现502 Bad Gateway。
检查 &lt;code&gt;PHP-FPM&lt;/code&gt; 的配置文件（路径通常位于 &lt;code&gt;/etc/php/7.4/fpm/pool.d/www.conf&lt;/code&gt; ），确认 &lt;code&gt;listen&lt;/code&gt; 指令是否正确设置为监听端口&lt;code&gt;9000&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;详细修改信息可以看文章 &lt;a href=&quot;https://moshanghua.net/details/3060&quot; title=&quot;迁移博客遇到的几个问题&quot;&gt;迁移博客遇到的几个问题&lt;/a&gt; 下的验证PHP安装提示 502&lt;/p&gt;
&lt;p&gt;再次访问应该就能看到展示PHP的所有配置信息了。
&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3055-02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;PHP8.1&lt;/h3&gt;
&lt;p&gt;Ubuntu 22.04 使用 &lt;code&gt;apt&lt;/code&gt; 软件包管理器安装默认的是 &lt;code&gt;PHP 8.1&lt;/code&gt; 版本。&lt;/p&gt;
&lt;h4&gt;1.运行以下命令，安装PHP。&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt -y install php-fpm&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;2.安装常用PHP扩展（例如：curl、gd、mbstring、mysql、xml、zip等）：&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo apt install php-curl php-gd php-mbstring php-mysql php-xml php-zip&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3.修改Nginx配置文件以支持PHP。&lt;/h4&gt;
&lt;p&gt;此步骤参考上文PHP7.4的安装步骤第7小节，创建文件验证PHP安装。&lt;/p&gt;
&lt;p&gt;使用systemctl命令控制服务：
启动服务 &lt;code&gt;sudo systemctl start php8.1-fpm&lt;/code&gt;
开机自启动 &lt;code&gt;sudo systemctl enable php8.1-fpm&lt;/code&gt;
检查 PHP-FPM 服务状态 &lt;code&gt;sudo systemctl status php8.1-fpm&lt;/code&gt;
重新启动 &lt;code&gt;sudo systemctl restart php8.1fpm&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;PHP8.2&lt;/h3&gt;
&lt;p&gt;在 Ubuntu 20.04 安装 PHP 8.2 和上文安装 php7.4 一样。&lt;/p&gt;
&lt;p&gt;需要做的就是启用 ondrej/php 存储库，并使用 &lt;code&gt;apt&lt;/code&gt; 安装 PHP 8.2。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo apt install software-properties-common
sudo add-apt-repository ppa:ondrej/php

sudo apt update
sudo apt install php8.2-fpm&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PHP 扩展的安装通常是以 php 开头，接着是版本号，然后是&lt;code&gt;-&lt;/code&gt;和扩展名称。格式&lt;code&gt;php8.2-[extname]&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;并不是所有php扩展都可以通过apt命令进行安装，Apt仓库仅提供常用PHP扩展，某些扩展可能需要自己手动编译。&lt;/p&gt;
&lt;p&gt;例如，要安装MySQL和GD扩展，您可以运行命令&lt;code&gt;sudo apt install php8.2-mysql php8.2-gd&lt;/code&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo apt update
sudo apt install php8.2-mysql php8.2-gd -y
sudo systemctl restart php8.2-fpm
sudo systemctl status php8.2-fpm&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;安装MySQL&lt;/h2&gt;
&lt;h3&gt;安装MySQL8.0&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;#
sudo apt -y install mysql-server

#查看MySQL版本
mysql -V&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;配置MySQL&lt;/h3&gt;
&lt;p&gt;进入MySQL&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo mysql&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;设置root用户密码&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ALTER USER &amp;#039;root&amp;#039;@&amp;#039;localhost&amp;#039; IDENTIFIED WITH mysql_native_password by &amp;#039;mynewpassword&amp;#039;;

## 密码以Mysql.1234为例
ALTER USER &amp;#039;root&amp;#039;@&amp;#039;localhost&amp;#039; IDENTIFIED WITH mysql_native_password by &amp;#039;Mysql.1234&amp;#039;;

## 退出MySQL数据库
exit;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;对MySQL进行安全性配置&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo mysql_secure_installation&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入root用户的密码。本示例中输入Mysql.1234&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sudo mysql_secure_installation

Securing the MySQL server deployment.

Enter password for user root:&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;配置说明（Yes | No 根据需要自行选择）：&lt;/strong&gt;
输入Y，设置密码验证策略&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;VALIDATE PASSWORD COMPONENT can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD component?

Press y|Y for Yes, any other key for No: Y&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;根据提示，选择密码验证策略。本示例输入2&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入Y，更改root用户密码。（根据需要，也可以不改）&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;Change the password for root ? ((Press y|Y for Yes, any other key for No) : Y&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入root用户密码。（如果跳过了上一步，这一步也不会出现）&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;New password:

Re-enter new password:

Estimated strength of the password:&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入Y，确认使用已设置的密码&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : Y&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入Y删除MySQL自带的匿名用户&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : Y&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入Y，禁止MySQL的root用户的远程登录权限。后面也可修改&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;Normally, root should only be allowed to connect from
&amp;#039;localhost&amp;#039;. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : Y&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入Y，移除test数据库。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;By default, MySQL comes with a database named &amp;#039;test&amp;#039; that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.

Remove test database and access to it? (Press y|Y for Yes, any other key for No) : &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入Y，重新加载授权表。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : Y&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当命令行回显All done!时，表示配置完成。&lt;/p&gt;
&lt;h3&gt;测试登录MySQL数据库。&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;## 登录MySQL数据库
sudo mysql -uroot -p&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;安装MySQL5.7&lt;/h3&gt;
&lt;p&gt;进入MySQL官方的Community Server选择历史版本：&lt;a href=&quot;https://downloads.mysql.com/archives/community/&quot;&gt;https://downloads.mysql.com/archives/community/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;1.&lt;strong&gt;下载tar包&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可以使用wget命令链接下载地址，也可以使用腾讯云提供的文件上传，将tar包放在Ubuntu的一个目录中&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;wget https://downloads.mysql.com/archives/get/p/23/file/mysql-server_5.7.42-1ubuntu18.04_amd64.deb-bundle.tar&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在目录下解压tar包&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;tar xvf mysql-server_5.7.42-1ubuntu18.04_amd64.deb-bundle.tar&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2.&lt;strong&gt;安装&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;安装依赖lib包&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo apt-get install ./libmysql*
sudo apt-get install libtinfo5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装客户端和服务端，按提示可能要先安装community版本&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo apt-get install ./mysql-community-client_5.7.42-1ubuntu18.04_amd64.deb
sudo apt-get install ./mysql-client_5.7.42-1ubuntu18.04_amd64.deb

#此步需要输入数据的root密码
sudo apt-get install ./mysql-community-server_5.7.42-1ubuntu18.04_amd64.deb

sudo apt-get install ./mysql-server_5.7.42-1ubuntu18.04_amd64.deb &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;过程中会提示设置MySQL的密码，用户名默认root
&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3055-03.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;3.启动MySQL&lt;/p&gt;
&lt;p&gt;对MySQL进行安全性配置&lt;/p&gt;
&lt;p&gt;配置说明见上文8.0部分&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo mysql_secure_installation&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;检查mysql服务状态&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;systemctl status mysql.service&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;出现下面界面说明安装成功&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;root@chixm: ~# systemctl status mysql.service
● mysql.service - MySQL Community Server
     Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2024-04-22 00:48:15 CST; 40s ago
    Process: 18203 ExecStartPre=/usr/share/mysql/mysql-systemd-start pre (code=exited, status=0/SUCCESS)
    Process: 18242 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid (code=exited, status=0/SUCC&amp;gt;
   Main PID: 18244 (mysqld)
      Tasks: 27 (limit: 1939)
     Memory: 170.5M
        CPU: 312ms
     CGroup: /system.slice/mysql.service
             └─18244 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid

Apr 21 00:48:14 iZ7xv436kce53s2t1abuavZ systemd[1]: Starting MySQL Community Server...
Apr 21 00:48:15 iZ7xv436kce53s2t1abuavZ systemd[1]: Started MySQL Community Server.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;至此MySQL5.7.42已经安装成功。&lt;/p&gt;
&lt;p&gt;登录MySQL&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;mysql -u root -p&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果不想使用终端管理 mysql，也可以使用图形界面 phpMyAdmin&lt;/p&gt;
&lt;h1&gt;安装 phpMyAdmin Nginx&lt;/h1&gt;
&lt;p&gt;当前phpMyAdmin稳定版本5.2.1。这里在Nginx的根目录安装phpMyAdmin。&lt;/p&gt;
&lt;p&gt;切换Nginx的默认根目录。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;cd /usr/share/nginx/html&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下载phpMyAdmin。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;wget https://files.phpmyadmin.net/phpMyAdmin/5.2.1/phpMyAdmin-5.2.1-all-languages.zip&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下载完成运行unzip命令解压缩phpMyAdmin源码。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo unzip phpMyAdmin-5.2.1-all-languages.zip&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重命名一下目录，配置时简短一点&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;mv phpMyAdmin-5.2.1-all-languages phpmyadmin&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;配置Nginx PhpMyAdmin&lt;/h2&gt;
&lt;p&gt;配置Nginx运行phpMyAdmin。&lt;/p&gt;
&lt;h3&gt;方法一：是使用Nginx的location来运行phpMyAdmin。&lt;/h3&gt;
&lt;p&gt;Nginx配置文件/etc/nginx/conf.d/default.conf&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;server {
    listen 80;
    listen 443 ssl http2;
    server_name xm.moshanghua.net;
    root /usr/share/nginx/html;

    location / {
        index index.php index.html index.htm;
        try_files $uri$uri/ /index.php?q=$uri&amp;amp;$args;
    }

    location /phpmyadmin/ {
        alias /usr/share/nginx/html/phpmyadmin/;# 注意末尾的斜杠
        index index.php index.html index.htm;
        try_files $uri $uri/ /phpmyadmin/index.php$is_args$args;
    }

    location ~ \.php$ {
        try_files $uri =404;
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    # 不想启用 HTTPS 就注释或者删除下面这段配置，上面的 listen 443 也注释掉
    # 引入证书文件开始
    ssl_certificate   /etc/nginx/ssl/xm.moshanghua.net.pem; #指定SSL证书文件路径。
    ssl_certificate_key  /etc/nginx/ssl/xm.moshanghua.net.key; # 指定SSL证书密钥文件路径。
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1;
    ssl_prefer_server_ciphers on;
    # 引入证书文件结束
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改配置后，&lt;code&gt;nginx -t&lt;/code&gt;命令测试Nginx配置的语法&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo systemctl restart nginx&lt;/code&gt;使nginx配置文件生效&lt;/p&gt;
&lt;p&gt;要访问phpMyAdmin界面，输入URL&lt;a href=&quot;https://xm.moshanghua.net/phpmyadmin/index.php&quot;&gt;https://xm.moshanghua.net/phpmyadmin/index.php&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3055-04.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在用户名字段中输入前面安装的数据库的用户名root或者设置名称，在密码字段中输入数据库的密码。&lt;/p&gt;
&lt;p&gt;然后登录后，就能看到phpMyAdmin面板。
&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3055-05.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;方法二：配置Nginx的Server块，通过独立子域名来运phpMyAdmin。&lt;/h3&gt;
&lt;p&gt;另外创建一个Nginx的Server块并配置独立的子域名。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;server {
    listen 80;
    listen 443 ssl http2;
    server_name phpmyadmin.moshanghua.net;
    root /usr/share/nginx/html/phpmyadmin;
    index index.php index.html index.htm;

    location ~ \.php$ {
        try_files $uri =404;
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    # 引入证书文件开始
    ssl_certificate   /etc/nginx/ssl/phpmyadmin.moshanghua.net.pem; #指定SSL证书文件路径。
    ssl_certificate_key  /etc/nginx/ssl/phpmyadmin.moshanghua.net.key; # 指定SSL证书密钥文件路径。
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1.3 TLSv1.2 TLSv1.1;
    ssl_prefer_server_ciphers on;
    # 引入证书文件结束

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修改配置后，&lt;code&gt;nginx -t&lt;/code&gt;命令测试Nginx配置的语法&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sudo systemctl restart nginx&lt;/code&gt;使nginx配置文件生效&lt;/p&gt;
&lt;p&gt;要访问phpMyAdmin界面，输入URL&lt;a href=&quot;https://phpmyadmin.moshanghua.net/index.php&quot;&gt;https://phpmyadmin.moshanghua.net/index.php&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3055-06.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;在用户名字段中输入前面安装的数据库的用户名root或者设置名称，在密码字段中输入数据库的密码。&lt;/p&gt;
&lt;p&gt;然后登录后，就能看到phpMyAdmin面板。
&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3055-07.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;几处配置&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3055-08.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;创建临时目录&lt;/h4&gt;
&lt;p&gt;变量 $cfg[&apos;TempDir&apos;] （/usr/share/nginx/html/phpmyadmin/tmp/）无法访问。phpMyAdmin无法缓存模板文件，所以会运行缓慢。&lt;/p&gt;
&lt;p&gt;解决此问题：&lt;/p&gt;
&lt;p&gt;1.&lt;strong&gt;确保临时目录存在&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;检查 &lt;code&gt;phpmyadmin/&lt;/code&gt; 目录下是否存在&lt;code&gt;/tmp&lt;/code&gt;目录，如果不存在，需要创建它：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo mkdir -p phpmyadmin/tmp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;确保 Nginx 用户（通常是 &lt;code&gt;www-data&lt;/code&gt;）有权限读写该临时目录。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo chown www-data:www-data phpmyadmin/tmp
sudo chmod 700 phpmyadmin/tmp&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2.&lt;strong&gt;配置 phpMyAdmin&lt;/strong&gt;：
复制 phpMyAdmin 目录下的示例配置文件并且重命名为config.inc.php来配置 phpMyAdmin，直接新建空白config.inc.php文件也可以。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sudo cp phpmyadmin/config.sample.inc.php phpmyadmin/config.inc.php&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要在 phpMyAdmin 的配置文件 &lt;code&gt;config.inc.php&lt;/code&gt; 末尾添加设置 &lt;code&gt;$cfg[&amp;#039;TempDir&amp;#039;]&lt;/code&gt;。
文件路径根据存放位置来写，本文存放在&lt;code&gt;/usr/share/nginx/html/&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 打开文件
sudo vim phpmyadmin/config.inc.php

# 末尾添加
$cfg[&amp;#039;TempDir&amp;#039;] = &amp;#039;/usr/share/nginx/html/phpmyadmin/tmp&amp;#039;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3.&lt;strong&gt;重启 Nginx 和 PHP-FPM&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;保存配置文件的更改，并重启 Nginx 和 PHP-FPM 以确保更改生效：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo systemctl restart nginx

# 对应自己安装的版本
sudo systemctl restart php7.4-fpm&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;设置一个 短语密码&lt;/h4&gt;
&lt;p&gt;从 phpMyAdmin 4.0.0 版本开始，&lt;code&gt;config.inc.php&lt;/code&gt; 配置文件支持使用短语密码（也称为“密码短语”或“passphrase”）来加密存储在配置中的敏感数据，如 &lt;code&gt;blowfish_secret&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;设置 &lt;code&gt;blowfish_secret&lt;/code&gt; 的步骤：&lt;/p&gt;
&lt;p&gt;1.&lt;strong&gt;生成加密密钥&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;生成一个随机的加密密钥：&lt;/p&gt;
&lt;p&gt;1.使用密码生成器成一个随机的密码短语。
&lt;a href=&quot;https://www.avast.com/zh-cn/random-password-generator&quot; title=&quot;随机密码生成器&quot;&gt;随机密码生成器&lt;/a&gt;
&lt;a href=&quot;https://ip.gs/password/&quot; title=&quot;Random Password Generator&quot;&gt;Random Password Generator&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2.使用命令行工具，如 &lt;code&gt;openssl&lt;/code&gt;：&lt;code&gt;openssl rand -base64 24&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;root@chixm:~# openssl rand -base64 24
Gt1jl6WQJy5HoUQcHp4+I0Y7Qfnfd+eu&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这将生成一个 24 字节的随机字符串，以 Base64 编码。&lt;/p&gt;
&lt;p&gt;2.&lt;strong&gt;编辑配置文件&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;将生成的加密密钥添加到您的 &lt;code&gt;config.inc.php&lt;/code&gt; 文件中，设置 &lt;code&gt;blowfish_secret&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$cfg[&amp;#039;blowfish_secret&amp;#039;] = &amp;#039;你生成的随机密码短语&amp;#039;;&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 打开编辑器
sudo vim phpmyadmin/config.inc.php

#添加一下配置到文件末尾
$cfg[&amp;#039;blowfish_secret&amp;#039;] = &amp;#039;Gt1jl6WQJy5HoUQcHp4+I0Y7Qfnfd+eu&amp;#039;; // 可以是任何随机字符串
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3.&lt;strong&gt;重启 Nginx 和 PHP-FPM&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;保存配置文件的更改，并重启 Nginx 和 PHP-FPM 以确保更改生效：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;sudo systemctl restart nginx

# 对应自己安装的版本
sudo systemctl restart php7.4-fpm&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;配置数据库 phpMyAdmin&lt;/h3&gt;
&lt;p&gt;报错下图信息是因为phpMyAdmin 需要数据库表。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3055-09.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3055-10.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;所以，要导入自带的 phpMyAdmin 归档包 create_tables.sql 来为 phpMyAdmin 创建表。&lt;/p&gt;
&lt;p&gt;使用 MySQL 客户端或 phpMyAdmin 登录到数据库服务器，创建数据库 &lt;code&gt;phpmyadmin&lt;/code&gt;，并导入create_tables.sql的数据。&lt;/p&gt;
&lt;p&gt;使用 MySQL 导入演示：
登录&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mysql -u root -p&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建数据库 phpmyadmin&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;CREATE DATABASE phpmyadmin;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;选择数据库，然后导入目录 &lt;code&gt;phpMyAdmin/sql&lt;/code&gt;下的 &lt;code&gt;create_tables.sql&lt;/code&gt; 这个库。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# 选择数据库
USE phpmyadmin;

# 导入数据
SOURCE /usr/share/nginx/html/phpmyadmin/sql/create_tables.sql;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;完整步骤：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;root@chixm:~ # mysql -u root -p

mysql&amp;gt; CREATE DATABASE phpmyadmin;
Query OK, 1 row affected (0.00 sec)

mysql&amp;gt; USE phpmyadmin;
Database changed
mysql&amp;gt; SOURCE /usr/share/nginx/html/phpmyadmin/sql/create_tables.sql;
Query OK, 1 row affected, 1 warning (0.00 sec)

Database changed
Query OK, 0 rows affected (0.01 sec)

Query OK, 0 rows affected (0.02 sec)

...

mysql&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时再刷新就没有错误提示了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/04/msh-3055-11.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;安装部署Node.js环境&lt;/h2&gt;
&lt;p&gt;演示版本&lt;code&gt;v16.17.0&lt;/code&gt;，更多版本访问官网 &lt;a href=&quot;https://nodejs.org/en&quot;&gt;Node.js&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;使用NVM安装管理多个Node.js版本&lt;/h3&gt;
&lt;p&gt;NVM（Node Version Manager）是Node.js的版本管理软件，可以轻松在Node.js各个版本间进行切换。
以下是简单的安装使用，更多信息可以前往 NVM 的 Github仓库进行查看&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/nvm-sh/nvm&quot;&gt;https://github.com/nvm-sh/nvm&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;安装 NVM&lt;/h3&gt;
&lt;p&gt;使用 cURL 或 Wget 命令：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行以下命令以加载 NVM 环境&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;export NVM_DIR=&amp;quot;$([ -z &amp;quot;${XDG_CONFIG_HOME-}&amp;quot; ] &amp;amp;&amp;amp; printf %s &amp;quot;${HOME}/.nvm&amp;quot; || printf %s &amp;quot;${XDG_CONFIG_HOME}/nvm&amp;quot;)&amp;quot;
[ -s &amp;quot;$NVM_DIR/nvm.sh&amp;quot; ] &amp;amp;&amp;amp; \. &amp;quot;$NVM_DIR/nvm.sh&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;验证 NVM 是否安装成功&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;nvm --version&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;使用 NVM 管理 Node.js 版本&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;查看可用的 Node.js 版本&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;通过以下命令查看所有可用的 Node.js 版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;nvm ls-remote&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;安装特定版本的 Node.js&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;例如，要安装最新的 LTS 版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;nvm install --lts&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;要安装其他特定版本，例如 &lt;code&gt;v16.17.0&lt;/code&gt; 版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;nvm install 16.17.0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;查看已安装的 Node.js 版本&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;使用以下命令查看系统中已安装的所有 Node.js 版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;nvm ls&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;切换 Node.js 版本&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;要切换到特定版本的 Node.js，例如切换到 &lt;code&gt;v16.17.0&lt;/code&gt; 版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;nvm use 16.17.0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;设置默认 Node.js 版本&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;要将某个版本设置为默认版本，例如设置  &lt;code&gt;v16.17.0&lt;/code&gt;  为默认版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;nvm alias default 16.17.0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;卸载 Node.js 版本&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;要卸载某个版本的 Node.js，例如卸载  &lt;code&gt;v16.17.0&lt;/code&gt;  版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;nvm uninstall 16.17.0&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;使用 Node.js 和 npm&lt;/h3&gt;
&lt;p&gt;使用以下命令来查看当前使用的 Node.js 和 npm 版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;node -v
npm -v&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;使用二进制文件安装&lt;/h2&gt;
&lt;p&gt;该方式使用的安装包是已编译好的二进制文件。解压文件之后，在bin文件夹中就已存在node和npm，无需重复编译。&lt;/p&gt;
&lt;p&gt;如果需要将该软件安装到其他目录下，又不想后期移动，可以先进入其目录下执行下载解压命令&lt;/p&gt;
&lt;p&gt;本文以安装Node.js &lt;code&gt;v16.0.0&lt;/code&gt;版本为例，且文件放在&lt;strong&gt;根目录&lt;/strong&gt;下。&lt;/p&gt;
&lt;p&gt;具体操作说明如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 进入根目录
cd ~

pwd
/root&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下载Node.js安装包。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;wget https://nodejs.org/dist/v16.17.0/node-v16.17.0-linux-x64.tar.xz&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解压Node.js安装包&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;tar xvf node-v16.17.0-linux-x64.tar.xz&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;创建node和npm的软链接。&lt;/p&gt;
&lt;p&gt;创建软链接后，您可以在任意目录下直接使用node和npm命令。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;ln -s /root/node-v16.17.0-linux-x64/bin/node /usr/local/bin/node
ln -s /root/node-v16.17.0-linux-x64/bin/npm /usr/local/bin/npm&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;至此，Node.js环境已安装完毕。软件默认安装在/root/node-v16.0.0-linux-x64/目录下。&lt;/p&gt;
&lt;h2&gt;参考文章 、资料&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://kimi.moonshot.cn/&quot;&gt;Kimi.ai&lt;/a&gt;
&lt;a href=&quot;https://blog.csdn.net/qq_36478642/article/details/125774344&quot; title=&quot;ubuntu 18.04 apt 升级 nginx 1.14 到 nginx 1.21.0&quot;&gt;ubuntu 18.04 apt 升级 nginx 1.14 到 nginx 1.21.0&lt;/a&gt;
&lt;a href=&quot;https://help.aliyun.com/zh/ecs/use-cases/build-an-lnmp-stack-on-a-ubuntu-instance&quot; title=&quot;手动部署LNMP环境（Ubuntu）&quot;&gt;手动部署LNMP环境（Ubuntu）&lt;/a&gt;
&lt;a href=&quot;https://www.cnblogs.com/DingyLand/p/17466734.html&quot;&gt;服务器Ubuntu Server 22.04安装低版本MySQL5.7&lt;/a&gt;
&lt;a href=&quot;https://cumi.co/20221006/&quot;&gt;https://cumi.co/20221006/&lt;/a&gt;
&lt;a href=&quot;https://www.myfreax.com/how-to-install-phpmyadmin-on-ubuntu-22-04-with-nginx/&quot;&gt;如何在Ubuntu 22.04安装 phpMyAdmin Nginx&lt;/a&gt;&lt;/p&gt;</content></entry><entry><title>服务器开荒指南</title><link href="https://www.moshanghua.net/archives/%E6%96%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%BC%80%E8%8D%92%E6%8C%87%E5%8D%97.html" /><id>https://www.moshanghua.net/archives/%E6%96%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%BC%80%E8%8D%92%E6%8C%87%E5%8D%97.html</id><updated>2024-04-16T02:28:05.000Z</updated><summary></summary><content type="html"></content></entry><entry><title>年末随笔：空虚与煎熬</title><link href="https://www.moshanghua.net/archives/%E6%80%8E%E6%A0%B7%E7%9A%842023.html" /><id>https://www.moshanghua.net/archives/%E6%80%8E%E6%A0%B7%E7%9A%842023.html</id><updated>2024-01-01T06:13:11.000Z</updated><summary></summary><content type="html">&lt;h2&gt;又是一年冬季 / 这一年的流水账&lt;/h2&gt;
&lt;p&gt;年底了，各种回顾一年总结性的东西也又陆续出来了。部分软件上开始推年度报告的页面，通过数据可视化的方式，让你看看你这一年在软件上都做了些什么。近期逛博客时，也看到部分博主有发布文章总结今年，展望2024。&lt;/p&gt;
&lt;p&gt;这不，看多了自己也就想瞎写点东西了，但自己并不是一个有仪式感的人，就抓住这股冲动劲记录一下。&lt;/p&gt;
&lt;p&gt;但简单地回忆，并没有记起多少事情，对于很多事和物，由于距离遥远已是模糊的，脑子里留下的更多是疲惫。&lt;/p&gt;
&lt;p&gt;想了很久无从下笔。没有总结性的东西，那就随便写一写，记录一下想法。&lt;/p&gt;
&lt;h2&gt;时间都去哪了  / 书影视听 / 统计&lt;/h2&gt;
&lt;h3&gt;聆听 / 音乐&lt;/h3&gt;
&lt;p&gt;这一年，邂逅新歌1143首，偏爱ilem教主的词和洛天依、祝眠的声音，再者就是歌手上新增了陈响，发现唱的部分作品也挺好听的。
然后，连续六年蝉联我年度歌手的马旭东变成了洛天依。
循环的多点的就是ilem写的《梦良衣》《上山岗》《白鸟过河摊》《四风判词》，以及今年天依出的几张专辑里的歌。
古风曲风上听的多的还是双笙 (陈元汐)和银临。
纯音乐上，吟唱，中国民族乐器，也挖掘出了原神的部分游戏纯音BGM。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/01/msh-2865-02.jpg&quot; alt=&quot;QQ音乐年度报告&quot; title=&quot;QQ音乐年度报告&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;关于视频 / 追剧 / 看番 / 看漫&lt;/h3&gt;
&lt;p&gt;这一年用的最多的是 B 站，看似没时间，这数据一出来，居然看了有400+小时的视频。（可怕~&lt;/p&gt;
&lt;p&gt;bilibili 账号等级在今年来到了 6 级，我也是个6级号了。&lt;/p&gt;
&lt;p&gt;年度 DNA：翻唱、你好生活第三季、虚拟歌手、虚拟 UP 主、手游直播&lt;/p&gt;
&lt;p&gt;感兴趣的综艺是&lt;a href=&quot;https://www.bilibili.com/bangumi/media/md28225593&quot; title=&quot;《你好生活！》&quot;&gt;《你好生活！》&lt;/a&gt;，这一年跳集前前后后依旧刷了好几遍，挺治愈的。七月中旬又开播了新一季&lt;a href=&quot;https://www.bilibili.com/bangumi/media/md20306033&quot; title=&quot;《你好生活 第四季》&quot;&gt;《你好生活 第四季》&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;一些观看过的视频稿件：
几个反复在刷的翻唱视频（莫名觉得好听）：
&lt;a href=&quot;https://www.bilibili.com/video/BV1FC4y1h7D7&quot; title=&quot;《江山无限》 不得不承认高手在民间！&quot;&gt;《江山无限》 不得不承认高手在民间！&lt;/a&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV1et4y157cw&quot; title=&quot;张朝阳版本《亲爱的那不是爱情》&quot;&gt;张朝阳版本《亲爱的那不是爱情》&lt;/a&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV1Ws411r71h&quot; title=&quot;【王健林】西海情歌 2015大连万达年会&quot;&gt;【王健林】西海情歌 2015大连万达年会&lt;/a&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV1ub411G7s9&quot; title=&quot;万达年会上王健林演唱《假行僧》&quot;&gt;万达年会上王健林演唱《假行僧》&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;东方甄选嘉宾访谈：
（因为看过这几位的作品，又刚好发现东方甄选还有相关的访谈，就...
&lt;a href=&quot;https://www.bilibili.com/video/BV1mg4y1M7HU&quot; title=&quot;渐冻症抗争者蔡磊对话东方甄选：苦难选中我们，请相信，我命由我不由天&quot;&gt;渐冻症抗争者蔡磊对话东方甄选：苦难选中我们，请相信，我命由我不由天&lt;/a&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV1Xb411o7zv/&quot; title=&quot;【官方高清版】盲人长笛演奏家吴晶对话俞敏洪、董宇辉：这命运但凡有剥夺，暗中皆有补偿&quot;&gt;【官方高清版】盲人长笛演奏家吴晶对话俞敏洪、董宇辉：这命运但凡有剥夺，暗中皆有补偿&lt;/a&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV1me411j7rs&quot; title=&quot;【官方字幕版】倪萍对话东方甄选：聊聊姥姥的质朴智慧&quot;&gt;【官方字幕版】倪萍对话东方甄选：聊聊姥姥的质朴智慧&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1m24y1a7Qk&quot; title=&quot;【官方字幕版】张朝阳对话东方甄选：追求使命感，实现人生意义，你会没有白来这一生&quot;&gt;【官方字幕版】张朝阳对话东方甄选：追求使命感，实现人生意义，你会没有白来这一生&lt;/a&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV1Px4y1j7XX&quot; title=&quot;《流浪地球2》导演郭帆，主演吴京、沙溢做客东方甄选直播间访谈全程&quot;&gt;《流浪地球2》导演郭帆，主演吴京、沙溢做客东方甄选直播间访谈全程&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;关于杨苡先生的两节采访：
年初看过她的书《一百年 那些人 那些事》，后知道的有采访
&lt;a href=&quot;https://www.bilibili.com/video/BV1wt4y1J7gX&quot; title=&quot;杨苡 翻译家｜每一天都要过得最好&quot;&gt;杨苡 翻译家｜每一天都要过得最好&lt;/a&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV1P84y177Pf&quot; title=&quot;吾家吾国｜独家专访百岁翻译家杨苡：“人生值得一过”&quot;&gt;吾家吾国｜独家专访百岁翻译家杨苡：“人生值得一过”&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/01/msh-2865-05.jpg&quot; alt=&quot;bilibili年度报告&quot; title=&quot;bilibili年度报告&quot; /&gt;&lt;/p&gt;
&lt;p&gt;看过的部分番剧：
《鬼灭之刃刀匠村篇》、《捡到退婚大小姐，教她幸福的事》
还在连载中的：
《咒术回战第二季》、《间谍过家家第二季》、&lt;a href=&quot;https://www.bilibili.com/bangumi/media/md21087073&quot; title=&quot;《葬送的芙莉莲》&quot;&gt;《葬送的芙莉莲》&lt;/a&gt;（好看！！）&lt;/p&gt;
&lt;p&gt;国创这一年里看过：
凡人系列&lt;a href=&quot;https://www.bilibili.com/bangumi/play/ep733316&quot; title=&quot;《凡人修仙传风起天南》（重制版）&quot;&gt;《凡人修仙传风起天南》（重制版）&lt;/a&gt;、&lt;a href=&quot;https://www.bilibili.com/bangumi/play/ep762895&quot; title=&quot;《凡人星海飞驰序章》&quot;&gt;《凡人星海飞驰序章》&lt;/a&gt;以及正在播的&lt;a href=&quot;https://www.bilibili.com/bangumi/play/ep785516&quot; title=&quot;《凡人修仙传星海飞驰（年番）》&quot;&gt;《凡人修仙传星海飞驰（年番）》&lt;/a&gt;
已完结的作品：
&lt;a href=&quot;https://www.bilibili.com/bangumi/play/ss44176&quot; title=&quot;《伍六七之暗影宿命》&quot;&gt;《伍六七之暗影宿命》&lt;/a&gt;，&lt;a href=&quot;https://www.bilibili.com/bangumi/play/ss43547&quot; title=&quot;《镇魂街第三季》&quot;&gt;《镇魂街第三季》&lt;/a&gt;，&lt;a href=&quot;https://www.bilibili.com/bangumi/play/ep754772&quot; title=&quot;《风灵玉秀第二章》&quot;&gt;《风灵玉秀第二章》&lt;/a&gt;，&lt;a href=&quot;https://www.bilibili.com/bangumi/play/ep759421&quot; title=&quot;《时光代理人第二季》&quot;&gt;《时光代理人第二季》&lt;/a&gt;，&lt;a href=&quot;https://www.bilibili.com/bangumi/play/ss26257&quot; title=&quot;《三体》&quot;&gt;《三体》&lt;/a&gt;，&lt;a href=&quot;https://www.bilibili.com/bangumi/play/ep682846&quot; title=&quot;《两不凝第二季》&quot;&gt;《两不凝第二季》&lt;/a&gt;，&lt;a href=&quot;https://www.bilibili.com/bangumi/play/ep763840&quot; title=&quot;《雾山五行 2 犀川幻紫林篇》&quot;&gt;《雾山五行 2 犀川幻紫林篇》&lt;/a&gt;......&lt;/p&gt;
&lt;p&gt;顺便记录一下持续再看的UP主：&lt;a href=&quot;https://space.bilibili.com/3379951&quot; title=&quot;ilem&quot;&gt;ilem&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/36081646&quot; title=&quot;洛天依&quot;&gt;洛天依&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/946974&quot; title=&quot;影视飓风&quot;&gt;影视飓风&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/125526&quot; title=&quot;-LKs-&quot;&gt;-LKs-&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/1895195099&quot; title=&quot;江寻千&quot;&gt;江寻千&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/275016013&quot; title=&quot;踢踢小鱼&quot;&gt;踢踢小鱼&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/52250&quot; title=&quot;视角姬&quot;&gt;视角姬&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/1950209&quot; title=&quot;水一大魔王&quot;&gt;水一大魔王&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/415405&quot; title=&quot;一夜北风吹&quot;&gt;一夜北风吹&lt;/a&gt;。
新增在某一段时间内看着或者持续再看：
&lt;a href=&quot;https://space.bilibili.com/10276136&quot; title=&quot;诺子喵呜&quot;&gt;诺子喵呜&lt;/a&gt;，一个盲人up主（一段时间没看，这涨粉速度，年初看着时好像10+w粉丝来着。
&lt;a href=&quot;https://space.bilibili.com/27717502&quot; title=&quot;时雨ioo&quot;&gt;时雨ioo&lt;/a&gt;，一个游戏up主，没玩游戏，说不上为什么就持续关注着了。
&lt;a href=&quot;https://space.bilibili.com/13926577&quot; title=&quot;昕有凌兮杂货铺&quot;&gt;昕有凌兮杂货铺&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/21317806&quot; title=&quot;Nic机长&quot;&gt;Nic机长&lt;/a&gt;，两位机长。
&lt;a href=&quot;https://space.bilibili.com/3461566945037260&quot; title=&quot;陈师傅开挖机&quot;&gt;陈师傅开挖机&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/410806558&quot; title=&quot;卡车拍档&quot;&gt;卡车拍档&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/270830584&quot; title=&quot;卡二代&quot;&gt;卡二代&lt;/a&gt;，挖掘机，卡车，内燃机的嘶吼
&lt;a href=&quot;https://space.bilibili.com/58078997&quot; title=&quot;polebug23&quot;&gt;polebug23&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/383038901&quot; title=&quot;锦堂生活空间&quot;&gt;锦堂生活空间&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/170029447&quot; title=&quot;饭饭麻麻菜菜&quot;&gt;饭饭麻麻菜菜&lt;/a&gt;，学习，vlog，记录
&lt;a href=&quot;https://space.bilibili.com/666759136&quot; title=&quot;渡一教育-提薪课&quot;&gt;渡一教育-提薪课&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/473631007&quot; title=&quot;程序员小山与Bug&quot;&gt;程序员小山与Bug&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/482867012&quot; title=&quot;吴悠讲编程&quot;&gt;吴悠讲编程&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/302954484&quot; title=&quot;峰华前端工程师&quot;&gt;峰华前端工程师&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/345880241&quot; title=&quot;好奇代码的三木&quot;&gt;好奇代码的三木&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/288339968&quot; title=&quot;PegasusWang&quot;&gt;PegasusWang&lt;/a&gt;，&lt;a href=&quot;https://space.bilibili.com/282616786&quot; title=&quot;DeeLMind&quot;&gt;DeeLMind&lt;/a&gt;，编程相关&lt;/p&gt;
&lt;p&gt;腾讯视频上，每一季的动漫都也有在看。
追了几年的《斗罗大陆》今年完结了，其实 &lt;del&gt;恋爱大陆&lt;/del&gt; 剧情已经没什么吸引力了，更像是一种习惯，一种有始有终的执念。
《斗破苍穹》本来也是很期待和小医仙的剧情的，但新一季年番播出到现在感觉越来越歪了。
然后国创这块，点开的大部分新漫，清一色不是索以文化就是若鸿文化制作...
值得一提的是，观感持续在线的&lt;a href=&quot;https://v.qq.com/x/cover/mcv8hkc8zk8lnov/x0036x5qqsr.html&quot; title=&quot;《完美世界》&quot;&gt;《完美世界》&lt;/a&gt;，复播的&lt;a href=&quot;https://v.qq.com/x/cover/324olz7ilvo2j5f/i00350r6rf4.html&quot; title=&quot;《吞噬星空》&quot;&gt;《吞噬星空》&lt;/a&gt;以及&lt;a href=&quot;https://v.qq.com/x/cover/mzc00200aaogpgh/r0047gdjpw6.html&quot; title=&quot;《仙逆》&quot;&gt;《仙逆》&lt;/a&gt;个人感觉都是很棒的作品！但仙逆不是年番作品，这季到现在已经快完结了。&lt;/p&gt;
&lt;p&gt;爱奇艺上的《大主宰年番》也在追着，目前感觉也还行。&lt;/p&gt;
&lt;p&gt;今年也看了很多漫画，多数在腾讯动漫和哔哩哔哩漫画上面看的，涉猎各种类型，作品略。&lt;/p&gt;
&lt;p&gt;最后，各平台放出的大量动漫 PV 预告里也看到了部分关注过的作品新作以及部分耳濡目染的的 IP，DNA 动了，期待上映中！&lt;/p&gt;
&lt;h3&gt;游戏&lt;/h3&gt;
&lt;p&gt;嗯...没玩过新游戏，游戏也没怎么玩，反正就好像是萎了什么游戏都玩不下去&lt;/p&gt;
&lt;p&gt;只和大肥在 欧卡 2 里一起跑过几趟运输
mc 今年也有去玩玩的，因为近几个月大肥又搭起了 Minecraft 服务器，还加了少量 mod
节奏大师也在年底公测上线了，又下载回来进去瞄了下，两年没打，整不会了&lt;/p&gt;
&lt;p&gt;然后就是有在关注主播看直播但没玩的游戏，和平精英，王者荣耀，原神。&lt;/p&gt;
&lt;h3&gt;阅读&lt;/h3&gt;
&lt;p&gt;这一年主要兴趣是在文学类，历史，小说上，阅读偏向故事类型的书，散文杂著，文学鉴赏，历史读物，历史小说，自传，外加网文小说等等。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/01/msh-2865-03.jpg&quot; alt=&quot;微信阅读年度报告&quot; title=&quot;微信阅读年度报告&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/01/msh-2865-04.jpg&quot; alt=&quot;微信年度榜单&quot; title=&quot;微信年度榜单&quot; /&gt;&lt;/p&gt;
&lt;p&gt;今年看的最多的仍旧是小说。年中又双叒叕刷了一遍《全职高手》，&lt;/p&gt;
&lt;p&gt;读《相信》《我听见这世界缤纷》《梦想永远不会太晚》让我进一步了解上了没怎么未关注的东西，渐冻症，盲人，话剧。&lt;/p&gt;
&lt;p&gt;部分书籍只是跳着翻了一半。&lt;/p&gt;
&lt;p&gt;读完念念不忘的一本书是《一百年，许多人，许多事：杨苡口述自传》，对民国的历史有了点兴趣。本书属于另类的民国历史，口述历史，有“碎碎念”的感觉，跟着杨先生的视角，仿佛穿越了几个时代，见证了无数人的人与事，看完，感觉自己也是挺“八卦”的。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;由作者的家境，到“西南联大”的学习经历。文中的大人物比比皆是，但于通常看的“大历史”来说，文中的人物更有生活气息，比如沈从文先生和张兆和请当时还是学生的杨先生吃林薇因带来的肉包子。尴尬闯女生宿舍的蒋校长。吴宓滴滴答答的拐杖声。巴金给鲁迅抬棺哭泣的样子。边讲话袖口边掉棉花的沈从文先生，以及沈从文对刚生完孩子的杨先生叮嘱“不能有了孩子就什么都放弃，还是要做事”......许多的轶事和大量的照片，丰富了对民国一角的认识。也从已经消逝了的时代日常生活的情形中感受时代变迁，触摸历史的温度。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;汪曾祺、杨振宁是她在西南联大的同学，沈从文、巴金是她一生的知己，《呼啸山庄》是她首创名字并翻译成中文的，她的丈夫赵瑞蕻翻译了小说《红与黑》，她的哥哥杨宪益和大嫂戴乃迭被认为是“翻译了整个中国的人”。&lt;/p&gt;
&lt;p&gt;基于杨苡的一百年，也去看了她最崇拜的哥der，看了自传，看了戴乃迭的两个祖国，然后也看到了赵蘅眼中的舅舅。&lt;/p&gt;
&lt;p&gt;有空，也还想读读沈从文先生，巴金，季羡林的文字，也想继续挖掘下西南联大相关的事迹。&lt;/p&gt;
&lt;h3&gt;浏览网页&lt;/h3&gt;
&lt;h3&gt;博客&lt;/h3&gt;
&lt;p&gt;博客存活时间又增加一年了，上半年不是很稳定，每个月博客都会掉线，具体表现为node进程占内存居高不下，一直90％往上，然后有时再高点进程就挂了…茫然啊，咱也不懂，就想着，既然是内存居高不下，那我把它拉一点起来呢？把原先的2H2G配置内存升了下变为2H4G……嗯，好像没挂服务了&lt;/p&gt;
&lt;p&gt;然后就是大肥搞了个自动化工作台，在大肥的帮助及操作下，我的友链添加服务也加入了期中。嗯，好处就是现在再有友链申请时不用再去打开后台复制粘贴内容然后更新了，直接工作台同意就自己写入数据库更新了！解放双手。&lt;/p&gt;
&lt;p&gt;友链上有变动，这一年里又离开了许多小伙伴。&lt;/p&gt;
&lt;p&gt;内容方面，这一年没写过什么，就这样了。&lt;/p&gt;
&lt;p&gt;在成本支出上，本博客花费 域名 + ECS 年付 700+的样子&lt;/p&gt;
&lt;p&gt;然后域名上，年底一时兴起购买了几个域名，并且手里的域名增加到了 6 个， 然后后缀方面涵盖了.net .com .cool .zone .group，后面几个后缀目前处于吃灰状态。&lt;/p&gt;
&lt;p&gt;服务器上除了博客的ECS，也还有在续费一个轻量服务器以及一个很久之前白菜价购买的虚拟机产品，但也都处于吃灰状态，挺浪费的。&lt;/p&gt;
&lt;h2&gt;我又在忙什么 / 想什么 / 变化 / 继续成长&lt;/h2&gt;
&lt;p&gt;不太好受的一年，无论是物理上，还是精神上，都让人产生一种想要出逃的冲动。
记忆力成直线的下滑，健忘……这种问题的严重程度就像从没有经历过这些事情一样。
时常情绪低落，胡思乱想。在精力有限，做不到我所想时，对自己丧失了信心。
状态特别差，工作是一团糟。
消费上依然没有节制，就没有多少积蓄。
学习上，没打鱼，晒了一年的网。&lt;/p&gt;
&lt;p&gt;茫然惊醒，一年又这样过去了，就自己好像一直在虚度光阴…&lt;/p&gt;
&lt;h3&gt;生活 / 健康 / 运动 / 社交 / 友情&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;面对未知与抉择，内心充满迷茫与焦虑，但也慢慢学会了逐渐应对和接受。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;目前的生活非常平淡，就像是游戏里的“NPC”，几乎每天都过得毫无新意，一年到头也不知道究竟干些什么有意义的事情，实在没什么可“总结”的。&lt;/p&gt;
&lt;p&gt;这一年也还是处于停止探索世界的状态，身在花都附近，却依旧没去附近转过。&lt;/p&gt;
&lt;p&gt;最大的变化大概就是换了个居住环境，22 年 11 月份的时候搬家了，从住了两年多的小巷子搬到了靠近主路边上的一公寓里 15 楼，站窗边看远处尽收眼底。（下定决心才搬的，搬家真麻烦，东西多了根本不想搬
从单间换到了一室一厅（住了近一年，又想换更大的了...
住高了唯一不足的就是停电或者电梯故障时了，回家就全靠爬楼梯了，概率虽小，但今年也有幸体验了一次，电梯进水故障，上下班爬了进一个星期的楼梯。真得劲...&lt;/p&gt;
&lt;p&gt;健康状态说不上，略过，精神状态以及睡眠情况不好，熬夜通宵能力状态什么的相比之前也下滑了（现在下半夜困的想原地躺下睡觉）。每天都是睡不饱睡不醒的样子，其精神状态严重影响日常。&lt;/p&gt;
&lt;p&gt;心理健康上，还不够成熟，还是不能控制好自己的情绪&lt;/p&gt;
&lt;p&gt;运动似乎没什么可写的，两点一线的日常里，始终都没有什么像样的运动，身体也因此每况愈下。&lt;/p&gt;
&lt;p&gt;今年下半年的平均睡眠时间是 5 小时 17 分。
不完全统计，全年一共走了 1,500,565 步，消耗 40, 492 卡路里。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/01/msh-2865-01.jpg&quot; alt=&quot;vivo健康&quot; title=&quot;vivo健康&quot; /&gt;&lt;/p&gt;
&lt;p&gt;我是&lt;code&gt;  I &lt;/code&gt; 人，和不熟的人聊天，三两句就能没下文了。
今年在社交上还是失败的，依然不善言辞，不主动。
所以，社交对我一直是件挺累的事。&lt;/p&gt;
&lt;p&gt;另外，值得高兴的是好兄弟在年底准备领证了，必须得狠狠地祝福一下！&lt;/p&gt;
&lt;h3&gt;工作那些事儿 / 变化&lt;/h3&gt;
&lt;p&gt;细想一下，工作上没什么可记录的，相反，总是因为工作上的事情而让自己郁郁寡欢、很少发自内心的笑。
主要，心态问题，这一年的工作状态极差，做事畏首畏尾，也没有了大的提升。&lt;/p&gt;
&lt;p&gt;当前工作不知道怎么说，有时想想，只要能心态摆正，感觉还是可以做下去，这操作对安于工作的话来说是一个好的状态吧，但是对于不安于这份工作来说又是一个不好的状态。&lt;/p&gt;
&lt;p&gt;嗯...所以计划是年后提桶跑路,不然磨磨蹭蹭又会是平平淡淡的一年。但其实也又纠结上了，辞职之后再做什么呢，想的越多可能越背离现实，嗯....辞了再说吧！&lt;/p&gt;
&lt;h3&gt;拥有了什么新东西 / 电子产品更新 / 消费&lt;/h3&gt;
&lt;p&gt;依然是没有节制地消费，不过买的东西已经不多了（该买的都买过了）
也买了几件新玩意，电子垃圾。&lt;/p&gt;
&lt;p&gt;vivo X100 Pro
Apple Mac Mini 八核 M2 芯片 16G + 512 丐版
vivo WATCH 2
微软Xbox游戏手柄
vivo Pad （2022年底）
IQUNIX OG 80 虫洞（2022年底）&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2024/01/msh-2865-06.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;其他物品&lt;/h4&gt;
&lt;p&gt;一张床垫
米家智能调香机
米家智能设备/传感器若干
实体书籍若干本【文学类，编程类，设定集，（插）画集，漫画】
BEMOE 《无尽蓝》Vsinger 洛天依 十周年专辑礼盒
Swift Block 超感华容道
GAN 14 Maglev_UV版&lt;/p&gt;
&lt;h4&gt;软件 / 订阅服务&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;部分工具列表，使用迭代和优化调整中...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;翻译：Bob
下载：Downie4
PDF+吃灰：UPDF&lt;/p&gt;
&lt;p&gt;Word：office 365
提醒、记录、导图工具：滴答清单
文字摘抄、想法记录：Flomo
笔记记录：Wolai
读书：微信读书、QQ 读书、番茄、七猫小说，实体书（20%）&lt;/p&gt;
&lt;p&gt;云服务：阿里云轻量应用服务器 2H2G30M 港区、 ECS 2H4G2M&lt;/p&gt;
&lt;p&gt;......&lt;/p&gt;
&lt;h4&gt;放弃购物&lt;/h4&gt;
&lt;p&gt;白白浪费定金系列，买来包装太大没地方放（开头嫌弃地方小的原因之一），然后，有离开这城的想法了，跨省搬运感觉麻烦...&lt;/p&gt;
&lt;p&gt;然后，BEMOE Vsinger 全员专辑《NoisyWorld》 CD版&amp;amp;珍藏白胶版忘记补款了...&lt;/p&gt;
&lt;p&gt;部分截图：
&lt;img src=&quot;https://assets.moshanghua.net/images/2024/01/msh-2865-07.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;钱去哪了&lt;/h3&gt;
&lt;p&gt;自己一个人，谈不上好好生活，也没有柴米油盐的概念，（之前）买东西不太会过多思考到底是否真的需要，每次都是念起然后就消费。这不，一年下来，依旧是没有多少的存款&lt;/p&gt;
&lt;p&gt;最近有想，真发生什么事，手里的数又能做什么呢。&lt;/p&gt;
&lt;p&gt;来年，消费观上要更加理性，尝试记账，珍惜财务支出的每一分。&lt;/p&gt;
&lt;h3&gt;学习 / 技术成长 / GTD / 知识管理&lt;/h3&gt;
&lt;p&gt;今年因为工作上的原因，还有个人懒散了，学习这件事上，其实最近几年基本上都没有学到什么东西，很少时间能沉下心研究一会东西。
技术学习停留在看，没有学和写，思考什么的就更没有了。&lt;/p&gt;
&lt;p&gt;再者，阅读，书架上的书很多，读完的很少。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Henry：“学技术，除了工作，不就是服务自己了嘛”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;大肥的这句话，听了若有所思，准备随性而为地学习了解一些新东西，如果能学以致用那就更好了。&lt;/p&gt;
&lt;p&gt;比如今年在掘金上看到 &lt;a href=&quot;https://github.com/chokcoco&quot; title=&quot;coco大佬&quot;&gt;coco大佬&lt;/a&gt;和&lt;a href=&quot;https://www.w3cplus.com/&quot; title=&quot;大漠老师&quot;&gt;大漠老师&lt;/a&gt;出的几本关于 &lt;a href=&quot;https://juejin.cn/course/frontend?query=CSS&quot; title=&quot;CSS 的小册&quot;&gt;CSS 的小册&lt;/a&gt;后，又燃起了我想捣鼓 CSS 的兴趣了。还有 &lt;a href=&quot;https://github.com/alphardex&quot; title=&quot;alphardex&quot;&gt;alphardex&lt;/a&gt; 的 &lt;a href=&quot;https://juejin.cn/book/7267462574734573604&quot; title=&quot;WebGL Shader 魔法指南&quot;&gt;WebGL Shader 魔法指南&lt;/a&gt;，好炫酷的感觉。&lt;a href=&quot;https://juejin.cn/user/2788017216685118&quot; title=&quot;神光&quot;&gt;神光&lt;/a&gt;也是有在关注的一个大佬，但他出的几本&lt;a href=&quot;https://juejin.cn/user/2788017216685118/course&quot; title=&quot;小册&quot;&gt;小册&lt;/a&gt;，暂时用不上。&lt;/p&gt;
&lt;p&gt;贴几个CodePen地址：
&lt;a href=&quot;https://codepen.io/airen&quot; title=&quot;大漠 on CodePen&quot;&gt;大漠 on CodePen&lt;/a&gt;：CSS
&lt;a href=&quot;https://codepen.io/Chokcoco&quot; title=&quot;Chokcoco on CodePen&quot;&gt;Chokcoco on CodePen&lt;/a&gt;：CSS
&lt;a href=&quot;https://codepen.io/alphardex&quot; title=&quot;alphardex on CodePen&quot;&gt;alphardex on CodePen&lt;/a&gt;：WebGL&lt;/p&gt;
&lt;p&gt;其他：
&lt;a href=&quot;https://csscoco.com/inspiration/#/&quot; title=&quot;CSS Inspiration -- CSS灵感&quot;&gt;CSS Inspiration -- CSS灵感&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;然后看过大肥日常发的部分渡一讲的碎片化知识，对出的一套教程也有想法...华峰，三木，依力等等，又贪多空想了不是... [ 别想了. jpg ]，越想越发现自己什么都没做。&lt;/p&gt;
&lt;p&gt;另外，就是记忆差，健忘，需要东西时想不起，在尝试所谓的知识管理，用工具构建个人知识合集。但目前还谈不上知识管理，既还没探索好工具的使用，也没有多少知识管理。&lt;/p&gt;
&lt;h3&gt;情绪 / 精神状态 / 改变 / 一些感想&lt;/h3&gt;
&lt;p&gt;自己在情绪管理做的挺差的，没有太多的情绪调节能力，就这一年里经常挂着情绪，可能由于对未来生活的恐惧，也不太能接受过于平庸的自己，就时常焦躁也有很重的悲观情绪，更多的是一些精神内耗。回顾整年，几乎想不起有哪些瞬间是让我感到过高兴的。&lt;/p&gt;
&lt;p&gt;更割裂的是，我觉得很忙，又不知道在忙什么，看不到什么成果，毫无成就感。或许高估了自己，总想着短期能做多少事，而低估自己一年可以完成的事。
因为短期的目标明确，可执行力强，而长期的事模糊的，看不清，认不清自己到底想要做什么，就导致一年就那么嘘嘘晃晃的过去，什么都想做，什么都没做、
不知不觉就产生了急于求成的心理，然后就过分焦虑。就经常在（欲望过多+能力不足+高估自己=痛苦）【痛苦——解决问题——解决不了——痛苦】的死循环中。&lt;/p&gt;
&lt;p&gt;为什么把自己搞成这样。
过一下自己的想法，欲望，需求...想的多，而能力跟不上，然后就焦虑（痛苦）上了，但自己面对焦虑，总很自责。&lt;/p&gt;
&lt;p&gt;焦虑好像是我们的天性，是出厂默认设置，所有人都会焦虑
人，天生就喜欢避难趋易、喜欢急于求成，想同时做很多事，想不用怎么努力就成功。
焦虑的根源，说的再直白一点就是，想同时做很多事，又想立即看到效果，但无能（没有能力）。&lt;/p&gt;
&lt;p&gt;相比面对焦虑自责，看清自己背后的欲望并设法改变才是下一步。
克制欲望，不要让自己同时做很多事。想那么多也没用，因为根本就没时间，这个没时间是事实，不是借口。
在没时间的前提下，想的越多，痛苦越大。
面对现实，看清自己真实的能力水平。先接受自己，承认自己现在确实很弱，这是现实，接受这个现实，然后在这个基础上，去做，去行动。&lt;/p&gt;
&lt;p&gt;当自己真在做一件事时，还是没有内耗的。所以，目前大体思路是让自己更充实一点。
未来，去做，去做，去做，关上脑子开始行动，脑子里的东西，都只是在纸上谈兵。&lt;/p&gt;
&lt;h2&gt;2024，关于新的一年&lt;/h2&gt;
&lt;p&gt;具体的 flag 就不立了，暂时也没有任何长远计划，即便制定了计划，也很难如期执行，只要慢慢改变自己的想法，融入在日常的每一天就好了。&lt;/p&gt;
&lt;p&gt;如果有可能，还是希望新的一年可以去开阔一下自己的视野，增长一些见识，也希望自己能以相对松弛的态度面对未来，然后再让生活丰富一些。如果做不到，来年继续再改变吧。&lt;/p&gt;
&lt;p&gt;最后，断断续续改写了这一堆废话和负能量的东西，因有些东西想着但表达转述不出来，写的很乱，就当胡言乱语吧，反正没人看。
又或者，也很感谢网络对面的你愿意停留看我唠叨这糟糕的故事。
祝新年快乐！望在新年里一切顺利，保持好运！有更多的精彩等着我们。&lt;/p&gt;
&lt;p&gt;初稿于 2024 / 01 / 01 中午
最后修改于  2024 / 01 / 20&lt;/p&gt;</content></entry><entry><title>2024，新年快乐~</title><link href="https://www.moshanghua.net/archives/%E5%8D%81%E4%B8%80%E6%9C%88.html" /><id>https://www.moshanghua.net/archives/%E5%8D%81%E4%B8%80%E6%9C%88.html</id><updated>2024-01-01T03:59:11.000Z</updated><summary></summary><content type="html">&lt;h2&gt;新年快乐~&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/bangumi/play/ep809625&quot; title=&quot;献给多彩的民族瑰宝! 洛天依龚琳娜《歌行四方》&quot;&gt;献给多彩的民族瑰宝! 洛天依龚琳娜《歌行四方》&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/bangumi/play/ep797486&quot; title=&quot;2023最美的夜 bilibili晚会&quot;&gt;2023最美的夜 bilibili晚会&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/tianyi/Shintani/0ff468bbed941f443c3a71652eea433a3557283.jpg&quot; alt=&quot;洛天依&quot; title=&quot;洛天依&quot; /&gt;
图片来源动态&lt;a href=&quot;https://www.bilibili.com/opus/881328354295283749&quot;&gt;https://www.bilibili.com/opus/881328354295283749&lt;/a&gt; ，&lt;/p&gt;
&lt;h2&gt;画师id&lt;/h2&gt;
&lt;p&gt;感谢深谷老师的画作~ 并允许使用~
B站id：&lt;a href=&quot;https://space.bilibili.com/3557283&quot;&gt;@深谷Shintani&lt;/a&gt;
微博id：&lt;a href=&quot;https://weibo.com/u/3875024604&quot;&gt;@深谷-shintani&lt;/a&gt;&lt;/p&gt;</content></entry><entry><title>配置使用 Tmux</title><link href="https://www.moshanghua.net/archives/%E5%8D%8E%E5%AE%B9%E9%81%93.html" /><id>https://www.moshanghua.net/archives/%E5%8D%8E%E5%AE%B9%E9%81%93.html</id><updated>2023-11-15T02:47:12.000Z</updated><summary></summary><content type="html">&lt;h2&gt;安装&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;brew install tmux

# 查看版本
tmux -V&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;基础配置&lt;/h2&gt;
&lt;p&gt;部分参数&lt;/p&gt;
&lt;p&gt;&lt;code&gt;set -g&lt;/code&gt;：全局设置，适用于所有窗口。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;bind&lt;/code&gt; 命令用于绑定键盘快捷键以执行特定命令，后面可以跟一些参数，&lt;/p&gt;
&lt;p&gt;&lt;code&gt;bind -n&lt;/code&gt; ：不使用前缀键。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;bind -r&lt;/code&gt; ：允许重复按键。（即，长按快捷键可以连续执行命令）&lt;/p&gt;
&lt;p&gt;&lt;code&gt;unbind&lt;/code&gt; ：解除已绑定的键盘快捷键&lt;/p&gt;
&lt;p&gt;&lt;code&gt;unbind -n&lt;/code&gt; ：解除不带前缀键的绑定&lt;/p&gt;
&lt;p&gt;&lt;code&gt;unbind -a&lt;/code&gt; ：移除所有通过 &lt;code&gt;bind&lt;/code&gt; 命令设置的键绑定&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;prefix&lt;/code&gt;前缀键设置&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;set -g prefix2 C-s
bind C-s send-prefix -2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;set -g prefix2 C-s&lt;/code&gt;: 这行配置将 tmux 的第二个前缀键设置为 &lt;code&gt;C-s&lt;/code&gt;（即 &lt;code&gt;Ctrl-s&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;在这里，&lt;code&gt;prefix2&lt;/code&gt; 表示第二个前缀键，意味着可以使用 &lt;code&gt;C-b&lt;/code&gt; 或 &lt;code&gt;C-s&lt;/code&gt; 作为前缀键来执行 tmux 的命令。&lt;/p&gt;
&lt;h3&gt;按键延迟&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# prefix 延迟时间，按下 Ctrl-b 之后立即响应
set -s escape-time 10
# 组合按键时间间隔
set -sg repeat-time 600 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;默认情况下，tmux 等待 &lt;code&gt;Escape&lt;/code&gt; 键的时间为 500 毫秒。在一些情况下，将此时间设置为 10 毫秒可以加快命令序列的处理速度，使 tmux 更加响应迅速。&lt;/p&gt;
&lt;p&gt;按键时间间隔，默认时间也是 500 毫秒。将其增加到 600 毫秒可以让用户在快速按两次前缀键时有更多的时间间隔。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;历史记录限制&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;将历史记录限制增加到 5000 行，以便在 tmux 中保存更多的命令行输出历史。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;set -g history-limit 5000&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;tmux 的显示设置&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 将窗口编号从 1 开始（默认是从 0 开始）
set -g base-index 1   
# 将面板编号与窗口编号一致，也从 1 开始（默认是从 0 开始）        
setw -g pane-base-index 1     

# 自动重命名窗口
setw -g automatic-rename on   
# 关闭窗口时重新编号剩余的窗口
set -g renumber-windows on
# 关闭最后一个窗口，tmux 会话自动退出
set -sg exit-empty on    

# 设置终端标题为当前窗口名称
set -g set-titles on          

# 设置 pane 显示时间
set -g display-panes-time 2000
# 设置消息显示时间
set -g display-time 2000            

# 状态栏刷新间隔
set -g status-interval 10    

# 清屏和历史记录
bind -n C-l send-keys C-l \; run &amp;#039;sleep 0.2&amp;#039; \; clear-history

# 禁用活动监控
set -g monitor-activity off
# 禁用视觉提示
set -g visual-activity off
# 禁用铃声提示
setw -g monitor-bell off

# 允许鼠标控制
set -g mouse on
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;会话相关&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;unbind [
unbind ]

# 创建会话
bind C-c new-session
# 查看会话
bind ] choose-session
# 打开会话和窗口树选择菜单并启用缩放
bind W choose-tree -Z

# 快速关闭会话
unbind C-x
bind-key -n C-x switch-client -T kill-session-mode

bind-key -T kill-session-mode 1 kill-session -t 1
bind-key -T kill-session-mode 2 kill-session -t 2
bind-key -T kill-session-mode 3 kill-session -t 3
bind-key -T kill-session-mode 4 kill-session -t 4
bind-key -T kill-session-mode 5 kill-session -t 5
bind-key -T kill-session-mode 6 kill-session -t 6
bind-key -T kill-session-mode 7 kill-session -t 7
bind-key -T kill-session-mode 8 kill-session -t 8
bind-key -T kill-session-mode 9 kill-session -t 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;bind BTab&lt;/code&gt;：绑定 &lt;code&gt;Shift-Tab&lt;/code&gt; 键（在 tmux 中，&lt;code&gt;B&lt;/code&gt; 表示 &lt;code&gt;Shift&lt;/code&gt; 键）。&lt;code&gt;switch-client -l&lt;/code&gt;：切换到上一个会话。&lt;/p&gt;
&lt;p&gt;通过按 &lt;code&gt;Shift-Tab&lt;/code&gt; 键，用户可以快速切换到上一个使用的 tmux 会话。&lt;/p&gt;
&lt;h3&gt;窗口导航&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 切换到上一个窗口
bind -r C-h previous-window
# 切换到下一个窗口
bind -r C-l next-window&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后定义了一组用于快速选择窗口的按键，由于想简化下按键次数，把数字1~9设置在多组命令上执行，这里设置一组专用于 &lt;code&gt;select-window&lt;/code&gt; 的前缀键&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;unbind C-g
bind-key -n C-g switch-client -T select-window-mode&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;解绑 &lt;code&gt;C-g&lt;/code&gt;，然后绑定 &lt;code&gt;C-g&lt;/code&gt; 来激活 &lt;code&gt;select-window-mode&lt;/code&gt; 键表&lt;/p&gt;
&lt;p&gt;创建并绑定 &lt;code&gt;select-window-mode&lt;/code&gt; 键表并绑定相应的按键命令&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt; select-window 默认设置方法&lt;/summary&gt;
&lt;pre class=&quot;language-Bash line-numbers&quot;&gt;&lt;code class=&quot;language-Bash&quot;&gt;
# 快速选择窗口
bind 1 select-window -t 1
bind 2 select-window -t 2
bind 3 select-window -t 3
bind 4 select-window -t 4
bind 5 select-window -t 5
bind 6 select-window -t 6
bind 7 select-window -t 7
bind 8 select-window -t 8
bind 9 select-window -t 9
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 快速选择窗口
bind-key -T select-window-mode 1 select-window -t 1
bind-key -T select-window-mode 2 select-window -t 2
bind-key -T select-window-mode 3 select-window -t 3
bind-key -T select-window-mode 4 select-window -t 4
bind-key -T select-window-mode 5 select-window -t 5
bind-key -T select-window-mode 6 select-window -t 6
bind-key -T select-window-mode 7 select-window -t 7
bind-key -T select-window-mode 8 select-window -t 8
bind-key -T select-window-mode 9 select-window -t 9&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同上，这里设置一组专属于  &lt;code&gt;join-pane&lt;/code&gt; 的前缀键，用于快速将单前窗格加入窗口的按键&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 将当前窗格加入指定窗口
unbind C-a
bind-key -n C-a switch-client -T join-pane-mode&lt;/code&gt;&lt;/pre&gt;
&lt;details&gt;
&lt;summary&gt;join-pane  默认设置方法&lt;/summary&gt;
&lt;pre class=&quot;language-Bash line-numbers&quot;&gt;&lt;code class=&quot;language-Bash&quot;&gt;
# 将当前窗格加入指定窗口
bind &apos;!&apos; join-pane -t :1
bind &apos;@&apos; join-pane -t :2
bind &apos;#&apos; join-pane -t :3
bind &apos;$&apos; join-pane -t :4
bind &apos;%&apos; join-pane -t :5
bind &apos;^&apos; join-pane -t :6
bind &apos;&amp;&apos; join-pane -t :7
bind &apos;*&apos; join-pane -t :8
bind &apos;(&apos; join-pane -t :9
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;bind-key -T join-pane-mode 1 join-pane -t :1
bind-key -T join-pane-mode 2 join-pane -t :2
bind-key -T join-pane-mode 3 join-pane -t :3
bind-key -T join-pane-mode 4 join-pane -t :4
bind-key -T join-pane-mode 5 join-pane -t :5
bind-key -T join-pane-mode 6 join-pane -t :6
bind-key -T join-pane-mode 7 join-pane -t :7
bind-key -T join-pane-mode 8 join-pane -t :8
bind-key -T join-pane-mode 9 join-pane -t :9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过按 &lt;code&gt;Ctrl-h&lt;/code&gt; 键，可以快速切换到上一个窗口。&lt;/p&gt;
&lt;p&gt;通过按 &lt;code&gt;Ctrl-l&lt;/code&gt; 键，可以快速切换到下一个窗口。&lt;/p&gt;
&lt;p&gt;通过 &lt;code&gt;Ctrl-g&lt;/code&gt; + 数字键快速切换到指定窗口。例如，按 &lt;code&gt;Ctrl-g&lt;/code&gt; + &lt;code&gt;1&lt;/code&gt; 切换到窗口 1。&lt;/p&gt;
&lt;p&gt;通过 &lt;code&gt;Ctrl-a&lt;/code&gt; + 数字键将当前窗格加入到指定窗口。例如，按 &lt;code&gt;Ctrl-a&lt;/code&gt; + &lt;code&gt;1&lt;/code&gt;  将当前窗格加入到窗口 1。&lt;/p&gt;
&lt;p&gt;和上面&lt;code&gt;join-pane&lt;/code&gt; 差不多的功能，也是将窗格移动到某个窗口，但这个还可以跨会话移动&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 打开会话和窗口树选择窗格并垂直移动面板
bind S choose-tree &amp;#039;move-pane -v -s &amp;quot;%%&amp;quot;&amp;#039;
# 打开会话和窗口树选择窗格并水平移动面板
bind V choose-tree &amp;#039;move-pane -h -s &amp;quot;%%&amp;quot;&amp;#039;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;choose-tree&lt;/code&gt;：打开会话和窗口树选择菜单。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;#039;move-pane -v -s &amp;quot;%%&amp;quot;&amp;#039;&lt;/code&gt;：选择后执行 &lt;code&gt;move-pane&lt;/code&gt; 命令，将选中的窗口垂直移动到当前面板。&lt;code&gt;%%&lt;/code&gt; 是一个 tmux 内部的占位符，用于表示选择的目标。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-v&lt;/code&gt;：将选中的窗格垂直移动到当前面板。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-h&lt;/code&gt;：将选中的窗格水平移动到当前面板。&lt;/p&gt;
&lt;h3&gt;窗格导航&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 垂直拆分，新的窗格位于当前窗格之上。
bind / split-window -vb
# 垂直拆分，新的窗格位于当前窗格之下。
bind ? split-window -v
# 水平拆分，新的窗格位于当前窗格之左
bind &amp;lt; split-window -hb
# 水平拆分，新的窗格位于当前窗格之右
bind &amp;gt; split-window -h&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过 &amp;gt; 和 &amp;lt; 键快速交换窗口位置，从而方便地调整窗口布局。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 选择左侧的窗格
bind -r h select-pane -L  
# 选择下方的窗格
bind -r j select-pane -D  
# 选择上方的窗格
bind -r k select-pane -U  
# 选择右侧的窗格
bind -r l select-pane -R  
# 快速选择窗格
bind 1 select-pane -t:.1
bind 2 select-pane -t:.2
bind 3 select-pane -t:.3
bind 4 select-pane -t:.4
bind 5 select-pane -t:.5
bind 6 select-pane -t:.6
bind 7 select-pane -t:.7
bind 8 select-pane -t:.8
bind 9 select-pane -t:.9
bind 0 select-pane -t:.10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些快捷键绑定将 &lt;code&gt;h&lt;/code&gt;、&lt;code&gt;j&lt;/code&gt;、&lt;code&gt;k&lt;/code&gt;、&lt;code&gt;l&lt;/code&gt; 键用作窗格导航键，类似于 Vim 的导航方式，就可以更方便地在不同窗格之间移动。&lt;/p&gt;
&lt;p&gt;通过 &lt;code&gt;&amp;lt;prefix&amp;gt;&lt;/code&gt; + 数字键快速切换到指定窗格。例如，按 &lt;code&gt;Ctrl-b&lt;/code&gt; + &lt;code&gt;1&lt;/code&gt; 或者&lt;code&gt;Ctrl-s&lt;/code&gt; + &lt;code&gt;1&lt;/code&gt;切换到窗格 1。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 将当前窗格与下方的窗格交换位置
bind &amp;#039;)&amp;#039; swap-pane -D
# 将当前窗格与上方的窗格交换位置   
bind &amp;#039;(&amp;#039; swap-pane -U
# 切换到下一个窗格布局
bind -n C-u next-layout
# 创建新窗口，路径为当前 pane 的路径
bind -n C-p new-window -c &amp;quot;#{pane_current_path}&amp;quot;
# 将当前窗格分离成新窗口
bind -n C-o break-pane
# 关闭当前窗格
bind -n C-q kill-pane
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过  &lt;code&gt;(&lt;/code&gt;  和  &lt;code&gt;)&lt;/code&gt;  键快速交换上下窗格的位置，从而方便地调整窗格布局。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;next-layout&lt;/code&gt; tmux默认提供了一些布局样式，使用它可以快速进行排版。&lt;/p&gt;
&lt;h3&gt;调整窗格大小&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 将窗格向左调整 2 个单元格
bind -r H resize-pane -L 2
# 将窗格向下调整 2 个单元格
bind -r J resize-pane -D 2
# 将窗格向上调整 2 个单元格
bind -r K resize-pane -U 2
# 将窗格向右调整 2 个单元格
bind -r L resize-pane -R 2

# 最大化当前窗格
bind f resize-pane -Z
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过 &lt;code&gt;H&lt;/code&gt;、&lt;code&gt;J&lt;/code&gt;、&lt;code&gt;K&lt;/code&gt;、&lt;code&gt;L&lt;/code&gt; 键精确调整窗格大小，可以更灵活的调整屏幕上窗格的布局。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;f&lt;/code&gt; 键快速最大化当前窗格，便于查看和操作，再次按下可以恢复原始大小。&lt;/p&gt;
&lt;p&gt;可视模式&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;tmux&lt;/code&gt; 中使用 Vi 风格的键绑定进行复制操作，自定义复制模式（Vi 模式）的键绑定&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 可视模式
bind -n C-v copy-mode
bind -T copy-mode-vi v send-keys -X begin-selection
bind -T copy-mode-vi C-v send-keys -X rectangle-toggle
bind -T copy-mode-vi h send-keys -X cursor-left
bind -T copy-mode-vi l send-keys -X cursor-right
bind -T copy-mode-vi k send-keys -X cursor-up
bind -T copy-mode-vi j send-keys -X cursor-down
bind -T copy-mode-vi i send-keys -X next-word-end
bind -T copy-mode-vi K send-keys -N 5 -X cursor-up
bind -T copy-mode-vi J send-keys -N 5 -X cursor-down
bind -T copy-mode-vi H send-keys -X start-of-line
bind -T copy-mode-vi L send-keys -X end-of-line
bind -T copy-mode-vi Y send-keys -X copy-end-of-line
bind -T copy-mode-vi y send-keys -X copy-selection-and-cancel
bind -T copy-mode-vi = send-keys -X search-again
bind -T copy-mode-vi = send-keys -X search-reverse
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;bind -n C-v copy-mode&lt;/code&gt; 绑定 &lt;code&gt;Ctrl-v&lt;/code&gt; 键进入复制模式（copy-mode），从而可以选择和复制屏幕上的文本内容。&lt;/p&gt;
&lt;p&gt;在复制模式下，下面的快捷键用于选择、复制和取消复制等操作：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;begin-selection&lt;/code&gt;：开始选择文本&lt;/p&gt;
&lt;p&gt;&lt;code&gt;rectangle-toggle&lt;/code&gt;：切换矩形选择模式&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cursor-left&lt;/code&gt; 、&lt;code&gt;cursor-right&lt;/code&gt; ：向某个方向移动&lt;/p&gt;
&lt;p&gt;&lt;code&gt;next-word-end&lt;/code&gt;：移动到下一个单词末尾&lt;/p&gt;
&lt;p&gt;&lt;code&gt;start-of-line&lt;/code&gt; 、&lt;code&gt;end-of-line&lt;/code&gt; ：移动到行首和行尾&lt;/p&gt;
&lt;p&gt;&lt;code&gt;copy-end-of-line&lt;/code&gt; ： 复制到行末&lt;/p&gt;
&lt;p&gt;&lt;code&gt;copy-selection-and-cancel&lt;/code&gt; ：复制选择并退出选择模式&lt;/p&gt;
&lt;p&gt;&lt;code&gt;search-again&lt;/code&gt;：重复上次搜索&lt;/p&gt;
&lt;h2&gt;其他快速变更指令&lt;/h2&gt;
&lt;h3&gt;切换状态栏的显示状态&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# -- 切换状态栏的显示状态
bind s if-shell &amp;#039;[[ $(tmux show -g status | cut -d\  -f2) == &amp;quot;on&amp;quot; ]]&amp;#039; \
&amp;#039;set -g status off&amp;#039; \
&amp;#039;set -g status on&amp;#039;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过 &lt;code&gt;s&lt;/code&gt; 键来实现在状态栏的显示和隐藏之间切换。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;if-shell &amp;#039;[[ $(tmux show -g status | cut -d\ -f2) == &amp;quot;on&amp;quot; ]]&amp;#039;&lt;/code&gt; 执行一个条件判断的 shell 脚本&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tmux show -g status&lt;/code&gt;：命令用于显示全局的 &lt;code&gt;status&lt;/code&gt;（状态栏）配置&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cut -d\ -f2&lt;/code&gt;：使用 &lt;code&gt;cut&lt;/code&gt; 命令提取第二个字段（即状态 &amp;quot;on&amp;quot; 或 &amp;quot;off&amp;quot;）&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[[ ... == &amp;quot;on&amp;quot; ]]&lt;/code&gt;：判断提取的状态是否为 &amp;quot;on&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;set -g status off&lt;/code&gt; ：状态栏状态为 &amp;quot;on&amp;quot;，则关闭状态栏&lt;/p&gt;
&lt;p&gt;&lt;code&gt;set -g status on&lt;/code&gt;：如果状态栏状态为 &amp;quot;off&amp;quot;，则开启状态栏&lt;/p&gt;
&lt;h3&gt;控制多窗格同步输入功能&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# -- 控制多窗格同步输入功能
bind C-g if-shell &amp;#039;[[ $(tmux showw synchronize-panes | cut -d\  -f2) == &amp;quot;on&amp;quot; ]]&amp;#039; \
&amp;#039;setw synchronize-panes off; set -g pane-border-style fg=magenta&amp;#039; \
&amp;#039;setw synchronize-panes on; set -g pane-border-style fg=red&amp;#039;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过 &lt;code&gt;Ctrl-g&lt;/code&gt; 键来实现在一个窗口下控制多窗格的同步输入功能开关，同时根据同步状态更改面板边框的颜色。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tmux showw synchronize-panes&lt;/code&gt;：命令用于显示当前窗格的 &lt;code&gt;synchronize-panes&lt;/code&gt; 状态。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cut -d\ -f2&lt;/code&gt;：使用 &lt;code&gt;cut&lt;/code&gt; 命令提取第二个字段（即状态 &amp;quot;on&amp;quot; 或 &amp;quot;off&amp;quot;）。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[[ ... == &amp;quot;on&amp;quot; ]]&lt;/code&gt;：判断提取的状态是否为 &amp;quot;on&amp;quot;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;setw synchronize-panes off; set -g pane-border-style fg=magenta&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果 &lt;code&gt;synchronize-panes&lt;/code&gt; 状态为 &amp;quot;on&amp;quot;，则将其关闭，并将面板边框颜色设置为 &lt;code&gt;magenta&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setw synchronize-panes off&lt;/code&gt;：关闭同步输入。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set -g pane-border-style fg=magenta&lt;/code&gt;：将面板边框颜色设置为紫红色。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;setw synchronize-panes on; set -g pane-border-style fg=red&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果 &lt;code&gt;synchronize-panes&lt;/code&gt; 状态为 &amp;quot;off&amp;quot;，则将其开启，并将面板边框颜色设置为 &lt;code&gt;red&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;setw synchronize-panes on&lt;/code&gt;：开启同步输入。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set -g pane-border-style fg=red&lt;/code&gt;：将面板边框颜色设置为红色。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;快速重新加载配置文件&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;bind r run &amp;#039;&amp;quot;$TMUX_PROGRAM&amp;quot; ${TMUX_SOCKET:+-S &amp;quot;$TMUX_SOCKET&amp;quot;} source &amp;quot;$TMUX_CONF&amp;quot;&amp;#039; \; display &amp;quot;#{TMUX_CONF} sourced&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过 &lt;code&gt;r&lt;/code&gt; 键快速重新加载 tmux 配置文件并显示提示信息，达到快速应用配置更改。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这行配置为 &lt;code&gt;r&lt;/code&gt; 键绑定了重新加载 tmux 配置文件的功能。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;run &amp;#039;&amp;quot;$TMUX_PROGRAM&amp;quot; ${TMUX_SOCKET:+-S &amp;quot;$TMUX_SOCKET&amp;quot;} source &amp;quot;$TMUX_CONF&amp;quot;&amp;#039;&lt;/code&gt;：运行 tmux 程序重新加载配置文件。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;display &amp;quot;#{TMUX_CONF} sourced&amp;quot;&lt;/code&gt;：在状态栏显示配置文件已重新加载的信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;安装tmux插件管理器&lt;/h2&gt;
&lt;p&gt;先克隆 &lt;a href=&quot;https://github.com/tmux-plugins/tpm&quot;&gt;tpm&lt;/a&gt; 仓库到本地环境&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将以下内容放在  &lt;code&gt;~/.tmux.conf &lt;/code&gt; 文件里启用插件&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# List of plugins
set -g @plugin &amp;#039;tmux-plugins/tpm&amp;#039;
set -g @plugin &amp;#039;tmux-plugins/tmux-sensible&amp;#039;

# Other examples:
# set -g @plugin &amp;#039;github_username/plugin_name&amp;#039;
# set -g @plugin &amp;#039;github_username/plugin_name#branch&amp;#039;
# set -g @plugin &amp;#039;git@github.com:user/plugin&amp;#039;
# set -g @plugin &amp;#039;git@bitbucket.com:user/plugin&amp;#039;

# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
run &amp;#039;~/.tmux/plugins/tpm/tpm&amp;#039;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后重载配置使其生效&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;:source ~/.tmux.conf

# 如果 tmux 已在运行，则在终端中键入此内容
tmux source ~/.tmux.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;插件&lt;/h3&gt;
&lt;h3&gt;主题&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/catppuccin/tmux&quot;&gt;catppuccin/tmux&lt;/a&gt; 主题&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# catppuccin theme
set -g @plugin &amp;quot;catppuccin/tmux&amp;quot;
set -g @catppuccin_flavour &amp;quot;mocha&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;常用的tmux操作按键（快捷键）&lt;/h2&gt;
&lt;p&gt;以下是一些个人定义的tmux操作按键（快捷键）&lt;/p&gt;
&lt;p&gt;个人配置使用 &lt;code&gt;C-s&lt;/code&gt; 作为二级前缀，同时保留 &lt;code&gt;C-s&lt;/code&gt; 作为默认前缀。&lt;/p&gt;
&lt;h3&gt;按键绑定说明&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt;&lt;/code&gt;  表示您必须按 &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;d&lt;/code&gt; 或 &lt;code&gt;Ctrl &lt;/code&gt;+ &lt;code&gt;s&lt;/code&gt;。&lt;br /&gt;
&lt;code&gt;&amp;lt;prefix&amp;gt; c&lt;/code&gt;  表示必须按 &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;d&lt;/code&gt; 或 &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;s&lt;/code&gt;，然后按 &lt;code&gt;c&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&amp;lt;prefix&amp;gt; C-c&lt;/code&gt;  表示必须按 &lt;code&gt;Ctrl &lt;/code&gt;+ &lt;code&gt;d &lt;/code&gt;或 &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;s&lt;/code&gt;，然后按 &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;c&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;个人配置使用以下绑定&lt;/h3&gt;
&lt;h4&gt;快捷操作&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; d&lt;/code&gt;   分离当前会话到后台运行&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; r&lt;/code&gt; 重新加载配置&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; C-g&lt;/code&gt; 控制多窗格的同步输入功能开关&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; s&lt;/code&gt; 显示隐藏底部状态栏&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C-l&lt;/code&gt; 清除屏幕和 tmux 历史记录&lt;/p&gt;
&lt;h4&gt;会话相关&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; &lt;/code&gt; &lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; C-c&lt;/code&gt;  当前窗口下快速创建新的会话&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; ]&lt;/code&gt; 查看已创建的会话&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; W&lt;/code&gt; 以树状图样式查看已创建的会话及其窗口窗格&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C-x&lt;/code&gt; + &lt;code&gt;1&lt;/code&gt; 快速关闭第一个会话（1~9 可以依顺序快速关闭对应的会话）&lt;/p&gt;
&lt;h4&gt;窗口相关&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; C-h&lt;/code&gt; 切换当前会话里的上一个窗口&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; C-l&lt;/code&gt; 切换当前会话里的下一个窗口&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C-g&lt;/code&gt; +  &lt;code&gt;数字键&lt;/code&gt; 将快速切换到当前会话里的其他指定窗口，例如按 &lt;code&gt;Ctrl-g&lt;/code&gt; + &lt;code&gt;1&lt;/code&gt;  将快速切换到当前会话里的第一个窗口（1~9 可以依顺序快速切换对应的窗口）&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C-a&lt;/code&gt; +  &lt;code&gt;数字键&lt;/code&gt; 将当前窗格加入到当前会话里的其他指定窗口，例如按 &lt;code&gt;Ctrl-a&lt;/code&gt; + &lt;code&gt;1&lt;/code&gt;  将当前窗格加入到窗口 1。（1~9 可以依顺序将当前窗格加入到其他对应的窗口）&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; S&lt;/code&gt; 以树状形式打开所有会话和窗口，并将选中想要移动的窗格垂直移动到当前（所选择的）会话窗口下（跨会话移动）&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; V&lt;/code&gt; 以树状形式打开所有会话和窗口，并将选中想要移动的窗格垂水平动到当前（所选择的）会话窗口下（跨会话移动）&lt;/p&gt;
&lt;h4&gt;窗格相关&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; &amp;lt;&lt;/code&gt;水平拆分，新的窗格位于当前窗格之左&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; &amp;gt;&lt;/code&gt;水平拆分，新的窗格位于当前窗格之右&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; ?&lt;/code&gt;垂直拆分，新的窗格位于当前窗格之下。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; /&lt;/code&gt; 垂直拆分，新的窗格位于当前窗格之上。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; h&lt;/code&gt;, &lt;code&gt;&amp;lt;prefix&amp;gt; j&lt;/code&gt;, &lt;code&gt;&amp;lt;prefix&amp;gt; k&lt;/code&gt; , &lt;code&gt;&amp;lt;prefix&amp;gt; l&lt;/code&gt; 焦点窗格上下左右移动选择&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt;&lt;/code&gt; +  &lt;code&gt;数字键&lt;/code&gt; 将快速将焦点切换到当前窗口下的其他窗格里，例如按 &lt;code&gt;&amp;lt;prefix&amp;gt;&lt;/code&gt; + &lt;code&gt;1&lt;/code&gt;  将快速将焦点切换到第一个窗格下（1~9 可以依顺序快速切换对应的窗格）&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; (&lt;/code&gt; ,  &lt;code&gt;&amp;lt;prefix&amp;gt; )&lt;/code&gt; 交换上下窗格的位置&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C-o&lt;/code&gt;将当前窗格分离成新窗口&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C-q&lt;/code&gt;关闭当前窗格&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C-u&lt;/code&gt;切换到下一个窗格布局&lt;/p&gt;
&lt;p&gt;&lt;code&gt;C-p&lt;/code&gt;创建新窗口，路径为当前 pane 的路径&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; H&lt;/code&gt;, &lt;code&gt;&amp;lt;prefix&amp;gt; J&lt;/code&gt;, &lt;code&gt;&amp;lt;prefix&amp;gt; K&lt;/code&gt;, &lt;code&gt;&amp;lt;prefix&amp;gt; L&lt;/code&gt; 调整窗口大小&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;prefix&amp;gt; f&lt;/code&gt; 当前窗格最大化，再次按下恢复  &lt;/p&gt;
&lt;h4&gt;可视模式，复制相关&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;C-v&lt;/code&gt;进入复制模式&lt;/p&gt;
&lt;p&gt;&lt;code&gt;v&lt;/code&gt; 开始选择文本&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Ctrl-v&lt;/code&gt; 切换矩形选择模式&lt;/p&gt;
&lt;p&gt;&lt;code&gt;h&lt;/code&gt;向左移动光标。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;l&lt;/code&gt;向右移动光标。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;k&lt;/code&gt;向上移动光标。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;j&lt;/code&gt;向下移动光标。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;K&lt;/code&gt;向上移动光标 5 行&lt;/p&gt;
&lt;p&gt;&lt;code&gt;J&lt;/code&gt;向下移动光标 5 行&lt;/p&gt;
&lt;p&gt;&lt;code&gt;H&lt;/code&gt;将光标移动到行首&lt;/p&gt;
&lt;p&gt;&lt;code&gt;L&lt;/code&gt;将光标移动到行尾&lt;/p&gt;
&lt;p&gt;&lt;code&gt;i&lt;/code&gt;将光标移动到下一个单词的结尾&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Y&lt;/code&gt;复制从光标当前位置到行尾的内容&lt;/p&gt;
&lt;p&gt;&lt;code&gt;y&lt;/code&gt;复制选择的内容并取消选择模式&lt;/p&gt;
&lt;p&gt;&lt;code&gt;=&lt;/code&gt;重复上一次的搜索&lt;/p&gt;
&lt;h2&gt;会话管理&lt;/h2&gt;
&lt;h3&gt;&lt;strong&gt;创建新的 tmux 会话&lt;/strong&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;tmux new -s session_name&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;tmux new-session -s mysession&lt;/code&gt;  创建一个名为 &lt;code&gt;mysession&lt;/code&gt; 的新会话&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;启动一个新的 tmux 会话并使其在后台运行&lt;/strong&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;tmux new-session -d -s session_name&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;列出当前正在运行的所有所有 tmux 会话&lt;/strong&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;tmux list-sessions
tmux ls
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;chixm:~ $ tmux list-sessions
3: 8 windows (created Sun Apr 28 15:39:55 2024)
7: 2 windows (created Mon Apr 29 10:42:05 2024)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这将列出所有后台运行的 tmux 会话及其名称。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;重命名会话&lt;/strong&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;tmux rename-session -t newnam chixm&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将编号为 &lt;code&gt;3&lt;/code&gt; 的会话重命名为 &lt;code&gt;chixm&lt;/code&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;chixm:~ $ tmux list-sessions      
7: 2 windows (created Mon Apr 29 10:42:05 2024)
chixm: 8 windows (created Sun Apr 28 15:39:55 2024)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;重新&lt;strong&gt;连接到会话&lt;/strong&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;tmux attach -t session_name
tmux attach-session -t session_name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;要重新连接到一个已经在后台运行的 tmux 会话，可以使用以下命令：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-t session_name&lt;/code&gt; 用于指定要连接的会话名称。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;chixm:~ $ tmux list-sessions      
7: 2 windows (created Mon Apr 29 10:42:05 2024)
chixm: 8 windows (created Sun Apr 28 15:39:55 2024)

# 进入到编号为 3 的会话
chixm:~ $ tmux attach-session -t 7
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;杀死结束会话&lt;/strong&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;tmux kill-session -t &amp;lt;session-name-or-id&amp;gt;

# 结束编号为 3 的会话
tmux kill-session -t 3

# 结束名为 chixm 的会话
tmux kill-session -t chixm

# 结束所有 tmux 会话
tmux kill-server

# 使用 xargs 一次性杀死多个会话
tmux list-sessions -F &amp;#039;#S&amp;#039; | xargs -I {} tmux kill-session -t {}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;# 结束当前会话
tmux kill-session&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在当前所在的会话内部执行，会话将被终止。&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;shell环境下重新加载 tmux 配置文件&lt;/strong&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-Bash&quot;&gt;tmux source ~/.tmux.conf&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;其他&lt;/h2&gt;
&lt;p&gt;开箱即用的配置&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/gpakosz/.tmux&quot;&gt;https://github.com/gpakosz/.tmux&lt;/a&gt;&lt;/p&gt;</content></entry><entry><title>【软件探索】终端工具，Tabby、Xterminal</title><link href="https://www.moshanghua.net/archives/%E8%BD%AF%E4%BB%B6%E6%8E%A2%E7%B4%A2-xterminal.html" /><id>https://www.moshanghua.net/archives/%E8%BD%AF%E4%BB%B6%E6%8E%A2%E7%B4%A2-xterminal.html</id><updated>2023-10-24T14:43:14.000Z</updated><summary></summary><content type="html">&lt;h2&gt;关于&lt;/h2&gt;
&lt;p&gt;近期有在本地往服务器上传文件的需求，之前 Windows 下一直用的 xshell 和 Xftp，家庭教育版免费，但它不跨平台，然后换设备后，大部分时候只是一点需求又不想开多设备。
因此，一顿乱逛找到目前在用的两款软件，&lt;strong&gt;Tabby&lt;/strong&gt;跨平台的终端工具，且集成了 FTP 功能，此软件日常用作本地 Shell居多，颜值在线。&lt;strong&gt;Xterminal&lt;/strong&gt; 看&lt;a href=&quot;https://txc.qq.com/products/598955/change-log&quot; title=&quot;更新日志&quot;&gt;更新日志&lt;/a&gt;似乎是款新生软件，功能挺杂的，主要用它的 ssh 和 FTP 功能，也是颜值在线。
然后两个软件都是花里胡哨的，所以，不轻量，内存占用较高。&lt;/p&gt;
&lt;h2&gt;Tabby&lt;/h2&gt;
&lt;p&gt;Tabby (前身Terminus) 是一个基于 TypeScript 开发、可定制的跨平台开源终端应用程序，用于本地shell，ssh和 Telnet连接，在 GitHub 上已经有 51.3k 的 star 了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/10/msh-2831-tabby.png&quot; alt=&quot;tabby 截图&quot; title=&quot;tabby 截图&quot; /&gt;&lt;/p&gt;
&lt;p&gt;终端特性：
定制主题和配色方案
支持自定义配置快捷键和多键快捷键
易用终端特性，如记忆标签，切分窗格，
支持丰富的扩展插件
支持基于SFTP 协议的文件传输功能
......&lt;/p&gt;
&lt;p&gt;官网：&lt;a href=&quot;https://tabby.sh/&quot; title=&quot;Tabby&quot;&gt;Tabby&lt;/a&gt;
GitHub 地址：&lt;a href=&quot;https://github.com/Eugeny/tabby&quot; title=&quot;https://github.com/Eugeny/tabby&quot;&gt;https://github.com/Eugeny/tabby&lt;/a&gt;
中文介绍：&lt;a href=&quot;https://github.com/Eugeny/tabby/blob/master/README.zh-CN.md&quot; title=&quot;Tabby README.zh-CN&quot;&gt;Tabby README.zh-CN&lt;/a&gt;
下载地址：&lt;a href=&quot;https://github.com/Eugeny/tabby/releases&quot; title=&quot;https://github.com/Eugeny/tabby/releases&quot;&gt;https://github.com/Eugeny/tabby/releases&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Xterminal&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Xterminal&lt;/strong&gt;，一个多终端的远程Web Shell 工具。在基础功能上（目前）没有任何限制可以免费使用，支持多个平台。
功能上轻松编辑，删除，新增，上传下载，移动文件。完全自定义布局，满足个性化需求，服务器图表化实时监控，清晰掌握系统状态。
缺点上就是&lt;strong&gt;软件美但不小，软件对终端的 CPU、内存占用较高，&lt;/strong&gt;颜值党可以优先考虑。然后就是&lt;strong&gt;软件需要登录激活。且有会员要收费的操作&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;官网：&lt;a href=&quot;https://www.xterminal.cn/&quot; title=&quot;Xterminal&quot;&gt;Xterminal&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;更好用的开发工具，但不止于 SSH、Terminal ......
不仅是强大的SSH工具，更提供本地控制台，以及更多即将
推出的开发相关功能，让您专注于创造卓越的代码&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/10/msh-2831-01.png&quot; alt=&quot;软件首页&quot; title=&quot;软件首页&quot; /&gt;&lt;/p&gt;
&lt;p&gt;SSH
&lt;img src=&quot;https://assets.moshanghua.net/images/2023/10/msh-2831-02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;多级分组
&lt;img src=&quot;https://assets.moshanghua.net/images/2023/10/msh-2831-03.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;监控面板
&lt;img src=&quot;https://assets.moshanghua.net/images/2023/10/msh-2831-04.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;书签跳转
&lt;img src=&quot;https://assets.moshanghua.net/images/2023/10/msh-2831-05.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;笔记
&lt;img src=&quot;https://assets.moshanghua.net/images/2023/10/msh-2831-06.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;</content></entry><entry><title>新的开始,心路历程</title><link href="https://www.moshanghua.net/archives/%E6%96%B0%E7%9A%84%E5%BC%80%E5%A7%8B%E5%BF%83%E8%B7%AF%E5%8E%86%E7%A8%8B.html" /><id>https://www.moshanghua.net/archives/%E6%96%B0%E7%9A%84%E5%BC%80%E5%A7%8B%E5%BF%83%E8%B7%AF%E5%8E%86%E7%A8%8B.html</id><updated>2023-10-01T07:17:31.000Z</updated><summary></summary><content type="html">&lt;p&gt;再次起航，谨以此文，记录一下这次一念起，能坚持到什么程度！&lt;/p&gt;
&lt;h2&gt;2023-10-01&lt;/h2&gt;</content></entry><entry><title>青花瓷天依</title><link href="https://www.moshanghua.net/archives/%E9%9D%92%E8%8A%B1%E7%93%B7%E5%A4%A9%E4%BE%9D.html" /><id>https://www.moshanghua.net/archives/%E9%9D%92%E8%8A%B1%E7%93%B7%E5%A4%A9%E4%BE%9D.html</id><updated>2023-09-10T15:23:42.000Z</updated><summary></summary><content type="html">&lt;p&gt;青花瓷天依
&lt;img src=&quot;https://assets.moshanghua.net/tianyi/Shintani/a79aea8eff40425f08c9c7bd60a42bc93557283.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;画师id&lt;/h2&gt;
&lt;p&gt;感谢深谷老师的画作~ 并允许使用~
B站id：&lt;a href=&quot;https://space.bilibili.com/3557283&quot;&gt;@深谷Shintani&lt;/a&gt;
微博id：&lt;a href=&quot;https://weibo.com/u/3875024604&quot;&gt;@深谷-shintani&lt;/a&gt;&lt;/p&gt;</content></entry><entry><title>♫《四风判词》ilem</title><link href="https://www.moshanghua.net/archives/%E5%9B%9B%E9%A3%8E%E5%88%A4%E8%AF%8D-ilem.html" /><id>https://www.moshanghua.net/archives/%E5%9B%9B%E9%A3%8E%E5%88%A4%E8%AF%8D-ilem.html</id><updated>2023-09-07T17:12:35.000Z</updated><summary></summary><content type="html">&lt;h2&gt;原创 《四风判词》ilem&lt;/h2&gt;
&lt;p&gt;彭虚子秉火夜游。路遇非僧非道一叟，着非白非黑一袍，驾非牛非马一骑，歌非庄非谐一调，言非今非古之事。和而歌，及天明乃别去。归，欲复咏，然倏而竟皆忘矣。惟余四阙长调之小引，故强录之，名曰《四风判词》。&lt;/p&gt;
&lt;p&gt;bilibili：&lt;a style=&quot;color: #409eff;&quot; href=&quot;https://www.bilibili.com/video/BV1Rp4y1P7Qe/&quot;  target=&quot;_blank&quot;&gt;原创 《四风判词》ilem&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;最近循环N遍了，每一句都能品出点什么但又似懂非懂，反正，就是有点儿好听！还有这算什么，叠字？合体字？挺有意思的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/09/msh-2779-01.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://assets.moshanghua.net/images/2023/09/msh-2779-02.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://assets.moshanghua.net/images/2023/09/msh-2779-03.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://assets.moshanghua.net/images/2023/09/msh-2779-04.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;</content></entry><entry><title>emo，致糟糕的自己，真的挺失望...</title><link href="https://www.moshanghua.net/archives/emo-%E8%87%B4%E7%B3%9F%E7%B3%95%E7%9A%84%E8%87%AA%E5%B7%B1-%E7%9C%9F%E7%9A%84%E6%8C%BA%E5%A4%B1%E6%9C%9B-2.html" /><id>https://www.moshanghua.net/archives/emo-%E8%87%B4%E7%B3%9F%E7%B3%95%E7%9A%84%E8%87%AA%E5%B7%B1-%E7%9C%9F%E7%9A%84%E6%8C%BA%E5%A4%B1%E6%9C%9B-2.html</id><updated>2023-08-12T19:52:38.000Z</updated><summary></summary><content type="html"></content></entry><entry><title>Windows下将Git bash添加到Windows terminal里</title><link href="https://www.moshanghua.net/archives/win%E4%B8%8B%E5%B0%86git-bash%E9%9B%86%E6%88%90%E5%88%B0wt%E9%87%8C.html" /><id>https://www.moshanghua.net/archives/win%E4%B8%8B%E5%B0%86git-bash%E9%9B%86%E6%88%90%E5%88%B0wt%E9%87%8C.html</id><updated>2023-07-30T01:07:04.000Z</updated><summary></summary><content type="html">&lt;p&gt;启动Windows terminal，打开设置，点击添加新配置文件，然后复制一份。
&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2765-01.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;名称自定义
&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2765-02.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这里的可执行文件在Git安装目录下的\bin\目录下选择bash.exe
&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2765-03.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;图标可自定义
&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2765-04.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;保存，就可以看到新配置了
&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2765-05.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后侧栏的启动栏目里点击默认配置文件，选择自己新建的配置文件，保存。
&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2765-06.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;下次打开默认就是bash了。git自带的bash是可以运行linux命令的。
&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2765-07.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;vim也是可以用的，选中的三行里是vim配置文件的存放路径&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2765-08.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;system vimrc file: &amp;quot;/etc/vimrc&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第一个路径 &lt;code&gt;/etc/vimrc&lt;/code&gt; 在git根目录下&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2765-09.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;user vimrc file: &amp;quot;$HOME/.vimrc&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第二个路径为用户根目录&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2765-10.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;目录下没有 &lt;code&gt;.vimrc&lt;/code&gt; 就新建一个&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 2nd user vimrc file: &amp;quot;~/.vim/vimrc&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第三个路径为用户根目录  &lt;code&gt;/.vim/vimrc&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2765-11.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;同样目录下没有就新建一下，先建隐藏文件夹，在建文件。&lt;/p&gt;
&lt;p&gt;然后基础的vim配置也写入在这个文件里。&lt;/p&gt;</content></entry><entry><title>入手一台丐版 Mini | 揽件日记</title><link href="https://www.moshanghua.net/archives/emo-%E8%87%B4%E7%B3%9F%E7%B3%95%E7%9A%84%E8%87%AA%E5%B7%B1-%E7%9C%9F%E7%9A%84%E6%8C%BA%E5%A4%B1%E6%9C%9B.html" /><id>https://www.moshanghua.net/archives/emo-%E8%87%B4%E7%B3%9F%E7%B3%95%E7%9A%84%E8%87%AA%E5%B7%B1-%E7%9C%9F%E7%9A%84%E6%8C%BA%E5%A4%B1%E6%9C%9B.html</id><updated>2023-07-26T01:55:16.000Z</updated><summary></summary><content type="html">&lt;p&gt;算是第一次用白苹果，上一次用 Mac OS 还是几年前买 NUC 8 硬改版上的黑果子，后面因为唤醒问题老点不亮屏幕，就换回 Win 了。&lt;/p&gt;
&lt;p&gt;起因是最近突然又想到 Mac OS，然后又想体验下 Mac OS 了，念起一上头就下单消费了。&lt;/p&gt;
&lt;p&gt;结合自己用电脑的习惯是在住房固定的，也没有外出带本的需求，就看了下 Mac mini 系列。&lt;/p&gt;
&lt;p&gt;使用需求上，琢磨了下，没想着拿来干什么大事，日常也就是开个游览器看看博客刷刷网页，挂个微信，写点文字，或者再开个编辑器写几行字符。&lt;/p&gt;
&lt;p&gt;配置上最开始看的是丐中丐版 M2 芯片 8+256，然后加“一”点的驱使下，各翻了一倍，嗯....就先这样吧&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2762-01.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;京东上25号早上下单，然后下午收到的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2762-02.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;开箱&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2762-03.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2762-04.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2762-05.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;再见熟悉的界面。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2762-06.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/msh-2762-07.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;</content></entry><entry><title>【天依唱片机】</title><link href="https://www.moshanghua.net/archives/%E7%95%99-10.html" /><id>https://www.moshanghua.net/archives/%E7%95%99-10.html</id><updated>2023-07-19T16:09:50.000Z</updated><summary></summary><content type="html">&lt;h2&gt;第一期&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/2753/8a63040eee88913162655a77170fd3d8c3085f28.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1AP411r7nh/&quot; title=&quot;第一期·夏日 | 来一杯夏日特饮，天依陪你度过暑假的夜晚~&quot;&gt;第一期·夏日 | 来一杯夏日特饮，天依陪你度过暑假的夜晚~&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;第二期&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/2753/c64f357f99b5a624e0bc4ac843d7e2daf083e953.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1aN4y1d7Ai&quot; title=&quot;第二期·夏夜｜歌声静静流淌，我们还有很多个陪伴彼此的日日夜夜&quot;&gt;第二期·夏夜｜歌声静静流淌，我们还有很多个陪伴彼此的日日夜夜&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;第三期&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/2753/74b0ed16f0a6e4cc989ae62add4b190e2066ea99.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1SV411A7Sy&quot; title=&quot;第三期·夏终 | 感到寂寞的时候，就来听天依唱歌吧~&quot;&gt;第三期·夏终 | 感到寂寞的时候，就来听天依唱歌吧~&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;第四期&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/2753/7dc31df2c3e9f1b41b1f7d8f30bf6a4db1d593df.jpg&quot; alt=&quot;&quot; /&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV1YQ4y1s7G3&quot; title=&quot;第四期·秋游 | 开启属于天依和你的秋日歌单&quot;&gt;第四期·秋游 | 开启属于天依和你的秋日歌单&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;第五期&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/2753/431f7d4feeb61a57a4c4c6d053f29cd28471d122.jpg&quot; alt=&quot;&quot; /&gt;
&lt;a href=&quot;https://www.bilibili.com/video/BV14v411c7Ro&quot; title=&quot;第五期·秋宴 | 岁月缱绻，有美景与佳曲，邀你共赏&quot;&gt;第五期·秋宴 | 岁月缱绻，有美景与佳曲，邀你共赏&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;第六期&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/2753/116e20249e945eee88b9a098dc5c58eef33c51d6.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1g5411q7bk&quot; title=&quot;第六期·圣诞&amp;amp;元旦特辑 | 有你陪伴与聆听的节日，才叫幸福&quot;&gt;第六期·圣诞&amp;amp;元旦特辑 | 有你陪伴与聆听的节日，才叫幸福&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;第七期&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/2753/c5fe4d296f648517eeda1c5e2ba513e972e8a835.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV19j421Q7St&quot; title=&quot;第七期·冬愿 | 在茫茫大雪中，听见希望的歌声&quot;&gt;第七期·冬愿 | 在茫茫大雪中，听见希望的歌声&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;第八期&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV17H4y1s7AL&quot; title=&quot;第八期·冬融 | 在暮冬暖阳下，盼冰雪融化为跃动的音符&quot;&gt;第八期·冬融 | 在暮冬暖阳下，盼冰雪融化为跃动的音符&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;第九期&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/images/2023/07/2753/cb0e80315b16f0d163ce3102d18d21d936081646.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1Ti421173v&quot; title=&quot;【天依唱片机】第九期·春游 | 加百列玫瑰，奏响春日的协奏曲&quot;&gt;【天依唱片机】第九期·春游 | 加百列玫瑰，奏响春日的协奏曲&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;第十期&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV15z421Y7Bk&quot; title=&quot;【天依唱片机】第十期·春回 | 你会如何形容一个春天&quot;&gt;【天依唱片机】第十期·春回 | 你会如何形容一个春天&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;第十一期&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1Ff421z7GB&quot; title=&quot;【天依唱片机】第十一期·春别 | 今日若无事，且听我一曲&quot;&gt;【天依唱片机】第十一期·春别 | 今日若无事，且听我一曲&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;第十二期&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;http://assets.moshanghua.net/images/2023/07/2753/77c1b61cc6bf39354129327b370145a736081646.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1UW421975p&quot; title=&quot;【天依唱片机】第十二期·微醺 | 放一张过去的CD听听那时我们的回忆&quot;&gt;【天依唱片机】第十二期·微醺 | 放一张过去的CD听听那时我们的回忆&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;第十三期&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.bilibili.com/video/BV1uPx4ejEce&quot; title=&quot;【天依唱片机】第十三期· 沉醉 | 就随着音乐与歌声在这个夜晚沉醉&quot;&gt;【天依唱片机】第十三期· 沉醉 | 就随着音乐与歌声在这个夜晚沉醉&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;图片抓取自洛天依B站官方账号，侵权练习删！&lt;/p&gt;</content></entry><entry><title>【水彩画】7.12</title><link href="https://www.moshanghua.net/archives/7-12.html" /><id>https://www.moshanghua.net/archives/7-12.html</id><updated>2023-07-12T16:35:16.000Z</updated><summary></summary><content type="html">&lt;p&gt;&lt;img src=&quot;https://assets.moshanghua.net/tianyi/e7aec531f7c4847bb9a96e800442ebfe3557283.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;点击可看深谷老师的美丽过程！还有老师的讲解&lt;a href=&quot;https://www.bilibili.com/video/BV1Gh4y1j7fE&quot; title=&quot;【水彩绘画】花20小时画洛天依11周年生日贺图&quot;&gt;【水彩绘画】花20小时画洛天依11周年生日贺图&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;再附上一份洛天依11周年生日会歌曲合集&lt;a href=&quot;https://www.bilibili.com/video/BV19W4y1f7hz&quot;&gt;2023官方生贺曲&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;画师id&lt;/h2&gt;
&lt;p&gt;感谢深谷老师的画作~ 并允许使用~
B站id：&lt;a href=&quot;https://space.bilibili.com/3557283&quot;&gt;@深谷Shintani&lt;/a&gt;
微博id：&lt;a href=&quot;https://weibo.com/u/3875024604&quot;&gt;@深谷-shintani&lt;/a&gt;&lt;/p&gt;</content></entry></feed>