2017-08-17 103 views
1

我有一个网站,用户应该能够注册为“工人”或“客户”,一个超级模型类型的网站。我创建了两个模型WorkerProfileCustomerProfile以及这两种表单,但是每次我提交客户或工作者表单时,新用户都会在http://127.0.0.1:8000/admin/的数据库中同时存入客户个人资料和工作人员个人资料,我如何防止这种情况发生发生了什么?问题扩展django用户模型

models.py:

from django.db import models 
from django.contrib.auth.models import User 
from django.db.models.signals import post_save 
from django.dispatch import receiver 

class WorkerProfile(models.Model): 
    user = models.OneToOneField(User, on_delete=models.CASCADE) 
    university = models.CharField(max_length=30, blank=True) 
    birth_date = models.DateField(null=True, blank=True) 

    role = models.CharField(max_length = 10, default = 'USER') 


    def __str__(self): 
     return self.user.username 

@receiver(post_save, sender=User) 
def create_worker_profile(sender, instance, created, **kwargs): 
    if created: 
     WorkerProfile.objects.create(user=instance) 

@receiver(post_save, sender=User) 
def save_worker_profile(sender, instance, **kwargs): 
    instance.workerprofile.save() 







class CustomerProfile(models.Model): 
    user = models.OneToOneField(User, on_delete=models.CASCADE) 
    university = models.CharField(max_length=30, blank=True) 
    birth_date = models.DateField(null=True, blank=True) 

    role = models.CharField(max_length = 10, default = 'CUSTOMER') 
    needLaundryDone = models.BooleanField(default = False) 

    def __str__(self): 
     return self.user.username 

@receiver(post_save, sender=User) 
def create_customer_profile(sender, instance, created, **kwargs): 
    if created: 
     CustomerProfile.objects.create(user=instance) 

@receiver(post_save, sender=User) 
def save_customer_profile(sender, instance, **kwargs): 
    instance.customerprofile.save() 

forms.py:

from django import forms 
from django.contrib.auth.forms import UserCreationForm 
from django.contrib.auth.models import User 

class WorkerSignUpForm(UserCreationForm): 
    #birth_date and university fields need to be declared seperately because they are not apart of User: 
    birth_date = forms.DateField(help_text='Required. Format: YYYY-MM-DD') 
    university = forms.CharField() 


    class Meta: 
     model = User 
     fields = ('username', 
        'email', 
        'first_name', 
        'last_name', 
        'birth_date', 
        'university', 
        'password1', 
        'password2',) 


class CustomerSignUpForm(UserCreationForm): 
    #birth_date and university fields need to be declared seperately because they are not apart of User: 
    birth_date = forms.DateField(help_text='Required. Format: YYYY-MM-DD') 
    university = forms.CharField() 


    class Meta: 
     model = User 
     fields = ('username', 
        'email', 
        'first_name', 
        'last_name', 
        'birth_date', 
        'university', 
        'password1', 
        'password2',) 

views.py:

def signup(request): 
    if request.method == 'POST': 
     form_worker = WorkerSignUpForm(request.POST) 
     form_customer = CustomerSignUpForm(request.POST) 
     if form_worker.is_valid(): 
      user = form_worker.save() 
      user.refresh_from_db() # load the profile instance created by the signal 
      user.workerprofile.birth_date = form_worker.cleaned_data.get('birth_date') 
      user.workerprofile.university = form_worker.cleaned_data.get('university') 
      user.save() # explicitly save custom fields not in User model 
      raw_password = form_worker.cleaned_data.get('password1') 
      user = authenticate(username=user.username, password=raw_password) 
      login(request, user) # login user after signup 
      return redirect('home') 
     elif form_customer.is_valid(): 
      user = form_customer.save() 
      user.refresh_from_db() # load the profile instance created by the signal 
      user.customerprofile.birth_date = form_customer.cleaned_data.get('birth_date') 
      user.customerprofile.university = form_customer.cleaned_data.get('university') 
      user.save() # explicitly save custom fields not in User model 
      raw_password = form_customer.cleaned_data.get('password1') 
      user = authenticate(username=user.username, password=raw_password) 
      login(request, user) # login user after signup 
      return redirect('home') 
    else: 
     form_worker = WorkerSignUpForm(request.POST) 
     form_customer = CustomerSignUpForm(request.POST) 
    return render(request, 'core/signup.html', {'form_worker': form_worker,'form_customer': form_customer }) 

signup.html:

{% extends 'core/base.html' %} 

{% block head %} 
    <title> Sign Up</title> 
{% endblock %} 
{% block body %} 


    <h3>Sign Up As Worker</h3> 
    <form method="post"> 
    {% csrf_token %} 
    {{ form_worker.as_p }} 
    <button type="submit">Sign up</button> 
    </form> 

    <h3>Sign Up As Customer</h3> 
    <form method="post"> 
    {% csrf_token %} 
    {{ form_customer.as_p }} 
    <button type="submit">Sign up</button> 
    </form> 
{% endblock %} 

回答

0

请勿在此处使用信号。它们都会在用户保存时触发,并且每个都创建相关的对象。

您应该删除这些信号,而是在视图中执行此操作。在每个表单的is_valid块中,您只能创建所需的特定对象。

if form_worker.is_valid(): 
    user = form_worker.save() 
    worker = WorkerProfile(user=user) 
    worker.birth_date = form_worker.cleaned_data.get('birth_date') 
    worker.university = form_worker.cleaned_data.get('university') 
    worker.save() 
    raw_password = form_worker.cleaned_data.get('password1') 
    ... 
elif form_customer.is_valid(): 
    user = form_customer.save() 
    customer = CustomerProfile(user=user) 
    ... 
+0

我同意丹尼尔,不要使用信号。 – GrandGTO

+0

@DanielRoseman我已经更新了你所说的视图,它太长了评论,所以我把它放在这里https://jsfiddle.net/jkm74fv4/。但是现在,即使我以客户身份注册,所有内容都将作为“工作人员”配置文件存储起来? –

+0

当您实例化表单以区分它们时,您需要使用前缀。虽然仔细观察,但我不明白为什么你有两种形式;为什么没有一个形式,与工人/客户复选框? –

0

这是正常的:

user = models.OneToOneField(User, on_delete=models.CASCADE) 

如果调用此两款车型,所以在保存过程中(),它会创建两个。

我建议你的是修改你的模型。你为什么不创建一个模型'Profil',并把一个布尔字段'is_customer'True/False?

+0

我打算增加一些功能,比如如果你是一个客户,你按下一个按钮,它表示你正在寻找某人提供服务(诸如'lookingForService'之类的客户的布尔字段),然后必须添加诸如付款信息(向工人发送付款的地方以及从客户那里获得付款的地方)。如果客户/工作人员每个人的'个人资料'中的某些字段总是等于null或空字符串(即工作人员不需要'lookForService'字段),那么这样可以吗?工人? –

+0

如果您将某个字段设置为Null或False,则这不是问题。我的意思是,基本上这在用户不填写他的个人资料字段的应用程序中并不罕见。 – GrandGTO