![](/img/trans.png)
[英]Django formtools how to store form data between logout/login cycles
[英]Django: split form in pages using formtools and save to data base
我有一個包含3個部分的表單:
1)tamanios(尺寸),2)念珠菌(數量),3)archivos subidos(上傳的圖片)。
我需要在一頁中將1和2分開,在另一頁中將3分開,然后將表單數據保存到數據庫中。
據我調查,這可以使用formtools。 但是,使用formtools,我不得不將我的模型分為兩個模型: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:stacktrace
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
使用formtools可能不是一個好的選擇( 恕我直言:它對您的表單的控制較少 ),相反,您可以將Django Form和Modelform用於多步表單,並使用django會話在每一步中存儲數據。 最后,您可以彈出這些會話數據並將其存儲在模型中。 例如:
# 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")),
通過這種方法,您無需拆分模型 ,也無需在最后一步中存儲數據。 僅供參考:它未經測試的代碼,但我希望它能為您提供正確的實施方向。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.