标签: django-signals

TransactionManagementError"在使用信号时,您不能在"原子"块结束之前执行查询,但仅在单元测试期间执行

我在尝试保存Django User模型实例时遇到TransactionManagementError,并在其post_save信号中,我保存了一些将用户作为外键的模型.

在使用信号时,上下文和错误与此问题django TransactionManagementError非常相似

但是,在这种情况下,错误仅在单元测试时发生.

它在手动测试中运行良好,但单元测试失败.

有什么我想念的吗?

以下是代码段:

views.py

@csrf_exempt
def mobileRegister(request):
    if request.method == 'GET':
        response = {"error": "GET request not accepted!!"}
        return HttpResponse(json.dumps(response), content_type="application/json",status=500)
    elif request.method == 'POST':
        postdata = json.loads(request.body)
        try:
            # Get POST data which is to be used to save the user
            username = postdata.get('phone')
            password = postdata.get('password')
            email = postdata.get('email',"")
            first_name = postdata.get('first_name',"")
            last_name = postdata.get('last_name',"")
            user = User(username=username, email=email,
                        first_name=first_name, last_name=last_name)
            user._company = postdata.get('company',None)
            user._country_code = postdata.get('country_code',"+91")
            user.is_verified=True …
Run Code Online (Sandbox Code Playgroud)

python django unit-testing django-signals

172
推荐指数
4
解决办法
5万
查看次数

Django信号与重写保存方法

我在缠绕这个问题时遇到了麻烦.现在我有一些看起来像这样的模型:

 def Review(models.Model)
    ...fields...
    overall_score = models.FloatField(blank=True)

def Score(models.Model)
    review = models.ForeignKey(Review)
    question = models.TextField()
    grade = models.IntegerField()
Run Code Online (Sandbox Code Playgroud)

评论有几个"分数",整体分数是分数的平均值.保存评论或分数时,我需要重新计算total_score平均值.现在我正在使用重写的保存方法.使用Django的信号调度程序会有什么好处吗?

python django django-signals django-models

81
推荐指数
3
解决办法
2万
查看次数

保持我的signals.py文件在Django项目中的正确位置

基于我正在阅读的Django文档,似乎signals.py在app文件夹中是一个很好的开始,但我面临的问题是,当我创建信号时pre_save,我尝试从模型中导入类,它与import在我的模型中.

# models.py

from django.contrib.auth.models import User
from django.db import models
from django.utils.translation import gettext as _
from signals import *

class Comm_Queue(CommunicatorAbstract):
    queue_statuses = (
        ('P', _('Pending')),
        ('S', _('Sent')),
        ('E', _('Error')),
        ('R', _('Rejected')),
    )
    status          = models.CharField(max_length=10, db_index=True, default='P')
    is_html         = models.BooleanField(default=False)
    language        = models.CharField(max_length=6, choices=settings.LANGUAGES)
    sender_email    = models.EmailField()
    recipient_email = models.EmailField()
    subject         = models.CharField(max_length=100)
    content         = models.TextField()
Run Code Online (Sandbox Code Playgroud)
# signals.py

from django.conf import settings
from django.db.models.signals import pre_save
from django.dispatch import receiver
from …
Run Code Online (Sandbox Code Playgroud)

django django-signals

76
推荐指数
6
解决办法
3万
查看次数

Django post_save()信号实现

我有一个关于django的问题.

我在这里有ManyToMany模型

class Product(models.Model):
     name = models.CharField(max_length=255)
     price = models.DecimalField(default=0.0, max_digits=9, decimal_places=2)
     stock = models.IntegerField(default=0)

     def  __unicode__(self):
         return self.name

class Cart(models.Model):
    customer = models.ForeignKey(Customer)
    products = models.ManyToManyField(Product, through='TransactionDetail')
    t_date = models.DateField(default=datetime.now())
    t_sum = models.FloatField(default=0.0)

    def __unicode__(self):
         return str(self.id)

