Django游戏应用:如何按登录用户等级展示解锁游戏?
问题描述
我正在开发一款游戏应用,已登录用户可根据其在应用中的等级(rank)访问不同游戏。例如,若登录用户的等级为100,则展示等级(game_rank)≤100的所有游戏,其余游戏将处于锁定状态。
目前我的HTML仅能显示通用的锁定/解锁游戏状态,无法实现用户针对性展示。现咨询实现该功能的最优方案:如何基于登录用户的等级展示可解锁的游戏?
相关字段说明
- 游戏等级为
Game_Info模型的game_rank字段 - 登录用户的等级为
User_Info模型的rank字段
现有代码
models.py
class Game_Info(models.Model): id = models.IntegerField(primary_key=True, unique=True, blank=True, editable=False) game_title = models.CharField(max_length=100, null=True) game_rank = models.CharField(max_length=1000, null=True, blank=True) game_image = models.ImageField(default='default.png', upload_to='game_covers', null=True, blank=True) locked_game = models.BooleanField(default=0) unlocked_game = models.BooleanField(default=0) class User_Info(models.Model): id = models.IntegerField(primary_key=True, blank=True) image = models.ImageField(default='/profile_pics/default.png', upload_to='profile_pics', null=True, blank=True) user = models.OneToOneField(settings.AUTH_USER_MODEL,blank=True, null=True, on_delete=models.CASCADE) rank = models.CharField(max_length=100, null=True, blank=True, default=1) user_games_enabled = models.ManyToManyField(Game_Info, blank=True, limit_choices_to={'unlocked_game': True})
home.html
{% for content in user_profile_games %} {% if content.locked_game == True %} <a class="game-tile-container" href="{% url 'detail' content.pk %}"> <div class="locked_game" style="padding-right: 5px;"> <div class="image-wrapper"> <img class="game-art" src="{{content.game_image.url }}" /> <img class="lock-img" src={% static 'images/treasure-chest-closed-alt.png' %} /> <button class="level-up">Reach level {{ content.game_rank }} to unlock</button> </div> </div> </a> <p class="game-title">{{ content.game_title }}</p> {% else %} {% endif %} {% endif %} {% if content.unlocked_game == True %} <a class="game-tile-container" href="{% url 'detail' content.pk %}"> <div class="image-wrapper" style="padding-right: 5px;"> <span class="material-icons play_btn">play_circle_filled</span> <img class="game-art" src="{{content.game_image.url }}" /> </div> </a> <p class="game-title">{{ content.game_title }}</p> {% endif %} {% endif %} {% endfor %}
views.py
def account_view_home(request): user_profile = User_Info.objects.all() user_profile_games = Game_Info.objects.all() user = request.user if request.user.is_authenticated: user_profile = User_Info.objects.filter(user=request.user) context = { 'user_profile': user_profile, 'user_profile_games' : user_profile_games } else: context = { 'user_profile': user_profile, 'user_profile_games' : user_profile_games } return render(request, 'home.html', context)
解决方案
1. 修正字段类型(核心问题)
当前rank和game_rank用了CharField,无法直接做数值大小比较,必须改成IntegerField。另外locked_game和unlocked_game这两个固定布尔字段完全没必要——游戏是否解锁是动态基于用户等级判断的,不需要存在数据库中。修改后的模型:
# models.py class Game_Info(models.Model): id = models.IntegerField(primary_key=True, unique=True, blank=True, editable=False) game_title = models.CharField(max_length=100, null=True) # 改为IntegerField,支持数值比较,默认等级1 game_rank = models.IntegerField(null=True, blank=True, default=1) game_image = models.ImageField(default='default.png', upload_to='game_covers', null=True, blank=True) # 移除固定锁定/解锁字段 # locked_game = models.BooleanField(default=0) # unlocked_game = models.BooleanField(default=0) class User_Info(models.Model): id = models.IntegerField(primary_key=True, blank=True) image = models.ImageField(default='/profile_pics/default.png', upload_to='profile_pics', null=True, blank=True) user = models.OneToOneField(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.CASCADE) # 改为IntegerField,默认等级1 rank = models.IntegerField(null=True, blank=True, default=1) # 若不需要手动解锁游戏(如付费解锁)可移除该字段;需要则保留,后续模板逻辑调整 # user_games_enabled = models.ManyToManyField(Game_Info, blank=True)
修改后执行数据库迁移:
python manage.py makemigrations python manage.py migrate
2. 优化视图逻辑
获取当前登录用户的等级并传递给模板,用get_or_create避免用户未创建User_Info实例的情况:
# views.py def account_view_home(request): user_profile_games = Game_Info.objects.all() user_rank = 0 # 未登录用户默认等级设为0,可按需调整 user_profile = None if request.user.is_authenticated: # 获取或创建当前用户的User_Info实例 user_profile, created = User_Info.objects.get_or_create(user=request.user) user_rank = user_profile.rank or 1 # 处理rank为None的情况 context = { 'user_profile': user_profile, 'user_profile_games': user_profile_games, 'user_rank': user_rank } return render(request, 'home.html', context)
3. 重构模板判断逻辑
直接用user_rank和游戏的game_rank做数值比较,动态显示锁定/解锁状态:
<!-- home.html --> {% for content in user_profile_games %} {% if user_rank >= content.game_rank %} <!-- 解锁状态:展示可玩游戏卡片 --> <a class="game-tile-container" href="{% url 'detail' content.pk %}"> <div class="image-wrapper" style="padding-right: 5px;"> <span class="material-icons play_btn">play_circle_filled</span> <img class="game-art" src="{{ content.game_image.url }}" /> </div> </a> <p class="game-title">{{ content.game_title }}</p> {% else %} <!-- 锁定状态:展示带锁卡片 --> <a class="game-tile-container" href="{% url 'detail' content.pk %}"> <div class="locked_game" style="padding-right: 5px;"> <div class="image-wrapper"> <img class="game-art" src="{{ content.game_image.url }}" /> <img class="lock-img" src="{% static 'images/treasure-chest-closed-alt.png' %}" /> <button class="level-up">Reach level {{ content.game_rank }} to unlock</button> </div> </div> </a> <p class="game-title">{{ content.game_title }}</p> {% endif %} {% endfor %}
可选:支持手动解锁游戏
若需要给用户手动解锁游戏(如付费、活动奖励),保留user_games_enabled字段后,修改模板判断条件:
{% for content in user_profile_games %} {% if user_rank >= content.game_rank or (user_profile and content in user_profile.user_games_enabled.all) %} <!-- 解锁状态 --> ... {% else %} <!-- 锁定状态 --> ... {% endif %} {% endfor %}
内容的提问来源于stack exchange,提问作者spidey677
相关产品推荐
相关产品推荐

