仅当创建的用户位于 Django 中的特定组时,如何发出信号 运行?

How do I make a signal run only if the user created is on a specific group in Django?

我有一个模型 Client,它使用 @receiver 信号在创建用户时更新其字段,因此它创建了一个 Client 配置文件。

class Client(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    address = models.CharField(max_length=200, verbose_name="Morada")
    city = models.CharField(max_length=200, verbose_name="Cidade")
    postal = models.CharField(max_length=8, validators=[RegexValidator(r'^\d{4}(-\d{3})?$')], verbose_name="Código Postal")
    nif = models.CharField(max_length=9, verbose_name="NIF", validators=[RegexValidator(r'^\d{1,10}$')], unique=True, null=True)
    mobile = models.CharField(max_length=9, verbose_name="Telemóvel", validators=[RegexValidator(r'^\d{1,10}$')])

    def __str__(self):
        return "%s %s" % (self.user.first_name, self.user.last_name)

    class Meta:
        verbose_name_plural = "Clientes"

    @receiver(post_save, sender=User)
    def update_user_profile(sender, instance, created, **kwargs):
        if created:
            Clients.objects.create(user=instance)
            instance.clients.save()

如果创建的用户属于 Clients 组,有没有办法只 运行 这样做?因为如果在 Employees 组中创建用户,我不想创建配置文件。

这是在 Clients 组中创建 Client 的视图:

@login_required(login_url='./accounts/login/')
def signup(request):
    if request.method == 'POST':
        form = SignUpForm(request.POST)
        if form.is_valid():
            user = form.save()  # this creates the user with first_name, email and last_name as well!
            group = Group.objects.get(name='Clients')
            user.groups.add(group)
            user.refresh_from_db()  # load the profile instance created by the signal
            user.clients.address = form.cleaned_data.get('address')
            user.clients.city = form.cleaned_data.get('city')
            user.clients.postal = form.cleaned_data.get('postal')
            user.clients.nif = form.cleaned_data.get('nif')
            user.clients.mobile = form.cleaned_data.get('mobile')
            return redirect('clients')
    else:
        form = SignUpForm()
    return render(request, 'backend/new_client.html', {'form': form})

在视图中进行(无信号):

@login_required(login_url='./accounts/login/')
def signup(request):
    if request.method == 'POST':
        form = SignUpForm(request.POST)
        if form.is_valid():
            user = form.save()  
            group = Group.objects.get(name='Clients')
            user.groups.add(group)
            client = Client.objects.create(
                user=user,
                address=form.cleaned_data.get('address')
                city=form.cleaned_data.get('city')
                postal=form.cleaned_data.get('postal')
                nif=form.cleaned_data.get('nif')
                mobile=form.cleaned_data.get('mobile')
            )
            return redirect('clients')
    else:
        form = SignUpForm()
    return render(request, 'backend/new_client.html', {'form': form})

然后您可以选择将所有代码移动到表单本身的 user = form.save() 下(我假设它是自定义 ModelForm):

# forms.py

class SignUpForm(models.Form):

    # your existing code here

    def save(self):
       # NB if you're still using py2 you'll need
       # `user = super(SignUpForm, self).save()` instead
       user = super().save()
       group = Group.objects.get(name='Clients')
       user.groups.add(group)
       cleaned_data = self.cleaned_data
       client = Client.objects.create(
           user=user,
           address=cleaned_data.get('address')
           city=cleaned_data.get('city')
           postal=cleaned_data.get('postal')
           nif=cleaned_data.get('nif')
           mobile=cleaned_data.get('mobile')
       )
       return user

您的视图变为:

@login_required(login_url='./accounts/login/')
def signup(request):
    if request.method == 'POST':
        form = SignUpForm(request.POST)
        if form.is_valid():
            form.save()  
            return redirect('clients')
    else:
        form = SignUpForm()
    return render(request, 'backend/new_client.html', {'form': form})

这两个选项都是正确的并且功能等效,但恕我直言,第二个选项更易于维护 - 首先是因为表单比视图更容易测试(您不需要创建请求对象),还因为它将整个域逻辑封装在同一个地方(表单),而不是将其分散在表单和视图之间。唯一的缺点是您失去了将 commit=False arg 传递给 form.save() 的能力,但由于此表单显然没有其他目的,您无论如何都不会使用此功能。