簡體   English   中英

Django:使用formtools在頁面中拆分表單並將其保存到數據庫

[英]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 FormModelform用於多步表單,並使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM