我有一个包含3个部分的表单:
1)tamanios(大小),2)念珠菌(数量),3)archivos subidos(上传的图片)。
我需要在一页中分开1和2,在另一页中分开3,然后将表单数据保存到数据库中。
据我调查,可以使用formtools实现。但是,使用formtools,我不得不将我的模型分为2个模型:a)TamaniosCantidades,b)ArchivosSubidos,以便可以在不同的“步骤”中进行渲染。
尽管如此,我宁愿只使用1个模型。但是,如果该解决方案包含一些ForeingKey来连接两个拆分的模型,则可以。
将表单另存为数据库中的模型对象需要做什么?
我想不出如何在向导类中编写“完成”方法。
原始模型:
class TamaniosCantidades(models.Model):
TAMANIOS = (('2x2', '2" x 2"',), ('3x3', '3" x 3"',),
('4x4', '4" x 4"',), ('5x5', '5" x 5"',))
CANTIDADES = (('50', '50',), ('100', '100',),
('150', '150',))
tamanios = models.CharField(max_length=10, choices=TAMANIOS)
cantidades = models.CharField(max_length=10, choices=CANTIDADES)
imagenes = models.FileField(upload_to='imagenes/')
uploaded_at = models.DateTimeField(auto_now_add=True)
修改后的模型(分解结果):
class TamaniosCantidades(models.Model):
TAMANIOS = (('2x2', '2" x 2"',), ('3x3', '3" x 3"',),
('4x4', '4" x 4"',), ('5x5', '5" x 5"',))
CANTIDADES = (('50', '50',), ('100', '100',),
('150', '150',))
tamanios = models.CharField(max_length=10, choices=TAMANIOS)
cantidades = models.CharField(max_length=10, choices=CANTIDADES)
# imagenes = models.FileField(upload_to='imagenes/')
# uploaded_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.tamanios
class ArchivosSubidos(models.Model):
# imagenes = models.FileField(upload_to='imagenes/') #commented because I was having problems uploading files with formtools
imagenes = models.CharField(max_length=100) #using charfield to test splitting
uploaded_at = models.DateTimeField(auto_now_add=True)
views.py
class ContactWizard(SessionWizardView):
template_name = "main_app/contact_form.html"
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'imagenes'))
def done(self, form_list, **kwargs):
form_data = process_form_data(form_list)
return HttpResponseRedirect('/')
# return HttpResponseRedirect('/done.html')
# return render('main_app/done.html', {'form_data':form_data})
def process_form_data(form_list):
form_data = [form.cleaned_data for form in form_list]
return form_data
urls.py
app_name = 'main_app'
urlpatterns = [
path('', views.index),
path('productos/', views.productos),
# path('productos/die-cut-stickers', views.die_cut, name='die-cut-stickers'),
path('contact/', ContactWizard.as_view([TamaniosCantidadesForm, ArchivosSubidosForm]))
]
更新1:堆栈跟踪
2x2 #printed from print(kwargs.get('tamanios', None)) in def save
Internal Server Error: /step-three/
Traceback (most recent call last):
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 296, in execute
return Database.Cursor.execute(self, query, params)
sqlite3.IntegrityError: NOT NULL constraint failed: main_app_tamanioscantidades.tamanios
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/core/handlers/base.py", line 124, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/views/generic/base.py", line 88, in dispatch
return handler(request, *args, **kwargs)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/views/generic/edit.py", line 172, in post
return super().post(request, *args, **kwargs)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/views/generic/edit.py", line 142, in post
return self.form_valid(form)
File "/home/ogonzales/Escritorio/web_proyects/gallito/main_app/views.py", line 195, in form_valid
return super(StepThreeView, self).form_valid(form)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/views/generic/edit.py", line 125, in form_valid
self.object = form.save()
File "/home/ogonzales/Escritorio/web_proyects/gallito/main_app/forms.py", line 55, in save
instance.save()
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/models/base.py", line 718, in save
force_update=force_update, update_fields=update_fields)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/models/base.py", line 748, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/models/base.py", line 812, in _save_table
forced_update)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/models/base.py", line 861, in _do_update
return filtered._update(values) > 0
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/models/query.py", line 712, in _update
return query.get_compiler(self.db).execute_sql(CURSOR)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1383, in execute_sql
cursor = super().execute_sql(result_type)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1065, in execute_sql
cursor.execute(sql, params)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/backends/utils.py", line 100, in execute
return super().execute(sql, params)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/backends/utils.py", line 68, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/backends/utils.py", line 77, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/utils.py", line 89, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
return self.cursor.execute(sql, params)
File "/home/ogonzales/Escritorio/projects_envs/gallito_env/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 296, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: NOT NULL constraint failed: main_app_tamanioscantidades.tamanios
[17/Nov/2018 03:53:44] "POST /step-three/ HTTP/1.1" 500 178292
答案 0 :(得分:2)
使用formtools可能不是一个不错的选择(恕我直言:IMHO:对您的表单的控制较少),相反,您可以将Django Form和Modelform用于多步表单,并在每个步骤中使用django session存储数据。最后,您可以弹出这些会话数据并将其存储在模型中。例如:
# Lets declare our choices in a global scope rather than inside models
TAMANIOS = (('2x2', '2" x 2"',), ('3x3', '3" x 3"',),
('4x4', '4" x 4"',), ('5x5', '5" x 5"',))
CANTIDADES = (('50', '50',), ('100', '100',),
('150', '150',))
# Declare Forms
class StepOneForm(forms.Form):
tamanios = forms.ChoiceField(choices=TAMANIOS)
class StepTwoForm(forms.Form):
cantidades = forms.ChoiceField(choices=CANTIDADES)
# Third step is attached to the model directly, we will do some tweaks inside the save method of this form
class StepThreeForm(forms.ModelForm):
class Meta:
model = TamaniosCantidades
fields = ('imagenes',)
# Views
# First Two steps are basic FormViews, because it will be used just to store data in session
class StepOneView(FormView):
form_class = StepOneForm
template_name = 'step_one.html'
success_url = '/step-two/'
def get_initials(self):
# pre-populate form if someone goes back and forth between forms
initial = super(StepOneView, self).get_initial()
initial['tamanios'] = self.request.session.get('tamanios', None)
return initial
def form_valid(self, form):
# In form_valid method we can access the form data in dict format
# and will store it in django session
self.request.session['tamanios'] = form.cleaned_data.get('tamanios')
return HttpResponseRedirect(self.get_success_url())
class StepTwoView(FormView):
form_class = StepTwoForm
template_name = 'step_two.html'
success_url = '/step-three/'
def get_initials(self):
# pre-populate form if someone goes back and forth between forms
initial = super(StepOneView, self).get_initial()
initial['cantidades'] = self.request.session.get('cantidades', None)
return initial
def form_valid(self, form):
# same as StepOneView
self.request.session['cantidades'] = form.cleaned_data.get('cantidades')
return HttpResponseRedirect(self.get_success_url())
# here we are going to use CreateView to save the Third step ModelForm
class StepThreeView(CreateView):
form_class = StepThreeForm
template_name = 'step_three.html'
success_url = '/thank-you/'
def form_valid(self, form):
form.instance.tamanios = self.request.session.get('tamanios') # get tamanios from session
form.instance.cantidades = self.request.session.get('cantidades') # get cantidades from session
del self.request.session['cantidades'] # delete cantidades value from session
del self.request.session['tamanios'] # delete tamanios value from session
self.request.session.modified = True
return super(StepThreeView, self).form_valid(form)
# template
# step_one.html, step_two.html, step_three.html can be all the same as following code
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit">
</form>
# urls
path('step-one/', StepOneView.as_view()),
path('step-two/', StepTwoView.as_view()),
path('step-three/', StepThreeView.as_view()),
path('thank-you/', TemplateView.as_view(template_name="thank-you.html")),
采用这种方法,您无需分割模型,并将数据存储在最后一步中。 FYI:其未经测试的代码,但我希望它能为您提供正确的实施方向。