首页 > 解决方案 > 如何为 Django Web App 中的每个用户获取唯一的用户数据

问题描述

我正在使用 Django 创建一个 WebApp 作为个人项目。这个应用程序跟踪远足挑战,并使用 API 从天气数据库中获取天气。我目前的问题是创建一个数据库结构,该结构将是一个很好的设计并且将来可以扩展。

目前,我有两个表。(Django 模型)

class Mountain(models.Model):
    mnt_name = models.CharField(max_length=100)
    latitude = models.FloatField()
    longitude = models.FloatField()
    elevation = models.IntegerField(default=0)
    distance = models.IntegerField(default=0)
    users_completed = models.ManyToManyField(User)
    # Commented from code to prevent issues
    # date_done = models.DateTimeField(blank=True, null=True, default=None)
    
    def __str__(self):
        return self.mnt_name

 class Challenge(models.Model):
    challenge_name = models.CharField(max_length=101)
    mountains = models.ManyToManyField(Mountain)
    
    def __str__(self):
        return self.challenge_name

我有一些我正在寻找的功能。我可以遍历列表users_completed并将它们与当前登录的用户进行比较,如果用户在列表中,则更新完成状态。但这不是一个好的解决方案,因为我无法完成用户特定的日期以及其他原因。

直觉上,我认为解决此问题的最佳方法是为每个用户配置文件添加每个挑战的副本,以便用户可以获得特定于用户的数据,例如完成状态和完成日期。但我不确定我将如何去做,或者是否有可能。

关于我应该如何重新排列我的模型的任何建议,以便我可以获得特定于用户的数据,例如山是否已完成,以及完成日期等。

非常感谢所有帮助。谢谢你。

标签: pythonsqldjangodatabase

解决方案


我可能会使用双重through实现。

from django.db import models
from django.contrib.auth.models import User


class Mountain(models.Model):
    mnt_name = models.CharField(max_length=100)
    latitude = models.FloatField()
    longitude = models.FloatField()
    elevation = models.IntegerField(default=0)
    distance = models.IntegerField(default=0)


class MountainChallenge(models.Model):
    """This allows you to use the same mountain in multiple challenges."""
    mountain = models.ForeignKey(Mountain, on_delete=models.CASCADE)
    challenge = models.ForeignKey("Challenge", on_delete=models.CASCADE)
    users_completed = models.ManyToManyField(User, through="UserMountain")


class UserMountain(models.Model):
    """This associates a user to a MoutainChallenge while storing other data."""
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    mountain_challenge = models.ForeignKey(MountainChallenge, on_delete=models.CASCADE)
    date = models.DateTimeField()


class Challenge(models.Model):
    challenge_name = models.CharField(max_length=101)
    mountains = models.ManyToManyField(Mountain, through="MountainChallenge")

注意我没有测试过这段代码。

  • Moutain您独立于挑战存储对象。
  • 您有一个MoutainChallenge代表 aMountain作为 a 的一部分Challenge
  • 它不能简单ManyToMany,因为您要关联已完成山的用户列表
  • 这样做UserMountain可以保存与成就相关的日期或其他事情
  • 在您的应用程序的业务方面,当UserMountain实现 a 时,您应该检查当前用户是否已实现当前用户的所有MoutainChallengesChallenge

希望这在没有过度设计的情况下是有意义的。

我认为它为未来的扩展留下了空间。


推荐阅读