问题描述
我正在用 django 创建一个艺术市场。我为配置文件设置了注册和自动创建信号。将在此应用程序上注册的用户分为三种类型:艺术家、赞助人和经纪人(我称之为 user_status。)我希望用户在注册表单上选择这三个字段之一。我已经到了这样的地步,reg 表单有选择字段和选项,用户可以选择一个,表单保存以创建用户和配置文件,但是当我进入管理时,配置文件没有选择的“user_status” .
我知道非常不鼓励在注册时捆绑配置文件模型字段,但我希望只有这一字段是可选的,因为它会对网站如何查找用户产生重大影响。我读过 (here) 说要在注册时正确填写个人资料字段会涉及很多烦人的自定义。这是真的吗?
我认为如果有解决方案,它会在 Signals.py 上,但我不确定。
在signals.py中输入:
user_status='Patron',
我可以用 instance.get('user_status')
之类的东西替换“赞助人”吗?我知道这里也有一些叫做“默认值”的东西,但我不熟悉。
user/signals.py
from django.db.models.signals import post_save
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:
# This functions but cannot get it to grab the form chosen field from the user.
# just default creates status as patron for now :(
Profile.objects.update_or_create(
user=instance,user_status='Patron',)
@receiver(post_save,sender=User)
def save_profile(sender,**kwargs):
instance.profile.save()
user/forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from users.models import Profile
STATUS_CHOICES = (
('Artist','Artist'),('Patron','Patron'),('Broker','Broker')
)
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
user_status = forms.ChoiceField(choices=STATUS_CHOICES)
class Meta:
model = User
fields = ['username','email','user_status','password1','password2']
users/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
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'Hello {username}! Your account has been created. You are now ready to log in.')
return redirect('login')
else:
form = UserRegisterForm()
return render(request,'users/register.html',{'form': form})
@login_required
def profile(request):
return render(request,'users/profile.html')
user/models.py
class Profile(models.Model):
STATUS_CHOICES = (
('Artist','Broker')
)
user = models.OneToOneField(User,on_delete=models.CASCADE,primary_key=True)
user_slug = models.SlugField(blank=True)
image = models.ImageField(default='default.jpg',upload_to='profile_pics')
user_status = models.CharField(max_length=100,choices=STATUS_CHOICES)
def __str__(self):
return f'{self.user.username} Profile'
修改反映第一条建议:
Views.py
def register(request):
if request.method == 'POST':
# create profile object but don't save it to db
profile = ProfileSetupForm.save(request.POST)
profile = profile_setup_form.save(commit=False)
user_form = UserRegisterForm(request.POST)
if user_form.is_valid():
# create user object
user = user_form.save(commit=False)
# set profile attribute of user object
user.profile = profile
# save user - calls post_save
user.save()
username = user.username
messages.success(request,f'Hello {username}! Your account has been created. You are now ready to log in.')
return redirect('login')
else:
user_form = UserRegisterForm()
profile_setup_form = ProfileSetupForm()
return render(
request,{
'user_form': user_form,'profile_setup_form': profile_setup_form
}
)
signals.py
@receiver(post_save,**kwargs):
if created:
Profile.objects.update_or_create(
user=instance,user_status=instance.profile.user_status,)
register.html
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Join Today</legend>
{{ user_form|crispy }}
{{ profile_setup_form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Sign Up</button>
</div>
</form>
<div class="border-top pt-3">
<small class="muted">
Already have an account? <a class="ml-2" href="{% url 'login' %}">Sign In</a>
</small>
</div>
</div>
{% endblock content %}
错误代码
Traceback (most recent call last):
File "/Users/Tom/Desktop/art_project/art_env/lib/python3.8/site-packages/django/core/handlers/exception.py",line 47,in inner
response = get_response(request)
File "/Users/Tom/Desktop/art_project/art_env/lib/python3.8/site-packages/django/core/handlers/base.py",line 181,in _get_response
response = wrapped_callback(request,*callback_args,**callback_kwargs)
File "/Users/Tom/Desktop/art_project/users/views.py",line 12,in register
profile = ProfileSetupForm.save(user_status,request.POST)
File "/Users/Tom/Desktop/art_project/art_env/lib/python3.8/site-packages/django/forms/models.py",line 451,in save
if self.errors:
Exception Type: AttributeError at /register/
Exception Value: 'DeferredAttribute' object has no attribute 'errors'
这里是错误代码,如果我把“user_status”去掉,所以这是你建议的代码:
Traceback (most recent call last):
File "/Users/Tom/Desktop/art_project/art_env/lib/python3.8/site-packages/django/core/handlers/exception.py",in register
profile = ProfileSetupForm.save(request.POST)
File "/Users/Tom/Desktop/art_project/art_env/lib/python3.8/site-packages/django/forms/models.py",in save
if self.errors:
Exception Type: AttributeError at /register/
Exception Value: 'QueryDict' object has no attribute 'errors'
调整后的 forms.py 文件
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from users.models import Profile
STATUS_CHOICES = (
('Artist','Broker')
)
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
# user_status = forms.ChoiceField(choices=STATUS_CHOICES)
class Meta:
model = User
fields = ['username','password2']
class ProfileSetupForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['user_status']
根据评论进行调整的当前 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,ProfileSetupForm
def register(request):
if request.method == 'POST':
# create profile object but don't save it to db
profile_setup_form = ProfileSetupForm.save(request.POST)
profile = profile_setup_form.save(commit=False)
user_form = UserRegisterForm(request.POST)
if user_form.is_valid():
# create user object
user = user_form.save(commit=False)
# set profile attribute of user object
user.profile = profile
# save user - calls post_save
user.save()
username = user.username
messages.success(request,'profile_setup_form': profile_setup_form
}
)
解决方法
我会在您的注册页面上包含另一个表格,尽管这只是作为解决方案的建议。
forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from user_status.models import Profile
STATUS_CHOICES = (
('Artist','Artist'),('Patron','Patron'),('Broker','Broker')
)
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
# user_status = forms.ChoiceField(choices=STATUS_CHOICES)
class Meta:
model = User
fields = ['username','email','password1','password2']
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['user_status']
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,ProfileForm
def register(request):
if request.method == 'POST':
# create profile object but don't save it to db
profile_form = ProfileForm(request.POST)
profile = profile_form.save(commit=False)
user_form = UserRegisterForm(request.POST)
if user_form.is_valid():
# create user object
user = user_form.save(commit=False)
# set profile attribute of user object
user.profile = profile
# save user - calls post_save
user.save()
username = user.username
messages.success(request,f'Hello {username}! Your account has been created. You are now ready to log in.')
return redirect('login')
else:
user_form = UserRegisterForm()
profile_form = ProfileForm()
return render(
request,'users/register.html',{
'user_form': user_form,'profile_form': profile_form
}
)
@login_required
def profile(request):
return render(request,'users/profile.html')
signals.py
from django.db.models.signals import post_save
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:
# can now set user_status attribute
Profile.objects.update_or_create(
user=instance,user_status=instance.profile.user_status,)
@receiver(post_save,sender=User)
def save_profile(sender,**kwargs):
instance.profile.save()
我不知道您的 register.html
页面是什么样的,但您可以通过以下方式显示这些表单作为示例。
register.html
<h1>Registration Page</h1>
<form action="/register" method="POST">
{% csrf_token %}
{{ user_form.as_p }}
{{ profile_form.as_p }}
<input type="submit" value="Register"></input>
</form>
如果您想让用户在注册时也包含这些内容,您可以在 profile_form 中包含更多字段,例如用户的图片。