django - 如何加入这些 Django 模型?
问题描述
我应该如何加入这些 Django 模型以获取所有参与登录用户挑战的 Player 模型(请参阅 views.py 中名为 challenge_participants 的变量?我没有想出如何使用 Django 模型有效实现这一点的解决方案。谢谢很多!
示例数据:假设 John 已登录。正如我们在 PlayerChallenge 模型中看到的那样,他是挑战 1 和 2 的一部分。我要做的是获取属于挑战 1 的所有玩家对象(Roger 就是这个例子)以及属于挑战 2 一部分的所有玩家对象的第二个列表(本例中为 Roger 和 Claude)。
播放器型号
╔═══════════╦═════════╦════════════════╗
║ user_name ║ user_id ║ wallet_balance ║
╠═══════════╬═════════╬════════════════╣
║ John ║ 123 ║ 20 ║
║ Roger ║ 231 ║ 15 ║
║ Claude ║ 582 ║ 10 ║
╚═══════════╩═════════╩════════════════╝
挑战模式
╔════╦═════════╦══════╦════════╦═══════════════════╦══════════╦═══════════════════╦═══════════════╗
║ id ║ status ║ type ║ amount ║ created_timestamp ║ duration ║ started_timestamp ║ end_timestamp ║
╠════╬═════════╬══════╬════════╬═══════════════════╬══════════╬═══════════════════╬═══════════════╣
║ 1 ║ active ║ 1 ║ 20 ║ TimeStamp ║ 02:00:00 ║ TimeStamp ║ TimeStamp ║
║ 2 ║ waiting ║ 2 ║ 30 ║ TimeStamp ║ 04:00:00 ║ TimeStamp ║ TimeStamp ║
║ 3 ║ waiting ║ 1 ║ 35 ║ TimeStamp ║ 07:00:00 ║ TimeStamp ║ TimeStamp ║
╚════╩═════════╩══════╩════════╩═══════════════════╩══════════╩═══════════════════╩═══════════════╝
玩家挑战模型
╔════╦════════╦═══════════╦════════════════════╗
║ id ║ player ║ challenge ║ accepted_timestamp ║
╠════╬════════╬═══════════╬════════════════════╣
║ 1 ║ John ║ 1 ║ TimeStamp ║
║ 2 ║ Roger ║ 1 ║ TimeStamp ║
║ 3 ║ Roger ║ 2 ║ TimeStamp ║
║ 4 ║ Claude ║ 2 ║ TimeStamp ║
║ 5 ║ John ║ 2 ║ TimeStamp ║
╚════╩════════╩═══════════╩════════════════════╝
代码:
模型.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
# Create your models here.
class Player(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
#additional fields
userid = models.CharField(max_length=256)
wallet_balance = models.IntegerField(default=0)
def __str__(self):
return self.user.username
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Player.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.player.save()
class Challenge(models.Model):
id = models.IntegerField(primary_key=True, unique=True)
status = models.CharField(max_length=20)
type = models.CharField(max_length=20)
amount = models.DecimalField(max_digits=10, decimal_places=2)
created_timestamp = models.DateTimeField()
duration = models.DurationField()
started_timestamp = models.DateTimeField(null=True, blank=True)
end_timestamp = models.DateTimeField(null=True, blank=True)
def __str__(self):
return str(self.id)
class PlayerChallenge(models.Model):
user_challenge_id = models.IntegerField(primary_key=True, unique=True)
player = models.ForeignKey(Player, on_delete=models.CASCADE)
challenge = models.ForeignKey(Challenge, on_delete=models.CASCADE)
accepted_timestamp = models.DateTimeField(null=True, blank=True)
def __str__(self):
return str(self.user_challenge_id) + " (Player: " + str(self.player.user.username) + ", Challenge: " + str(self.challenge.id) + ")"
视图.py
from django.shortcuts import render
from django.http import HttpResponse
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponseRedirect, HttpResponse
from django.urls import reverse
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from challengeview.models import Player,Challenge,PlayerChallenge
@login_required
def index(request):
challenges = Challenge.objects.filter(playerchallenge__player = request.user.player)
challenges_participants = Player.objects.filter(playerchallenge__challenge = challenges)
my_dict = {
'challenges_participants' : challenges_participants,
'challenges' : challenges,
}
return render(request, "challengeview/index.html", context=my_dict)
多谢您的支持!
解决方案
在 Django 中,您不能像在简单的SQL表中那样对关系进行建模。有 3 种强大的关系类型OnetoOne, ForeignKey, ManytoMany
。从 django.utils 导入时区
class Player(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
#additional fields
userid = models.CharField(max_length=256)
wallet_balance = models.IntegerField(default=0)
challenges = models.ManyToMany('Challenge') #a challenge can be belonged to many players in this case
def __str__(self):
return self.user.username
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Player.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.player.save()
class Challenge(models.Model):
status = models.CharField(max_length=20)
type = models.CharField(max_length=20)
amount = models.DecimalField(max_digits=10, decimal_places=2)
duration = models.DurationField()
started_timestamp = models.DateTimeField(null=True, blank=True)
end_timestamp = models.DateTimeField(null=True, blank=True)
created_timestamp = models.DateTimeField()
def __str__(self):
return str(self.id)
class PlayerActivity(models.Model):
challenge = models.ForeingKey(on_delete=models.SET_NULL,
null=True,
related_name='activity_challenge')
created_by = models.ForeignKey(Player,
on_delete=models.SET_NULL,
null=True,
related_name='activity_created_by')
created_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return str(self.user_challenge_id) + " (Player: " + str(self.player.user.username) + ", Challenge: " + str(self.challenge.id) + ")"
如果一个挑战只能属于一个玩家,但一个玩家可以有很多挑战,那么Foreignkey。如果一个玩家可以有很多挑战并且一个挑战可以属于许多玩家,那么 ManyToMany。
当您使用查询时,您应该始终考虑发送到后端的请求。您可以使用select_related
最小化请求。
all_challenges = Challenge.objects.all()
logged_user_challenges = Player.objects.filter(user=request.user,challenges__in=all_challenges)
others_same_challenges = Player.objects.filter(challenges=logged_user_challenges.challenges)
或者
logged_user_challenges = PlayerActivity.objects.filter(user=request.user).latest('created_at')
但是你会遇到其他人的问题......你需要一个循环来获取所有内容,这只是不建议。
注意:您必须在视图中操作数据节省。
推荐阅读
- twitter-bootstrap - 我的 Bootstrap 布局包含我想删除的大间隙
- c - 拖动滚动实现?
- python - 根据另一列中的非空值计算一列中的唯一值
- spring-boot - 生成的字段与我在实体中定义的不匹配
- python - 字典在迭代过程中改变了大小,在深度复制之后,python
- swiftui - 将消息从子视图发布到父视图
- python - Windows bash shell 显示错误的 Python 版本
- version - 如何在 Racket 中获取已安装软件包的版本号
- javascript - 出现错误:DeprecationWarning: Buffer(),仅在使用 IISNode 部署网站时
- filter - PowerBI中高级分组完成的百分比?