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
问题定位
- 模型与视图字段不匹配:
Playlist模型未定义music_ids和plays字段,但视图中多处直接操作这两个字段,导致Django无法识别字段,或读取到非法数据。 - 字段类型不匹配:
Song的song_id是数值型AutoField,但LikedSong的music_id定义为CharField,默认值是字符串"name"。用非数值的music_id查询Song时,会触发类型错误。 - 字符串切片风险:
addSongToPlaylist中song_id = ids[0][2:]如果输入格式错误(比如ids[0]长度不足2),会直接得到空字符串,存入后查询Song引发错误。 - 无输入校验:多个视图直接从
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
相关产品推荐
相关产品推荐

