我正在尝试实现自定义信号,但是我以前从未做过,所以我似乎搞砸了。
这是我来自models.py的代码:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save, post_delete
from django.dispatch import Signal
from django.db.models import Max,Count
from django.apps import apps
# Create your models here.
class Player(models.Model):
player_name = models.CharField(max_length=150)
current_level_no = models.IntegerField(null=True)
no_of_moves = models.IntegerField(null=True)
class Meta:
verbose_name_plural = 'Players'
def __str__(self):
return self.player_name
class PlayerStats(models.Model):
player_name = models.ForeignKey(to=Player, on_delete=models.CASCADE)
level_no = models.IntegerField(null=True)
moves = models.IntegerField(null=True)
class Meta:
verbose_name_plural = 'Players Stats'
# It works!
TotalLevels = 25
MaxCurrentLevel = PlayerStats.objects.aggregate(max_levels=Max('level_no'))['max_levels']
PlayerCount = Player.objects.aggregate(count_players=Count('player_name', distinct=True))['count_players']
def create_player(sender, instance, created, **kwargs):
if created:
new_username=instance.username
Player.objects.create(player_name=new_username, current_level_no=None, no_of_moves=None)
def delete_player(sender, instance, **kwargs):
deleted_username=instance.username
Player.objects.filter(player_name=deleted_username).delete()
def create_player_stat(sender, instance, **kwargs):
for x in range(1, TotalLevels+1):
PlayerStats.objects.create(player_name=instance, level_no=x, moves=None)
UpdateLevelsSignal = Signal(providing_args=['Update'])
if MaxCurrentLevel != TotalLevels and PlayerCount != 0:
UpdateLevelsSignal.send(UpdateLevelsSignal,Update=True)
def UpdateLevels(sender, Update,**kwargs):
if Update:
if MaxCurrentLevel < TotalLevels:
for x in Player.objects.all().values_list('player_name', flat=True):
instance = Player.objects.get(player_name=x)
for y in range(TotalLevels-MaxCurrentLevel, TotalLevels+1):
PlayerStats.objects.create(player_name=instance, level_no=y, moves=None)
else:
for x in Player.objects.all().values_list('player_name', flat=True):
instance = Player.objects.get(player_name=x)
for y in range(MaxCurrentLevel-TotalLevels, MaxCurrentLevel+1):
PlayerStats.objects.filter(player_name=instance, level_no=y, moves=None).delete()
post_save.connect(create_player, sender=User)
post_delete.connect(delete_player, sender=User)
post_save.connect(create_player_stat, sender=Player)
UpdateLevelsSignal.connect(UpdateLevels, sender=UpdateLevelsSignal)
基本上是根据某些条件创建或删除某些模型对象的信号,没有什么花哨的。但是,当我检查模型对象时,触发条件并没有发生任何变化。
如果有人可以指出我在这里做错了什么或提出解决方案,那将会很有帮助!
一如既往,非常感谢您的回答!
答案 0 :(得分:1)
这不会解决您的问题,但是我不想在评论中添加它。您应将信号和接收器移动到它们自己的文件中的原因是限制了模型文件中有多少业务逻辑。此外,它在处理多个应用程序时具有更大的可扩展性。
project/
app1/
apps.py
models.py
signals.py
receivers.py
app2/
apps.py
models.py
receivers.py
在上面的每个应用中,apps.py文件将类似于:
class App1Config(AppConfig):
def ready(self):
# This makes Django load up the register the connected receivers.
from project.app1 import receivers, signals
您希望将接收器移动到其自己的文件中的原因部分是由于要触发仅影响app2
中的模型/对象但由某个模型中的某个事件触发的函数的情况app1
。例如:
#project/app2/receivers.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from project.app1.models import Foo
from .models import Bar
@receiver(post_save, sender=Foo)
def create_bar_for_foo(instance, created, *, raw=False, **kwargs):
if created:
Bar.objects.create(foo=foo)
您可以在app2/models.py
中安装该接收器,但是感觉不正确。如果它是与基于模型的事件无关的自定义信号,那将感觉特别陌生。
我希望Django文档能够尝试解释如何组织信号和接收器,但是Django的《 Two Scoops》一书在解释它方面做得很好。