如何在Django中创建和使用信号
信号被用来执行任何关于修改模型实例的行动。信号是帮助我们将事件与行动联系起来的工具。我们可以开发一个函数,当一个信号调用它时,它就会运行。换句话说,信号被用来在数据库中修改/创建一个特定的条目时执行一些动作。例如,人们希望在数据库中创建一个新的用户实例时,立即创建一个配置文件实例。
有3种类型的信号。
- pre_save/post_save : 这个信号在save()方法之前/之后发挥作用。
- pre_delete/post_delete : 这个信号在删除一个模型的实例(方法delete())后抛出之前发挥作用。
- pre_init/post_init : 这个信号在实例化一个模型(
__init__()
方法)之前/之后抛出。
如何使用Signals ion Django
例如,如果我们想在使用post_save信号创建用户时立即创建一个用户的资料。
Models.py
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'
Views.py
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)
Forms.py
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(使用接收器方法)
# 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的新手,你可能会对这段代码感到困惑,那么正在发生的事情是,当用户模型被保存时,一个名为create_profile的信号被触发,它创建了一个Profile实例,其外键指向了用户的实例。另一个方法save_profile只是保存了这个实例。
现在我们来了解一下这些论点
- receiver – 接收信号并做某事的功能。
- sender – 发出信号
- created – 检查模型是否被创建。
- instance – 创建的模型实例
- kwargs -通配符关键字参数
另一种连接信号与功能的方式。
你需要将信号文件与app.py文件的准备功能连接起来,以便使用它们。
from django.apps import AppConfig
class UsersConfig(AppConfig):
name = 'users'
def ready(self):
import users.signals
这里的信号是活的。
如果我们创建一个用户
那么他的资料就会自动创建。
你也可以在管理视图中检查它
使用接收者方法的pre_save –
Pre_save方法是在调用save函数之前被激发的,而且只有在成功执行pre_save方法之后,模型才被保存。
# 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),那么只要任何保存方法被触发,它就会被触发。
post_save.connect(my_function_post_save, sender=MyModel)
pre_save.connect(my_function, sender= UserTextMessage)