简体   繁体   English

Django 信号@receiver POST_SAVE 不适用于 PROD(在 DEV 上正常)

[英]Django signals @receiver POST_SAVE not working on PROD (ok on DEV)

Getting nuts... On dev , my signals (for sending an alert by mail) works for all save (create + update) and delete.发疯了......在 dev 上,我的信号(用于通过邮件发送警报)适用于所有保存(创建+更新)和删除。 But on prod , only delete action sends an email. I didn't notice at once delete signals were working so I spent much time looking for an issue caused by firewall (blocked email outgoing).但是在 prod 上,只有删除操作会发送 email。我没有立即注意到删除信号正在工作,所以我花了很多时间寻找由防火墙引起的问题(阻止 email 传出)。

Post Save后保存

@receiver(post_save, sender=Navette)
def alerte(sender, instance, created, **kwargs):
    ref = instance.ref
    user = instance.user.username

    if created:
        alert(pour=['tintin@gmail.com'],
              sujet=f'Nouvelle navette pour la référence {ref} créé par {user}')
    else:
        alert(pour=['tintin@gmail.com'],
              sujet=f'Mise à jour de la navette pour la référence {ref} par {user}')

Post Delete删除后

@receiver(post_delete, sender=Navette)
def alerte(sender, instance, **kwargs):
    ref = instance.ref
    user = instance.user
    alert(pour=['tintin@gmail.com'],
          sujet=f'La navette pour la référence {ref} a été supprimée par {user}')

just for info: alert.py仅供参考:alert.py

def alert(**kwargs):

    #ref = kwargs.get('ref', 'noref')
    de = kwargs.get('de', 'toto@gmail.com')
    pour = kwargs.get('pour', 'tintin@gmail.com')
    sujet = kwargs.get('sujet', 'Sujet Général')
    contenu = kwargs.get('contenu', 'cf. objet du mail')
    fichier = kwargs.get('fichier', '')

    host = 'smtp.gmail.com'
    port = 465
    user = settings.EMAIL_HOST_USER
    passw = settings.EMAIL_HOST_PASSWORD

    msg = EmailMessage()
    msg['Subject'] = sujet
    msg['From'] = de
    msg['To'] = pour
    msg.set_content('HTML uniquement')

    msg.add_alternative(contenu, subtype='html')

    with smtplib.SMTP_SSL(host, port) as smtp:
        smtp.login(user, passw)
        smtp.send_message(msg)

As said almost everywhere, I declared my app not just with its name in settings.py: 'navette.apps.NavetteConfig', and registrered the app config in its __init__ -> default_app_config = 'navette.apps.ActivityAppConfig' even if I thought Ik heard it was not necessary anymore on DJANGO 3.正如几乎所有地方所说的那样,我不仅在 settings.py: 'navette.apps.NavetteConfig',而且在其__init__ -> default_app_config = 'navette.apps.ActivityAppConfig'中注册了应用程序配置,即使我认为Ik 听说在 DJANGO 3 上没有必要了。

Finally, heres my apps.py for this app最后,这是我的应用程序的 apps.py

from django.apps import AppConfig


class NavetteConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'navette'

    def ready(self):
        import navette.signals

Any idea?任何的想法?

EDIT编辑

navette.views navette.views

@login_required
def NavetteCreateView(request):
    form = NavetteDetailForm(request.POST)
    if request.method == 'POST':
        form = NavetteDetailForm(request.POST)
        if form.is_valid():
            form.save()
            navette_ref = form.cleaned_data.get('ref')
            logr.debug(f'{navette_ref} - enregistrée')
            messages.success(
                request, f'La navette {navette_ref} a bien 
        été créée.')
            return redirect('/navettes')
    else:
        form = NavetteDetailForm()

    context = {'form': form, 'title': 'Nouvelle Navette'}
    return render(request, 'navette/navette_form.html', 
context)

I checked the form_valid -> True我检查了 form_valid -> True

This is a workaround but if you are really going nuts over this you can try using the pre_save signal instead.这是一种解决方法,但如果您真的对此感到疯狂,您可以尝试使用pre_save信号。 With pre_save you can check manually whether the instance has an id , if it doesn't have it then it's a new object.使用pre_save你可以手动检查实例是否有id ,如果没有那么它是一个新的 object。

@receiver(pre_save, sender=Navette)
def alerte(sender, instance, **kwargs):
    ref = instance.ref
    user = instance.user.username

    if not instance.id:
        alert(pour=['tintin@gmail.com'],
              sujet=f'Nouvelle navette pour la référence {ref} créé par {user}')
    else:
        alert(pour=['tintin@gmail.com'],
              sujet=f'Mise à jour de la navette pour la référence {ref} par {user}')

It's possible that your receiver function is getting garbage-collected.您的接收器 function 可能正在被垃圾回收。

The Django docs say this on the subject: Django 文档就此主题进行了说明:

Note also that Django stores signal handlers as weak references by default, so if your handler is a local function, it may be garbage collected.另请注意,Django 默认将信号处理程序存储为弱引用,因此如果您的处理程序是本地 function,则可能会被垃圾回收。 To prevent this, pass weak=False when you call the signal's connect().为防止出现这种情况,请在调用信号的 connect() 时传递 weak=False。

Try using @receiver(post_save, sender=Navette, weak=False)尝试使用@receiver(post_save, sender=Navette, weak=False)

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

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