You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django项目执行migrate命令触发ValueError错误求助

Django migrate报错:ValueError: Field 'song_id' expected a number but got ''

我用Django开发音乐流媒体网站,执行migrate命令时触发错误:ValueError: Field 'song_id' expected a number but got '',不清楚song_id为何会拿到空字符串,需要定位问题代码并修复。


视图代码(views.py)

def myPlaylist(request, id):
user = request.user
if user.is_authenticated:
    # Extracting Playlists of the Authenticated User
    myPlaylists = list(Playlist.objects.filter(user=user))
if user.is_authenticated:
    if request.method == "POST":
        song_id = request.POST["music_id"]
        playlist = Playlist.objects.filter(playlist_id=id).first()
        if song_id in playlist.music_ids:
            playlist.music_ids.remove(song_id)
            playlist.plays -= 1
            playlist.save()
        message = "Successfull"
        print(message)
        return HttpResponse(json.dumps({'message': message}))
    else:
        images = os.listdir("music_app/static/PlaylistImages")
        print(images)
        randomImagePath = random.choice(images)
        randomImagePath = "PlaylistImages/" + randomImagePath
        print(randomImagePath)
        currPlaylist = Playlist.objects.filter(playlist_id=id).first()
        music_ids = currPlaylist.music_ids
        playlistSongs = []
        recommendedSingers = []
        for music_id in music_ids:
            song = Song.objects.filter(song_id=music_id).first()
            random.shuffle(recommendedSingers)
            recommendedSingers = list(set(recommendedSingers))[:6]
            playlistSongs.append(song)

        return render(request, "myPlaylist.html", {'playlistInfo': currPlaylist,
                                                       'playlistSongs': playlistSongs,
                                                       'myPlaylists': myPlaylists,
                                                       'recommendedSingers': recommendedSingers,
                                                       'randomImagePath': randomImagePath})
def addSongToPlaylist(request):
user = request.user
if user.is_authenticated:
    try:
        data = request.POST['data']
        ids = data.split("|")
        song_id = ids[0][2:]
        playlist_id = ids[1][2:]
        print(ids[0][2:], ids[1][2:])
        currPlaylist = Playlist.objects.filter(playlist_id=playlist_id).first()
        if song_id not in currPlaylist.music_ids:
            currPlaylist.music_ids.append(song_id)
            currPlaylist.plays = len(currPlaylist.music_ids)
            currPlaylist.save()
        return HttpResponse("Successfull")
    except:
        return redirect("/")
    # return redirect("/")
else:
    return redirect("/")

def likesong(request):
myPlaylists = []
try:
    # print("Request Submitted Successfully!!!")
    user = request.user
    if user.is_authenticated:
        # Extracting Playlists of the Authenticated User
        myPlaylists = list(Playlist.objects.filter(user=user))
    if user.is_authenticated:
        if request.method == "POST":
            song_id = request.POST["music_id"]
            isPresent = False
            if LikedSong.objects.filter(user=user, music_id=song_id).exists():
                isPresent = True

            if isPresent:
                LikedSong.objects.filter(user=user, music_id=song_id).delete()
                # print(f"Your song is removed from the liked song id: {song_id}")
            else:
                like = LikedSong(user=user, music_id=song_id)
                like.save()
                # print(f"Your song successfully added id: {song_id}")
            message = "Successfull"
            return HttpResponse(json.dumps({'message': message}))
        else:
            like = LikedSong.objects.filter(user=user)
            ids = []
            for i in like:
                ids.append(i.music_id)
            preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(ids)])
            likedSongs = Song.objects.filter(song_id__in=ids).order_by(preserved)
            return render(request, "likedSong.html", {'likedSongs': likedSongs})
    else:
        # print("User is not authenticated")
        return redirect("/")
except:
    return redirect("/")

模型代码(models.py)

class Song(models.Model):
song_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50)
artist = models.CharField(max_length=50)
album = models.CharField(max_length=50, blank=True)
song = models.FileField(upload_to="media/songs/", validators=[FileExtensionValidator(allowed_extensions=['mp3', 'wav'])], default="name")
image = models.ImageField(upload_to="media/songimage/", validators=[FileExtensionValidator(allowed_extensions=['jpeg', 'jpg', 'png'])], default="https://placehold.co/300x300/png")
data = models.DateTimeField(auto_now=False, auto_now_add=True)
slug = models.SlugField()

def __str__(self):
    return self.name

class Meta:
    ordering = ['name']


