Django - 从表单更新多个模型 - 数据不保存
Django - Updating multiple models from a form - Data does not saved
我有一个自定义 User
模型来管理一些配置文件用户:is_student
、is_professor
和 is_executive
此外,在这个模型中,我有 get_student_profile()
、get_professor_profile()
和 get_executive_profile()
方法从我的不同视图中获取每个用户的用户配置文件数据。
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
username = models.CharField(max_length=40, unique=True)
slug = models.SlugField(max_length=100, blank=True)
is_student = models.BooleanField(default=False)
is_professor = models.BooleanField(default=False)
is_executive = models.BooleanField(default=False)
def get_student_profile(self):
student_profile = None
if hasattr(self, 'studentprofile'):
student_profile = self.studentprofile
return student_profile
def get_professor_profile(self):
professor_profile = None
if hasattr(self, 'professorprofile'):
professor_profile = self.professorprofile
return professor_profile
def get_executive_profile(self):
executive_profile = None
if hasattr(self, 'executiveprofile'):
executive_profile = self.executiveprofile
return executive_profile
此外,每个配置文件用户 is_student
、is_professor
和 is_executive
都有自己的模型,我在其中管理他们自己的数据:
class StudentProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(max_length=100,blank=True)
origin_education_school = models.CharField(max_length=128)
current_education_school = models.CharField(max_length=128)
extra_occupation = models.CharField(max_length=128)
class ProfessorProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(max_length=100,blank=True)
class ExecutiveProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(max_length=100,blank=True)
就是这样,在我的 User
模型中,我覆盖了 save()
方法来表示创建的用户的 username
字段的值相等到属于配置文件用户的 slug
,它将带走该用户(StudentProfile
、ProfessorProfile
、ExecutiveProfile
):
def save(self, *args, **kwargs):
user = super(User,self).save(*args,**kwargs)
# Creating an user with student, professor and executive profiles
if self.is_student and not StudentProfile.objects.filter(user=self).exists() \
and self.is_professor and not ProfessorProfile.objects.filter(user=self).exists() \
and self.is_executive and not ExecutiveProfile.objects.filter(user=self).exists():
student_profile = StudentProfile(user=self)
student_slug = self.username
student_profile.slug = student_slug
professor_profile = ProfessorProfile(user=self)
professor_slug = self.username
professor_profile.slug = professor_slug
executive_profile = ExecutiveProfile(user=self)
executive_slug = self.username
executive_profile.slug = executive_slug
student_profile.save()
professor_profile.save()
executive_profile.save()
# And so for all possibles profile combinations
对于这三个配置文件,我在其中生成了自己的字段的三个表单
class StudentProfileForm(forms.ModelForm):
class Meta:
model = StudentProfile
fields = ('origin_education_school', 'current_education_school',
'extra_occupation')
class ProfessorProfileForm(forms.ModelForm):
class Meta:
model = ProfessorProfile
fields = ('occupation',)
class ExecutiveProfileForm(forms.ModelForm):
class Meta:
model = ExecutiveProfile
fields = ('occupation', 'enterprise_name', 'culturals_arthistic','ecological')
我通过此 URL:
访问查看用户个人资料
url(r"^profile/(?P<slug>[\w\-]+)/$",
views.account_profiles__update_view,
name='profile'
),
在我基于函数的视图中 account_profiles__update_view()
我正在管理用户的请求,并根据以下内容创建表单实例(StudentProfileForm
、ProfessorProfileForm
、ExecutiveProfileForm
)用户个人资料(is_student
、is_professor
和 is_executive
)
@login_required
def account_profiles__update_view(request, slug):
user = request.user
# user = get_object_or_404(User, username = slug)
# empty list
_forms = []
if user.is_student:
profile = user.get_student_profile()
_forms.append(forms.StudentProfileForm)
if user.is_professor:
profile = user.get_professor_profile()
_forms.append(forms.ProfessorProfileForm)
if user.is_executive:
profile = user.get_executive_profile()
_forms.append(forms.ExecutiveProfileForm)
# user = get_object_or_404(settings.AUTH_USER_MODEL, username = slug)
if request.method == 'POST':
# Create a list with all formularies in which there is some POST
# operation. This mean if there is one, two or three profiles together
# or individual
formularios =[Form(data = request.POST,instance=profile) for Form in _forms]
if all([form.is_valid() for form in formularios]):
# Only save dato to database if all formularies that send
# the user in their request are correct or well formed in their
# data. Check that all formularies has been filled
for form in formularios:
profile = form.save(commit=False)
profile.user = user
profile.save()
return redirect('dashboard')
else:
formularios = [Form() for Form in _forms]
# Access to class Forms instanced (StudentProfileForm,
# ProfessorProfileForm, ExecutiveProfileForm), through the __class__
# pŕoperty which return the class onlying. An this class have another
# property named __name__ which return the name of string of a class,
# which is the same name with I did name the form classes
# (StudentProfileForm, ProfessorProfileForm, ExecutiveProfileForm)
# Next I call to their string method to grant that I always will return
# a string and I call to lower.
# The idea with this is place data into a python dictionarie and access
# to it
data = {form.__class__.__name__.__str__().lower(): form for form in formularios}
data['userprofile'] = profile
return render(request, 'accounts/profile_form.html', data,)
而我的profile_form.html
模板我有以下小逻辑:
<form method="POST">
{% csrf_token %}
{% if userprofile.user.is_student %}
<div align="center"><i>My Student Profile data</i></div>
{% bootstrap_form studentprofileform %}
{{ studentprofileform.non_field_errors }}
{% endif %}
{% if userprofile.user.is_professor %}
<div align="center"><i>My Professor Profile data</i></div>
{% bootstrap_form professorprofileform %}
{{ professorprofileform.non_field_errors }}
{% endif %}
{% if userprofile.user.is_executive %}
<div align="center"><i>My Executive Profile data</i></div>
{% bootstrap_form executiveprofileform %}
{{ executiveprofileform.non_field_errors }}
{% endif %}
<input type="submit" value="Save Changes" class="btn btn-default">
</form>
我想写下所有这些细节来评论发生在我身上的以下情况:
我在我的模板中渲染了三个表单
仅存储与所选的最新用户配置文件相关的数据,这意味着:
个人资料:is_student
、is_professor
和 is_executive
- 具有
is_student
个人资料的用户...保存数据
- 具有
is_professor
个人资料的用户...保存数据
具有 is_executive
个人资料的用户...保存数据
具有 is_student
和 is_professor
配置文件的用户:仅将数据保存到 is_professor
配置文件。不在 is_student
个配置文件表单字段中保存数据
具有 is_student
和 is_executive
配置文件的用户:仅将数据保存到 is_executive
配置文件。不在 is_student
个配置文件表单字段中保存数据
具有 is_professor
和 is_executive
配置文件的用户:仅将数据保存到 is_executive
配置文件。不在 is_professor
个配置文件表单字段中保存数据
具有 is_student
、is_professor
和 is_executive
配置文件的用户:仅将数据保存到 is_executive
配置文件。不在 is_professor
和 is_student
个人资料表单字段中保存数据
此时,只考虑最新选择的配置文件用户,并根据它保存他们的相关数据,而不是其他。
这是因为在我的 account_profiles__update_view()
基于函数的视图中我有这个 if
.. 句子逻辑:
if user.is_student:
profile = user.get_student_profile()
_forms.append(forms.StudentProfileForm)
if user.is_professor:
profile = user.get_professor_profile()
_forms.append(forms.ProfessorProfileForm)
if user.is_executive:
profile = user.get_executive_profile()
_forms.append(forms.ExecutiveProfileForm)
但是,我不知道我是否应该考虑在这里执行所有可能的配置文件用户组合并创建相同的表单实例组合。这是表演的事实吗?
我尝试将 account_profiles__update_view()
作为基于 class 的视图,here some code about it 但是配置文件和实例的特征形式发送到模板,让我选择基于函数的视图选项。
¿最好的选择是什么?
对于这个长问题,我深表歉意,我确实想提供所有细节,以便更好地理解我想要完成的代码和方法。
我非常感谢一些支持和指导。
我冒昧地为你清理了一些东西。让我们回顾一下每一件作品。
models.py
无需使用 hasattr()
探测模型。我们更愿意使用这样一个事实,即用户和配置文件之间的 OneToOneField
将在关系的两边放置一个引用。这意味着您可以简单地覆盖您的 save()
方法,如下所示:
注意:您可能更愿意使用 Signals 创建配置文件。
from django.conf import settings
from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.db import models
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
username = models.CharField(max_length=40, unique=True)
slug = models.SlugField(max_length=100, blank=True)
is_student = models.BooleanField(default=False, help_text="User is student")
is_professor = models.BooleanField(default=False, help_text="User is professor")
is_executive = models.BooleanField(default=False, help_text="User is executive")
USERNAME_FIELD = 'email'
def save(self, *args, **kwargs):
super(User, self).save(*args, **kwargs)
if self.is_student and getattr(self, 'studentprofile', None) is None:
StudentProfile.objects.create(
user=self,
slug=self.username
)
if self.is_professor and getattr(self, 'professorprofile', None) is None:
ProfessorProfile.objects.create(
user=self,
slug=self.username
)
if self.is_executive and getattr(self, 'executiveprofile', None) is None:
ExecutiveProfile.objects.create(
user=self,
slug=self.username
)
views.py
同样,让我们使用这样一个事实,即用户的 OneToOneField
将包含对配置文件的引用:
@login_required
def update_view(request):
user = request.user
# Populate Forms and Instances (if applicable)
form_profiles = []
if user.is_student:
form_profiles.append({'form': StudentProfileForm, 'instance': user.studentprofile})
if user.is_professor:
form_profiles.append({'form': ProfessorProfileForm, 'instance': user.professorprofile})
if user.is_executive:
form_profiles.append({'form': ExecutiveProfileForm, 'instance': user.executiveprofile})
if request.method == 'POST':
forms = [x['form'](data=request.POST, instance=x['instance']) for x in form_profiles]
if all([form.is_valid() for form in forms]):
for form in forms:
form.save()
return redirect('dashboard')
else:
forms = [x['form'](instance=x['instance']) for x in form_profiles]
return render(request, 'accounts/profile_form.html', {'forms': forms})
forms.py
您的表单可能如下所示:
class StudentProfileForm(forms.ModelForm):
title = "Student Form"
class Meta:
model = StudentProfile
fields = (
'origin_education_school',
'current_education_school',
'extra_occupation',
)
profile_form.html
<form method="post">
{% csrf_token %}
{% for form in forms %}
<h1>{{ form.title }}</h1>
{{ form }}
{% endfor %}
<button type="submit">Submit</button>
</form>
我仔细检查过,表格保存正确。
P.S。如果您想使用基于 Class 的视图,您可以遵循此 Gist 定义的 类:https://gist.github.com/michelts/1029336
我有一个自定义 User
模型来管理一些配置文件用户:is_student
、is_professor
和 is_executive
此外,在这个模型中,我有 get_student_profile()
、get_professor_profile()
和 get_executive_profile()
方法从我的不同视图中获取每个用户的用户配置文件数据。
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
username = models.CharField(max_length=40, unique=True)
slug = models.SlugField(max_length=100, blank=True)
is_student = models.BooleanField(default=False)
is_professor = models.BooleanField(default=False)
is_executive = models.BooleanField(default=False)
def get_student_profile(self):
student_profile = None
if hasattr(self, 'studentprofile'):
student_profile = self.studentprofile
return student_profile
def get_professor_profile(self):
professor_profile = None
if hasattr(self, 'professorprofile'):
professor_profile = self.professorprofile
return professor_profile
def get_executive_profile(self):
executive_profile = None
if hasattr(self, 'executiveprofile'):
executive_profile = self.executiveprofile
return executive_profile
此外,每个配置文件用户 is_student
、is_professor
和 is_executive
都有自己的模型,我在其中管理他们自己的数据:
class StudentProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(max_length=100,blank=True)
origin_education_school = models.CharField(max_length=128)
current_education_school = models.CharField(max_length=128)
extra_occupation = models.CharField(max_length=128)
class ProfessorProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(max_length=100,blank=True)
class ExecutiveProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(max_length=100,blank=True)
就是这样,在我的 User
模型中,我覆盖了 save()
方法来表示创建的用户的 username
字段的值相等到属于配置文件用户的 slug
,它将带走该用户(StudentProfile
、ProfessorProfile
、ExecutiveProfile
):
def save(self, *args, **kwargs):
user = super(User,self).save(*args,**kwargs)
# Creating an user with student, professor and executive profiles
if self.is_student and not StudentProfile.objects.filter(user=self).exists() \
and self.is_professor and not ProfessorProfile.objects.filter(user=self).exists() \
and self.is_executive and not ExecutiveProfile.objects.filter(user=self).exists():
student_profile = StudentProfile(user=self)
student_slug = self.username
student_profile.slug = student_slug
professor_profile = ProfessorProfile(user=self)
professor_slug = self.username
professor_profile.slug = professor_slug
executive_profile = ExecutiveProfile(user=self)
executive_slug = self.username
executive_profile.slug = executive_slug
student_profile.save()
professor_profile.save()
executive_profile.save()
# And so for all possibles profile combinations
对于这三个配置文件,我在其中生成了自己的字段的三个表单
class StudentProfileForm(forms.ModelForm):
class Meta:
model = StudentProfile
fields = ('origin_education_school', 'current_education_school',
'extra_occupation')
class ProfessorProfileForm(forms.ModelForm):
class Meta:
model = ProfessorProfile
fields = ('occupation',)
class ExecutiveProfileForm(forms.ModelForm):
class Meta:
model = ExecutiveProfile
fields = ('occupation', 'enterprise_name', 'culturals_arthistic','ecological')
我通过此 URL:
访问查看用户个人资料url(r"^profile/(?P<slug>[\w\-]+)/$",
views.account_profiles__update_view,
name='profile'
),
在我基于函数的视图中 account_profiles__update_view()
我正在管理用户的请求,并根据以下内容创建表单实例(StudentProfileForm
、ProfessorProfileForm
、ExecutiveProfileForm
)用户个人资料(is_student
、is_professor
和 is_executive
)
@login_required
def account_profiles__update_view(request, slug):
user = request.user
# user = get_object_or_404(User, username = slug)
# empty list
_forms = []
if user.is_student:
profile = user.get_student_profile()
_forms.append(forms.StudentProfileForm)
if user.is_professor:
profile = user.get_professor_profile()
_forms.append(forms.ProfessorProfileForm)
if user.is_executive:
profile = user.get_executive_profile()
_forms.append(forms.ExecutiveProfileForm)
# user = get_object_or_404(settings.AUTH_USER_MODEL, username = slug)
if request.method == 'POST':
# Create a list with all formularies in which there is some POST
# operation. This mean if there is one, two or three profiles together
# or individual
formularios =[Form(data = request.POST,instance=profile) for Form in _forms]
if all([form.is_valid() for form in formularios]):
# Only save dato to database if all formularies that send
# the user in their request are correct or well formed in their
# data. Check that all formularies has been filled
for form in formularios:
profile = form.save(commit=False)
profile.user = user
profile.save()
return redirect('dashboard')
else:
formularios = [Form() for Form in _forms]
# Access to class Forms instanced (StudentProfileForm,
# ProfessorProfileForm, ExecutiveProfileForm), through the __class__
# pŕoperty which return the class onlying. An this class have another
# property named __name__ which return the name of string of a class,
# which is the same name with I did name the form classes
# (StudentProfileForm, ProfessorProfileForm, ExecutiveProfileForm)
# Next I call to their string method to grant that I always will return
# a string and I call to lower.
# The idea with this is place data into a python dictionarie and access
# to it
data = {form.__class__.__name__.__str__().lower(): form for form in formularios}
data['userprofile'] = profile
return render(request, 'accounts/profile_form.html', data,)
而我的profile_form.html
模板我有以下小逻辑:
<form method="POST">
{% csrf_token %}
{% if userprofile.user.is_student %}
<div align="center"><i>My Student Profile data</i></div>
{% bootstrap_form studentprofileform %}
{{ studentprofileform.non_field_errors }}
{% endif %}
{% if userprofile.user.is_professor %}
<div align="center"><i>My Professor Profile data</i></div>
{% bootstrap_form professorprofileform %}
{{ professorprofileform.non_field_errors }}
{% endif %}
{% if userprofile.user.is_executive %}
<div align="center"><i>My Executive Profile data</i></div>
{% bootstrap_form executiveprofileform %}
{{ executiveprofileform.non_field_errors }}
{% endif %}
<input type="submit" value="Save Changes" class="btn btn-default">
</form>
我想写下所有这些细节来评论发生在我身上的以下情况:
我在我的模板中渲染了三个表单
仅存储与所选的最新用户配置文件相关的数据,这意味着:
个人资料:is_student
、is_professor
和 is_executive
- 具有
is_student
个人资料的用户...保存数据 - 具有
is_professor
个人资料的用户...保存数据 具有
is_executive
个人资料的用户...保存数据具有
is_student
和is_professor
配置文件的用户:仅将数据保存到is_professor
配置文件。不在is_student
个配置文件表单字段中保存数据具有
is_student
和is_executive
配置文件的用户:仅将数据保存到is_executive
配置文件。不在is_student
个配置文件表单字段中保存数据具有
is_professor
和is_executive
配置文件的用户:仅将数据保存到is_executive
配置文件。不在is_professor
个配置文件表单字段中保存数据具有
is_student
、is_professor
和is_executive
配置文件的用户:仅将数据保存到is_executive
配置文件。不在is_professor
和is_student
个人资料表单字段中保存数据
此时,只考虑最新选择的配置文件用户,并根据它保存他们的相关数据,而不是其他。
这是因为在我的 account_profiles__update_view()
基于函数的视图中我有这个 if
.. 句子逻辑:
if user.is_student:
profile = user.get_student_profile()
_forms.append(forms.StudentProfileForm)
if user.is_professor:
profile = user.get_professor_profile()
_forms.append(forms.ProfessorProfileForm)
if user.is_executive:
profile = user.get_executive_profile()
_forms.append(forms.ExecutiveProfileForm)
但是,我不知道我是否应该考虑在这里执行所有可能的配置文件用户组合并创建相同的表单实例组合。这是表演的事实吗?
我尝试将 account_profiles__update_view()
作为基于 class 的视图,here some code about it 但是配置文件和实例的特征形式发送到模板,让我选择基于函数的视图选项。
¿最好的选择是什么?
对于这个长问题,我深表歉意,我确实想提供所有细节,以便更好地理解我想要完成的代码和方法。 我非常感谢一些支持和指导。
我冒昧地为你清理了一些东西。让我们回顾一下每一件作品。
models.py
无需使用 hasattr()
探测模型。我们更愿意使用这样一个事实,即用户和配置文件之间的 OneToOneField
将在关系的两边放置一个引用。这意味着您可以简单地覆盖您的 save()
方法,如下所示:
注意:您可能更愿意使用 Signals 创建配置文件。
from django.conf import settings
from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.db import models
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
username = models.CharField(max_length=40, unique=True)
slug = models.SlugField(max_length=100, blank=True)
is_student = models.BooleanField(default=False, help_text="User is student")
is_professor = models.BooleanField(default=False, help_text="User is professor")
is_executive = models.BooleanField(default=False, help_text="User is executive")
USERNAME_FIELD = 'email'
def save(self, *args, **kwargs):
super(User, self).save(*args, **kwargs)
if self.is_student and getattr(self, 'studentprofile', None) is None:
StudentProfile.objects.create(
user=self,
slug=self.username
)
if self.is_professor and getattr(self, 'professorprofile', None) is None:
ProfessorProfile.objects.create(
user=self,
slug=self.username
)
if self.is_executive and getattr(self, 'executiveprofile', None) is None:
ExecutiveProfile.objects.create(
user=self,
slug=self.username
)
views.py
同样,让我们使用这样一个事实,即用户的 OneToOneField
将包含对配置文件的引用:
@login_required
def update_view(request):
user = request.user
# Populate Forms and Instances (if applicable)
form_profiles = []
if user.is_student:
form_profiles.append({'form': StudentProfileForm, 'instance': user.studentprofile})
if user.is_professor:
form_profiles.append({'form': ProfessorProfileForm, 'instance': user.professorprofile})
if user.is_executive:
form_profiles.append({'form': ExecutiveProfileForm, 'instance': user.executiveprofile})
if request.method == 'POST':
forms = [x['form'](data=request.POST, instance=x['instance']) for x in form_profiles]
if all([form.is_valid() for form in forms]):
for form in forms:
form.save()
return redirect('dashboard')
else:
forms = [x['form'](instance=x['instance']) for x in form_profiles]
return render(request, 'accounts/profile_form.html', {'forms': forms})
forms.py
您的表单可能如下所示:
class StudentProfileForm(forms.ModelForm):
title = "Student Form"
class Meta:
model = StudentProfile
fields = (
'origin_education_school',
'current_education_school',
'extra_occupation',
)
profile_form.html
<form method="post">
{% csrf_token %}
{% for form in forms %}
<h1>{{ form.title }}</h1>
{{ form }}
{% endfor %}
<button type="submit">Submit</button>
</form>
我仔细检查过,表格保存正确。
P.S。如果您想使用基于 Class 的视图,您可以遵循此 Gist 定义的 类:https://gist.github.com/michelts/1029336