简体   繁体   English

在Django中,是否可以看出是哪个方法生成了SQL查询?

[英]In Django, is it possible to see which method is generating a SQL query?

When creating a custom User (inherits from AbstractUser ) we have a signal which creates a randomized password (from Django's get_random_string ) and send it out in an email in a celery task to the user.当创建自定义用户(继承自AbstractUser )时,我们有一个信号创建一个随机密码(来自 Django 的get_random_string )并在 celery 任务中将其发送给用户的 email 。

# accounts/models.py
class User(AbstractUser):
    # ...

    def save(self, *args, **kwargs):
        if self.avatar:
            self.avatar = resized_image(self.avatar, settings.SOCIAL_AVATAR_SIZE)
        super().save(*args, **kwargs)

resized_image returns from django.core.files.uploadedfile import InMemoryUploadedFile resized_image from django.core.files.uploadedfile import InMemoryUploadedFile返回

# accounts/signals.py
@receiver(post_save, sender=User, dispatch_uid="c_employee")
def create_employee(sender, instance: User, created, **kwargs):
    if not instance.has_usable_password():
        password = get_random_string(length=12)

    email_args = {  # we're collecting information for the celery task
        "password": password,
    }
    email_send_as_task.delay(
        email_args, "Sending PASSWORD CREATE email to {{ instance.email }}"
    )
    
    if password:
        logger.debug(f"CREATE PASSWORD FOR INSTANCE: {instance}")
        sender.objects.filter(pk=instance.pk).update(password=make_password(password))  # .update so we don't trigger signal again

And looking through my (logging level DEBUG ) logs, I can see the following:查看我的(日志记录级别DEBUG )日志,我可以看到以下内容:

D0121 18:55:35.434 accounts.signals:81 CREATE PASSWORD FOR INSTANCE: Employee @ Example
D0121 18:55:35.641 django.db.backends:123 (0.000) UPDATE "accounts_user" SET "password" = 'pbkdf2_sha256$260000$FKRktQOZAwQ4OjcvD3QHGn$dmg9T1Y3mEwN1nbI5W2EyOAHp2chU4MGvSlaOTORNxY=' WHERE "accounts_user"."id" = 394; args=('pbkdf2_sha256$260000$FKRktQOZAwQ4OjcvD3QHGn$dmg9T1Y3mEwN1nbI5W2EyOAHp2chU4MGvSlaOTORNxY=', 394)

So far so good.到目前为止,一切都很好。

But then, later in the logs, this query appears:但是,稍后在日志中,会出现以下查询:

D0121 18:55:35.770 django.db.backends:123 (0.015) UPDATE "accounts_user" SET "password" = '', "last_login" = NULL, "is_superuser" = false, "username" = 'employee@example.com', "first_name" = 'First name', "last_name" = 'Employee', "email" = 'employee@example.com', "is_staff" = false, "is_active" = true, "date_joined" = '2023-01-21T17:55:35.044046+00:00'::timestamptz, "company_id" = 20, "venue_id" = 297, "avatar" = 'users/avatar.jpg', "is_admin" = false, "is_developer" = true, "role" = 'event', "allow_update" = true, "device_id" = NULL WHERE "accounts_user"."id" = 394; args=('', False, 'employee@example.com', 'First name', 'Employee', 'employee@example.com', False, True, datetime.datetime(2023, 1, 21, 17, 55, 35, 44046, tzinfo=<UTC>), 20, 297, 'users/avatar.jpg', False, True, 'event', True, 394)

My question is thus: why is the password re-set to empty string?因此,我的问题是:为什么将密码重新设置为空字符串? And how do I go about debugging/understanding where this query originates from?我 go 如何调试/了解此查询的来源?

TYIA蒂亚

Apparently it seems that we're running into a race-condition when writing to the DB.显然,我们在写入数据库时似乎遇到了竞争条件。 It seems that calling a method outside of the signal doesn't trigger another call to the post_save signal when we're already inside it.当我们已经在信号内部时,似乎在信号外部调用方法不会触发对post_save信号的另一次调用。

This is how the working solution looks like atm:这就是工作解决方案看起来像 atm 的方式:

# accounts/signals.py
from accounts.utils import create_password


@receiver(post_save, sender=User, dispatch_uid="c_employee")
def create_employee(sender, instance: User, created, **kwargs):
    if not instance.has_usable_password():
        logger.debug(f"CREATE PASSWORD FOR INSTANCE: {instance}")
        password = create_password(obj=instance)

    email_args = {  # we're collecting information for the celery task
        "password": password,
    }
    email_send_as_task.delay(
        email_args, "Sending PASSWORD CREATE email to {{ instance.email }}"
    )

and in the utils.py file:utils.py文件中:

# accounts/utils.py
from django.utils.crypto import get_random_string


def create_password(obj=None, length=12):
    password = get_random_string(length=length)
    if obj is not None:
        obj.set_password(password)
        obj.save()
    return password

I have to surmise that there is some Django magic I yet haven't understood.我不得不推测有一些 Django 魔法我还没有理解。 Unfortunatelly this doesn't answer the question in the headline but using .save() instead of .update() solved my problem.不幸的是,这并没有回答标题中的问题,但使用.save()而不是.update()解决了我的问题。

The comment from @peter-deglopper pointed me in the right direction. @peter-deglopper的评论为我指明了正确的方向。 Thanks!谢谢!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM