Laravel migration如何将指定列的值设置为另一列的默认值
实现方案说明
直接在Laravel迁移中通过default()方法设置字段默认值无法实现该需求,核心原因是SQL本身不允许字段默认值引用同表的其他字段值。可通过以下两种方案实现需求:
方案一:使用Laravel模型事件(推荐)
通过监听模型的creating事件,在数据写入数据库前自动填充slug字段,无需额外更新操作。
- 打开
app/Models/Article.php模型文件,添加如下代码:
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class Article extends Model { // 配置可批量赋值的字段 protected $fillable = ['id', 'title', 'details', 'slug']; protected static function booted() { // 监听模型创建前的事件 static::creating(function ($article) { // 仅当slug未手动赋值时,默认取id的值 if (empty($article->slug)) { $article->slug = $article->id; } }); } }
配置完成后直接调用你给出的创建代码即可,slug字段会自动填充为对应id的值。该方案是Laravel社区的主流实现方式,逻辑调整方便,无需修改数据库结构。
方案二:使用数据库触发器
如果需要该逻辑在数据库层面生效(即不依赖Laravel模型,直接操作数据库插入也能自动填充),可以在迁移文件中创建触发器:
- 在articles表迁移文件中添加触发器逻辑:
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\DB; return new class extends Migration { public function up() { Schema::create('articles', function (Blueprint $table) { $table->string('id')->primary(); $table->string('title'); $table->text('details'); $table->string('slug'); $table->timestamps(); }); // 创建插入前触发的触发器 DB::unprepared(' CREATE TRIGGER articles_slug_default BEFORE INSERT ON `articles` FOR EACH ROW BEGIN IF NEW.slug IS NULL OR NEW.slug = "" THEN SET NEW.slug = NEW.id; END IF; END '); } public function down() { // 回滚时先删除触发器 DB::unprepared('DROP TRIGGER IF EXISTS `articles_slug_default`'); Schema::dropIfExists('articles'); } };
注意事项
如果你的id是MySQL自增主键而非手动传入的UUID,creating事件触发时自增id还未生成,需要将事件换成created,此时会额外执行一次更新操作,而触发器方案不受该影响。
内容的提问来源于stack exchange,提问作者Michel Gisenäl
相关产品推荐
相关产品推荐