class TransactionDetail(models.Model):
    product = models.ForeignKey(Product)
    cart = models.ForeignKey(Cart)
    amount = models.IntegerField(default=0)
Run Code Online (Sandbox Code Playgroud)

对于创建的1个购物车对象,我可以插入尽可能多的新TransactionDetail对象(产品和金额).我的问题是.我该如何实现触发器?我想要的是每当创建交易细节时,我希望产品库存的数量减去transactiondetail中的金额.

我读过有关post_save()但我不确定如何实现它.也许这样的事情

when:post_save(TransactionDetail,Cart)#Cart对象,其中TransactionDetail.cart = Cart.id

post_save(TransactionDetail, 
       Cart) #Cart object where TransactionDetail.cart= Cart.id
Cart.stock -= TransactionDetail.amount
Run Code Online (Sandbox Code Playgroud)

python django django-signals django-models

61
推荐指数
4
解决办法
7万
查看次数

覆盖Django的级联删除行为有哪些选择?

Django模型通常可以非常充分地处理ON DELETE CASCADE行为(以适用于本机不支持它的数据库的方式).

但是,我在努力发现在不适合的情况下覆盖此行为的最佳方法是什么,例如在以下场景中:

  • ON DELETE RESTRICT(即如果有子记录,则阻止删除对象)

  • ON DELETE SET NULL(即不删除子记录,但将其父键设置为NULL而不是断开关系)

  • 删除记录时更新其他相关数据(例如删除上传的图像文件)

以下是我所知道的实现这些目标的潜在方法:

  • 覆盖模型的delete()方法.虽然这种方法有效,但是当通过a删除记录时,它会被回避QuerySet.此外,delete()必须重写每个模型,以确保Django的代码永远不会被调用,super()并且无法调用,因为它可能使用a QuerySet来删除子对象.

  • 使用信号.这似乎是理想的,因为在直接删除模型或通过QuerySet删除时会调用它们.但是,不可能阻止删除子对象,因此无法实现ON CASCADE RESTRICT或SET NULL.

  • 使用正确处理此问题的数据库引擎(在这种情况下Django会做什么?)

  • 等到Django支持它(直到那时还有bug ...)

似乎第一种选择是唯一可行的选择,但它很难看,用洗澡水将婴儿扔出去,并且当添加新的模型/关系时可能会遗漏某些东西.

我错过了什么吗?有什么建议?

django django-signals cascading-deletes

57
推荐指数
3
解决办法
4万
查看次数

django - 在保存之前比较新旧字段值

我有一个django模型,我需要在保存之前比较字段的新旧值.

我已经尝试了save()继承和pre_save信号.它被正确触发,但我找不到实际更改字段的列表,无法比较新旧值.有一种方法?我需要它来优化预先行动.

谢谢!

python django django-signals

57
推荐指数
6
解决办法
3万
查看次数

Django:如何判断post_save信号是否在新对象上触发?

我需要对Django中新创建的对象进行一些后台后处理.此后处理应仅在新对象上运行,而不是刚刚更新的对象.

我知道在pre_save中我可以检查对象是否有id,如果没有则那么它是一个新对象.但问题是在后处理中我需要访问id(这样我就可以将结果保存回数据库).

我怎么能以干净的方式做到这一点?

django django-signals

48
推荐指数
3
解决办法
2万
查看次数

如何防止灯具与django post_save信号代码冲突?

在我的应用程序中,我想在新用户注册时在某些表中创建条目.例如,我想创建一个userprofile,然后引用他们的公司和其他一些记录.我用post_save信号实现了这个:

def callback_create_profile(sender, **kwargs):
    # check if we are creating a new User
    if kwargs.get('created', True):
        user = kwargs.get('instance')
        company = Company.objects.create(name="My Company")
        employee = Employee.objects.create(company=company, name_first=user.first_name, name_last=user.last_name)
        profile = UserProfile.objects.create(user=user, employee=employee, partner=partner)
