0

我有一个模型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 组,有没有办法只运行它?因为如果在员工组中创建用户,我不想创建配置文件。

这是在 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})
4

1 回答 1

1

在视图中执行此操作(无信号):

@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=Falsearg传递给 的能力form.save(),但是由于这种形式显然没有其他用途,因此您无论如何都不会使用此功能。

于 2020-03-12T10:58:56.277 回答