class Playlist(models.Model):
    playlist_id = models.AutoField(primary_key=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=50, default="name")
    image = models.ImageField(upload_to="media/images/", validators=[FileExtensionValidator(allowed_extensions=['jpeg', 'jpg', 'png'])])
    slug = models.SlugField()

    def __str__(self):
        return self.user.first_name


class LikedSong(models.Model):
    liked_id = models.AutoField(primary_key=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    music_id = models.CharField(max_length=50, default="name")

    def __str__(self):
        return self.user.first_name

问题定位

  1. 模型与视图字段不匹配:Playlist模型未定义music_ids和plays字段,但视图中多处直接操作这两个字段,导致Django无法识别字段,或读取到非法数据。
  2. 字段类型不匹配:Song的song_id是数值型AutoField,但LikedSong的music_id定义为CharField,默认值是字符串"name"。用非数值的music_id查询Song时,会触发类型错误。
  3. 字符串切片风险:addSongToPlaylist中song_id = ids[0][2:]如果输入格式错误(比如ids[0]长度不足2),会直接得到空字符串,存入后查询Song引发错误。
  4. 无输入校验:多个视图直接从request.POST获取song_id,未校验是否为有效数值,空值或非法字符串直接传入查询会触发错误。

修复方案

1. 修正Playlist模型,补充缺失字段

使用JSONField存储歌曲ID数组,添加播放数字段:

from django.db.models import JSONField

class Playlist(models.Model):
    playlist_id = models.AutoField(primary_key=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=50, default="name")
    image = models.ImageField(upload_to="media/images/", validators=[FileExtensionValidator(allowed_extensions=['jpeg', 'jpg', 'png'])])
    slug = models.SlugField()
    # 新增字段
    music_ids = JSONField(default=list)  # 存储歌曲ID数组
    plays = models.IntegerField(default=0)  # 播放次数

    def __str__(self):
        return self.user.first_name

2. 修正LikedSong的music_id字段类型

改为IntegerField,匹配Song的song_id类型:

class LikedSong(models.Model):
    liked_id = models.AutoField(primary_key=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    music_id = models.IntegerField()  # 替换CharField为IntegerField,移除默认字符串

    def __str__(self):
        return self.user.first_name

注意:若数据库已有旧数据,需先清理或迁移数据,避免类型转换错误。

3. 修复addSongToPlaylist的切片逻辑,添加输入校验

确保ID为有效数值,避免空值:

def addSongToPlaylist(request):
    user = request.user
    if user.is_authenticated:
        try:
            data = request.POST.get('data', '')
            if not data:
                return HttpResponse("Invalid input")
            ids = data.split("|")
            if len(ids) < 2:
                return HttpResponse("Invalid data format")
            # 优化切片逻辑,确保获取有效ID
            song_id_str = ids[0].strip()
            if song_id_str.startswith('id'):
                song_id_str = song_id_str[2:]
            playlist_id_str = ids[1].strip()
            if playlist_id_str.startswith('id'):
                playlist_id_str = playlist_id_str[2:]
            # 校验是否为有效整数
            if not song_id_str.isdigit() or not playlist_id_str.isdigit():
                return HttpResponse("Invalid ID format")
            song_id = int(song_id_str)
            playlist_id = int(playlist_id_str)
            
            currPlaylist = Playlist.objects.filter(playlist_id=playlist_id).first()
            if not currPlaylist:
                return HttpResponse("Playlist not found")
            if song_id not in currPlaylist.music_ids:
                currPlaylist.music_ids.append(song_id)
                currPlaylist.plays = len(currPlaylist.music_ids)
                currPlaylist.save()
            return HttpResponse("Successfull")
        except Exception as e:
            print(f"Error: {e}")
            return redirect("/")
    else:
        return redirect("/")

4. 为所有操作song_id的视图添加输入校验

比如myPlaylist和likesong的POST请求:

# myPlaylist POST部分修改
song_id_str = request.POST.get("music_id", "")
if not song_id_str.isdigit():
    return HttpResponse(json.dumps({'message': 'Invalid song ID'}), status=400)
song_id = int(song_id_str)

# likesong POST部分修改
song_id_str = request.POST.get("music_id", "")
if not song_id_str.isdigit():
    return HttpResponse(json.dumps({'message': 'Invalid song ID'}), status=400)
song_id = int(song_id_str)

5. 重新执行迁移命令

完成模型修改后,备份数据后执行:

python manage.py makemigrations
python manage.py migrate

内容的提问来源于stack exchange,提问作者Federico Monetti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 05:34:53