# Register the callback
post_save.connect(callback_create_profile, sender=User, dispatch_uid="core.models")
Run Code Online (Sandbox Code Playgroud)

运行时效果很好.我可以使用admin创建一个新用户,其他三个表也可以获得合理的条目.(除此之外,员工因为user.first_name和user.last_name在保存时未在管理员表单中填写.我仍然不明白为什么这样做)

当我运行我的测试套件时出现问题.在此之前,我创建了一堆灯具来在表格中创建这些条目.现在我收到一条错误,指出:

IntegrityError: duplicate key value violates unique constraint "core_userprofile_user_id_key"
Run Code Online (Sandbox Code Playgroud)

我想这是因为我已经在id为"1"的灯具中创建了公司,员工和个人资料记录,现在post_save信号正在尝试重新创建它.

我的问题是:我可以在运行灯具时禁用此post_save信号吗?我可以检测到我作为测试套件的一部分运行而不是创建这些记录吗?我现在应该从灯具中删除这些记录吗(虽然信号只设置默认值而不是我想要测试的值)?为什么夹具加载代码不会覆盖创建的记录?

人们如何做到这一点?

python django signals django-signals fixtures

47
推荐指数
3
解决办法
8251
查看次数

我如何模拟django信号处理程序?

我有一个通过装饰器连接的signal_handler,这个非常简单:

@receiver(post_save, sender=User, 
          dispatch_uid='myfile.signal_handler_post_save_user')
def signal_handler_post_save_user(sender, *args, **kwargs):
   # do stuff
Run Code Online (Sandbox Code Playgroud)

我想做的是在测试中使用模拟库http://www.voidspace.org.uk/python/mock/进行模拟,以检查django调用它的次数.我的代码目前是这样的:

def test_cache():
    with mock.patch('myapp.myfile.signal_handler_post_save_user') as mocked_handler:
        # do stuff that will call the post_save of User
    self.assert_equal(mocked_handler.call_count, 1)
Run Code Online (Sandbox Code Playgroud)

这里的问题是即使被模拟也会调用原始的信号处理程序,这很可能是因为@receiver装饰器正在某处存储信号处理程序的副本,所以我在嘲笑错误的代码.

所以问题是:如何模拟我的信号处理程序以使我的测试工作?

请注意,如果我将信号处理程序更改为:

def _support_function(*args, **kwargs):
    # do stuff

@receiver(post_save, sender=User, 
          dispatch_uid='myfile.signal_handler_post_save_user')
def signal_handler_post_save_user(sender, *args, **kwargs):
   _support_function(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

而我嘲笑_support_function,一切都按预期工作.

python django signals mocking django-signals

43
推荐指数
2
解决办法
8264
查看次数

如何使用Django模型继承信号?

我在Django中有一些模型继承级别:

class WorkAttachment(models.Model):
    """ Abstract class that holds all fields that are required in each attachment """
    work            = models.ForeignKey(Work)
    added           = models.DateTimeField(default=datetime.datetime.now)
    views           = models.IntegerField(default=0)

    class Meta:
        abstract = True


class WorkAttachmentFileBased(WorkAttachment):
    """ Another base class, but for file based attachments """
    description     = models.CharField(max_length=500, blank=True)
    size            = models.IntegerField(verbose_name=_('size in bytes'))

    class Meta:
        abstract = True


class WorkAttachmentPicture(WorkAttachmentFileBased):
    """ Picture attached to work """
    image           = models.ImageField(upload_to='works/images', width_field='width', height_field='height')
    width           = models.IntegerField()
    height          = models.IntegerField()
Run Code Online (Sandbox Code Playgroud)

有许多不同的模型继承自WorkAttachmentFileBasedWorkAttachment …

python django django-signals

40
推荐指数
6
解决办法
8124
查看次数