📜  如何在 Django 中创建和使用信号?

📅  最后修改于: 2022-05-13 01:54:38.027000             🧑  作者: Mango

如何在 Django 中创建和使用信号?

信号用于对模型实例的修改执行任何操作。信号是帮助我们将事件与动作联系起来的实用程序。我们可以开发一个在信号调用时运行的函数。换句话说,信号用于对数据库中特定条目的修改/创建执行某些操作。例如,一旦在数据库中创建了一个新的用户实例,就希望创建一个配置文件实例

有 3 种类型的信号。

  1. pre_save/post_save :此信号在方法 save() 之前/之后起作用。
  2. pre_delete/post_delete :这个信号在删除模型的实例(方法 delete())之后这个信号被抛出之前起作用。
  3. pre_init/post_init :在实例化模型之前/之后抛出此信号(__init__() 方法)。

如何使用信号离子 Django?

例如,如果我们想在使用 post_save 信号创建用户后立即创建用户的个人资料

模型.py

Python3
from django.db import models
from django.contrib.auth.models import User
from PIL import Image
  
  
class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    image = models.ImageField(default='default.jpg', upload_to='profile_pics')
  
    def __str__(self):
        return f'{self.user.username} Profile'


Python3
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from .forms import UserRegisterForm, UserUpdateForm, ProfileUpdateForm
  
  
def register(request):
    if request.method == 'POST':
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            form.save()
            username = form.cleaned_data.get('username')
            messages.success(request, f'Your account has been created! You are now able to log in')
            return redirect('login')
    else:
        form = UserRegisterForm()
    return render(request, 'users/register.html', {'form': form})
  
  
@login_required
def profile(request):
    if request.method == 'POST':
        u_form = UserUpdateForm(request.POST, instance=request.user)
        p_form = ProfileUpdateForm(request.POST,
                                   request.FILES,
                                   instance=request.user.profile)
        if u_form.is_valid() and p_form.is_valid():
            u_form.save()
            p_form.save()
            messages.success(request, f'Your account has been updated!')
            return redirect('profile')
  
    else:
        u_form = UserUpdateForm(instance=request.user)
        p_form = ProfileUpdateForm(instance=request.user.profile)
  
    context = {
        'u_form': u_form,
        'p_form': p_form
    }
  
    return render(request, 'users/profile.html', context)


Python3
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import Profile
  
  
class UserRegisterForm(UserCreationForm):
    email = forms.EmailField()
  
    class Meta:
        model = User
        fields = ['username', 'email', 'password1', 'password2']
  
  
class UserUpdateForm(forms.ModelForm):
    email = forms.EmailField()
  
    class Meta:
        model = User
        fields = ['username', 'email']
  
  
class ProfileUpdateForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ['image']


Python3
# code
from django.db.models.signals import post_save, pre_delete
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile
  
  
@receiver(post_save, sender=User) 
def create_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)
   
@receiver(post_save, sender=User) 
def save_profile(sender, instance, **kwargs):
        instance.profile.save()


Python3
from django.apps import AppConfig
  
class UsersConfig(AppConfig):
    name = 'users'
  
    def ready(self):
        import users.signals


Python3
# code
from django.db.models.signals import post_save, pre_delete,pre_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile
  
  
@receiver(pre_save, sender=User) 
def checker(sender, instance, **kwargs):
    if instance.id is None:
        pass
    else:
      current=instance
      previous=User.objects.get(id=instance.id)
      if previous.reaction!= current.reaction:
               #save method can be called


视图.py

蟒蛇3

from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from .forms import UserRegisterForm, UserUpdateForm, ProfileUpdateForm
  
  
def register(request):
    if request.method == 'POST':
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            form.save()
            username = form.cleaned_data.get('username')
            messages.success(request, f'Your account has been created! You are now able to log in')
            return redirect('login')
    else:
        form = UserRegisterForm()
    return render(request, 'users/register.html', {'form': form})
  
  
@login_required
def profile(request):
    if request.method == 'POST':
        u_form = UserUpdateForm(request.POST, instance=request.user)
        p_form = ProfileUpdateForm(request.POST,
                                   request.FILES,
                                   instance=request.user.profile)
        if u_form.is_valid() and p_form.is_valid():
            u_form.save()
            p_form.save()
            messages.success(request, f'Your account has been updated!')
            return redirect('profile')
  
    else:
        u_form = UserUpdateForm(instance=request.user)
        p_form = ProfileUpdateForm(instance=request.user.profile)
  
    context = {
        'u_form': u_form,
        'p_form': p_form
    }
  
    return render(request, 'users/profile.html', context)

表单.py

蟒蛇3

from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import Profile
  
  
class UserRegisterForm(UserCreationForm):
    email = forms.EmailField()
  
    class Meta:
        model = User
        fields = ['username', 'email', 'password1', 'password2']
  
  
class UserUpdateForm(forms.ModelForm):
    email = forms.EmailField()
  
    class Meta:
        model = User
        fields = ['username', 'email']
  
  
class ProfileUpdateForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ['image']

Signals.py(使用接收器方法)

蟒蛇3

# code
from django.db.models.signals import post_save, pre_delete
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile
  
  
@receiver(post_save, sender=User) 
def create_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)
   
@receiver(post_save, sender=User) 
def save_profile(sender, instance, **kwargs):
        instance.profile.save()

如果您是 Django 的新手,您可能会对这段代码感到困惑,因此,当保存 User 模型时,会触发一个名为create_profile的信号,该信号创建一个 Profile 实例,外键指向用户的实例.另一种方法save_profile只是保存实例。

现在让我们了解这些论点



  • 接收器-谁接收信号,并且做了该函数。
  • sender – 发送信号
  • created — 检查模型是否已创建
  • instance — 创建的模型实例
  • **kwargs –通配符关键字参数

将信号与函数连接的另一种方法:

您需要将信号文件与 app.py 文件就绪函数连接起来才能使用它们。

蟒蛇3

from django.apps import AppConfig
  
class UsersConfig(AppConfig):
    name = 'users'
  
    def ready(self):
        import users.signals

信号在这里。

如果我们创建一个用户

 然后他的个人资料会自动创建。

您也可以在管理员视图中查看



pre_save 使用接收器方法 –

Pre_save 方法在调用 save函数之前触发,并且模型也只有在 pre_save 方法成功执行后才会保存

蟒蛇3

# code
from django.db.models.signals import post_save, pre_delete,pre_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile
  
  
@receiver(pre_save, sender=User) 
def checker(sender, instance, **kwargs):
    if instance.id is None:
        pass
    else:
      current=instance
      previous=User.objects.get(id=instance.id)
      if previous.reaction!= current.reaction:
               #save method can be called

如果反应发生变化,我们会使用它。

使用信号连接方法

上述方法的另一种方法是使用连接方法来触发信号。

如果你只使用 post_save.connect(my_function),那么只要任何 save 方法被触发,它就会被触发。

post_save.connect(my_function_post_save, sender=MyModel)
pre_save.connect(my_function, sender= UserTextMessage)