如何从 Django SessionWizardView 获取主键和数据
How to get Primary Key and data from Django SessionWizardView
我有一个 SessionWizardView
生成 3 种形式,具体取决于之前的选择。选择表格后,用户填写表格并将其提交给每个案例的特定ListView
,使用POST。问题是获取这些值,主要是主键。
SessionWizardView
,我按照文档 (https://django-formtools.readthedocs.io/en/stable/wizard.html#wizard-template-for-each-form) 进行操作,它按我预期的方式工作。 3 个表格的最后一个字段已预先填写,具体取决于第一个字段。
在 ListView
中,我尝试使用 request.session.pop()
从 SessionWizardView
中获取字段。在这里,我有了第一个疑问:我使用了 forms.py
中的变量名(例如:request.session.pop('formField1', {})
)和 POST 中的字段 ID(request.session.pop('opcao1-formField1', {})
)。在这两种情况下,浏览器 return 'int' object has no attribute 'pk'
错误。
我已经测试了向导可以显示给我的 3 个表单,它们都显示相同的错误,所以我将把第一个的代码放上去,所以文本要简短。
urls.py:
logger = logging.getLogger(__name__)
urlpatterns = [
# path('', views.IndexView.as_view(), name="index"),
path('', views.IndexView.as_view(views.FORMS), name="index"),
path('detail/', views.DetailView.as_view(), name="detail"),
views.py:
class IndexView(SessionWizardView):
condition_dict = {"opcao1" : graficoEscolhido1,
"opcao2" : graficoEscolhido2,
"opcao3" : graficoEscolhido3,
}
template_name = 'solid/index.html'
success_url = reverse_lazy('detail')
def done(self, form_list, **kwargs):
self.request.session['opcao1-dateDataInicial'] = str(form_list.cleaned_data['opcao1-dateDataInicial'])
self.request.session['opcao1-dateDataFinal'] = str(form_list.cleaned_data['opcao1-dateDataFinal'])
self.request.session['opcao1-codigoDuto'] = form_list.cleaned_data['opcao1-codigoDuto']
self.request.session['opcao1-codigoExtremidade'] = float(form_list.cleaned_data['opcao1-codigoExtremidade'])
# I've already commented the previous line, trade wizard for
# request. Put form_list.get_all_cleaned_data(), too as test.
return render(self.request, "solid/detail.html", {
'form_data': [form.cleaned_data for form in form_list],
})
class DetailView(generic.ListView):
def get_context_data(self, **kwargs):
cursor = connection.cursor()
# Trying to get from previous session. I've replaced request for
# wizard too, in previous attempt.
inicio = self.request.session.pop('opcao1-dateDataInicial', {})
final = self.request.session.pop('opcao1-dateDataFinal', {})
cod_id = self.request.session.pop('opcao1-codigoID', {})
extra = self.request.session.pop('opcao1-valorExtra', {})
Temp1 = TEMP.objects.values_list('TE_CD_ID_S_Temp', flat = True).filter(
TE_CD_ID_Cod = cod_id,
TE_VL_Ponto = extra)
Dens1 = DENS.objects.values_list('DE_CD_ID_S_Den', flat = True).filter(
DE_CD_ID_Cod = cod_id,
DE_VL_Ponto = extra)
Vaz1 = VAZ.objects.values_list('VA_CD_ID_S_Vaz', flat = True).filter(
VA_CD_ID_Cod = cod_id,
VA_VL_Ponto = extra)
Pres1 = PRES.objects.values_list('PR_CD_ID_S_Pres', flat = True).filter(
PR_CD_ID_Cod = cod_id,
PR_VL_Ponto = extra)
cursor.execute('giant query',(str(sensorPres[0]), inicio, final,
str(sensorTemp[0]), inicio, final,
str(sensorDens[0]), inicio, final,
str(sensorVaz[0]), inicio, final))
lista = cursor.fetchall()
listaArray = np.asarray(lista)
tempo = listaArray[:,0]
valpres = listaArray[:,1]
valpres = np.array(valpres)
valpres = valpres.astype(float)
valtemp = listaArray[:,2]
valtemp = np.array(valtemp)
valtemp = valtemp.astype(float)
valden = listaArray[:,3]
valden = np.array(valden)
valden = valden.astype(float)
valvaz = listaArray[:,4]
valvaz = np.array(valvaz)
valvaz = valvaz.astype(float)
kwargs['tempo'] = tempo
kwargs['valpres'] = valpres
kwargs['valtemp'] = valtemp
kwargs['valden'] = valden
kwargs['valvaz'] = valvaz
kwargs['dateInicial'] = inicio
kwargs['dateFinal'] = final
return super().get_context_data(**kwargs)
forms.py:
class get_Codigo_DutoGrafico1(forms.Form):
# codigoID is a PK in the model.
codigoID = forms.ModelMultipleChoiceField(label = "Código ID",
queryset = PRINCIPAL.objects.values_list('CD_ID', flat = True),
widget = forms.SelectMultiple(attrs = {'id' : 'id_codigo_id'}))
dateDataInicial = forms.DateTimeField(label = 'Data Inicial',
input_formats = ['%d/%m/%Y %H:%M:%S'],
widget=XDSoftDateTimePickerInput())
dateDataFinal = forms.DateTimeField(label = 'Data Final',
input_formats = ['%d/%m/%Y %H:%M:%S'],
widget=XDSoftDateTimePickerInput())
valorExtra = forms.ModelMultipleChoiceField(label = 'Valor Extra',
queryset = DENS.objects.values_list('DE_VL_Ponto', flat = True).none(),
widget = forms.SelectMultiple(attrs = {'id' : 'id_codigoDropDown'}))
index.html:
<div class = "container-fluid" id = "wrapper">
<div class = "row">
{% load i18n %}
{% block head %}
{{ wizard.form.media }}
{% endblock %}
{% block content %}
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action = "" method = "post" id = "formGrafico" data-data-url="{% url 'ajax_load_duto' %}" data-data2-url="{% url 'ajax_load_data2' %}" novalidate>
{% csrf_token %}
<table>
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form }}
{% endfor %}
{% else %}
{{ wizard.form }}
{% endif %}
</table>
{% if wizard.steps.prev %}
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.first }}">{% trans "first step" %}</button>
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">{% trans "prev step" %}</button>
{% endif %}
<input type="submit" value="{% trans "submit" %}"/>
</form>
{% endblock %}
我希望获得 detail.html 中的值并以不同方式显示数据。但是,我收到以下错误:'int' 对象没有属性 'pk'。 POST return 如下:
POST
Variable Value
csrfmiddlewaretoken
'TArU7O0laFVnRiWp9rEpUOE4bUoPNYulB2zNkFbwnLFxbVBwr4Qmp7ZQ5FfhJ3r7'
index_view-current_step
'opcao1'
opcao1-codigoDuto
'177'
opcao1-dateDataInicial
'03/05/2018 10:19:00'
opcao1-dateDataFinal
'01/07/2018 10:20:00'
opcao1-codigoExtremidade
'2,127000000000000'
整个错误回溯:
Environment:
Request Method: POST
Request URL: http://127.0.0.1:8000/
Django Version: 2.1.7
Python Version: 3.6.7
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'compressor',
'django_extensions',
'solid',
'sekizai',
'formtools']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback:
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
34. response = get_response(request)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
126. response = self.process_exception_by_middleware(e, request)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
124. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/views/generic/base.py" in view
68. return self.dispatch(request, *args, **kwargs)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/formtools/wizard/views.py" in dispatch
248. response = super(WizardView, self).dispatch(request, *args, **kwargs)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/views/generic/base.py" in dispatch
88. return handler(request, *args, **kwargs)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/formtools/wizard/views.py" in post
301. if form.is_valid():
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/forms/forms.py" in is_valid
185. return self.is_bound and not self.errors
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/forms/forms.py" in errors
180. self.full_clean()
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/forms/forms.py" in full_clean
381. self._clean_fields()
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/forms/forms.py" in _clean_fields
399. value = field.clean(value)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/forms/models.py" in clean
1293. qs = self._check_values(value)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/forms/models.py" in _check_values
1326. pks = {str(getattr(o, key)) for o in qs}
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/forms/models.py" in <setcomp>
1326. pks = {str(getattr(o, key)) for o in qs}
Exception Type: AttributeError at /
Exception Value: 'int' object has no attribute 'pk'
所以数据是从 SessionWizardView 传递过来的,但是中间有些东西是错误的。为了测试 'int' 问题,我将 str() 设置为 "cod_id" 并且仍然收到 'int' 错误消息。我在 Stack 中搜索了一些与之相关的内容,但我一无所获。
错误是因为你的 ModelMultipleChoiceField
有一个 queryset
属性设置为一个整数列表,这是错误的,你的查询集应该是一个对象列表:PRINCIPAL.objects.all()
。 ModelMultipleChoiceField
接收一个整数作为输入(发布的数据),但想要一个对象 (PRINCIPAL
) 作为 value
。
如果您想自定义值向用户显示的方式,您应该继承 ModelMultipleChoiceField
并覆盖 label_from_instance
方法:
class IDModelMultipleChoiceField(ModelMultipleChoiceField):
def label_from_instance(self, instance):
return instance.pk
并在您的表单中
cogidoID = IDModelMultipleChoiceField(queryset=..., label=...)
我有一个 SessionWizardView
生成 3 种形式,具体取决于之前的选择。选择表格后,用户填写表格并将其提交给每个案例的特定ListView
,使用POST。问题是获取这些值,主要是主键。
SessionWizardView
,我按照文档 (https://django-formtools.readthedocs.io/en/stable/wizard.html#wizard-template-for-each-form) 进行操作,它按我预期的方式工作。 3 个表格的最后一个字段已预先填写,具体取决于第一个字段。
在 ListView
中,我尝试使用 request.session.pop()
从 SessionWizardView
中获取字段。在这里,我有了第一个疑问:我使用了 forms.py
中的变量名(例如:request.session.pop('formField1', {})
)和 POST 中的字段 ID(request.session.pop('opcao1-formField1', {})
)。在这两种情况下,浏览器 return 'int' object has no attribute 'pk'
错误。
我已经测试了向导可以显示给我的 3 个表单,它们都显示相同的错误,所以我将把第一个的代码放上去,所以文本要简短。
urls.py:
logger = logging.getLogger(__name__)
urlpatterns = [
# path('', views.IndexView.as_view(), name="index"),
path('', views.IndexView.as_view(views.FORMS), name="index"),
path('detail/', views.DetailView.as_view(), name="detail"),
views.py:
class IndexView(SessionWizardView):
condition_dict = {"opcao1" : graficoEscolhido1,
"opcao2" : graficoEscolhido2,
"opcao3" : graficoEscolhido3,
}
template_name = 'solid/index.html'
success_url = reverse_lazy('detail')
def done(self, form_list, **kwargs):
self.request.session['opcao1-dateDataInicial'] = str(form_list.cleaned_data['opcao1-dateDataInicial'])
self.request.session['opcao1-dateDataFinal'] = str(form_list.cleaned_data['opcao1-dateDataFinal'])
self.request.session['opcao1-codigoDuto'] = form_list.cleaned_data['opcao1-codigoDuto']
self.request.session['opcao1-codigoExtremidade'] = float(form_list.cleaned_data['opcao1-codigoExtremidade'])
# I've already commented the previous line, trade wizard for
# request. Put form_list.get_all_cleaned_data(), too as test.
return render(self.request, "solid/detail.html", {
'form_data': [form.cleaned_data for form in form_list],
})
class DetailView(generic.ListView):
def get_context_data(self, **kwargs):
cursor = connection.cursor()
# Trying to get from previous session. I've replaced request for
# wizard too, in previous attempt.
inicio = self.request.session.pop('opcao1-dateDataInicial', {})
final = self.request.session.pop('opcao1-dateDataFinal', {})
cod_id = self.request.session.pop('opcao1-codigoID', {})
extra = self.request.session.pop('opcao1-valorExtra', {})
Temp1 = TEMP.objects.values_list('TE_CD_ID_S_Temp', flat = True).filter(
TE_CD_ID_Cod = cod_id,
TE_VL_Ponto = extra)
Dens1 = DENS.objects.values_list('DE_CD_ID_S_Den', flat = True).filter(
DE_CD_ID_Cod = cod_id,
DE_VL_Ponto = extra)
Vaz1 = VAZ.objects.values_list('VA_CD_ID_S_Vaz', flat = True).filter(
VA_CD_ID_Cod = cod_id,
VA_VL_Ponto = extra)
Pres1 = PRES.objects.values_list('PR_CD_ID_S_Pres', flat = True).filter(
PR_CD_ID_Cod = cod_id,
PR_VL_Ponto = extra)
cursor.execute('giant query',(str(sensorPres[0]), inicio, final,
str(sensorTemp[0]), inicio, final,
str(sensorDens[0]), inicio, final,
str(sensorVaz[0]), inicio, final))
lista = cursor.fetchall()
listaArray = np.asarray(lista)
tempo = listaArray[:,0]
valpres = listaArray[:,1]
valpres = np.array(valpres)
valpres = valpres.astype(float)
valtemp = listaArray[:,2]
valtemp = np.array(valtemp)
valtemp = valtemp.astype(float)
valden = listaArray[:,3]
valden = np.array(valden)
valden = valden.astype(float)
valvaz = listaArray[:,4]
valvaz = np.array(valvaz)
valvaz = valvaz.astype(float)
kwargs['tempo'] = tempo
kwargs['valpres'] = valpres
kwargs['valtemp'] = valtemp
kwargs['valden'] = valden
kwargs['valvaz'] = valvaz
kwargs['dateInicial'] = inicio
kwargs['dateFinal'] = final
return super().get_context_data(**kwargs)
forms.py:
class get_Codigo_DutoGrafico1(forms.Form):
# codigoID is a PK in the model.
codigoID = forms.ModelMultipleChoiceField(label = "Código ID",
queryset = PRINCIPAL.objects.values_list('CD_ID', flat = True),
widget = forms.SelectMultiple(attrs = {'id' : 'id_codigo_id'}))
dateDataInicial = forms.DateTimeField(label = 'Data Inicial',
input_formats = ['%d/%m/%Y %H:%M:%S'],
widget=XDSoftDateTimePickerInput())
dateDataFinal = forms.DateTimeField(label = 'Data Final',
input_formats = ['%d/%m/%Y %H:%M:%S'],
widget=XDSoftDateTimePickerInput())
valorExtra = forms.ModelMultipleChoiceField(label = 'Valor Extra',
queryset = DENS.objects.values_list('DE_VL_Ponto', flat = True).none(),
widget = forms.SelectMultiple(attrs = {'id' : 'id_codigoDropDown'}))
index.html:
<div class = "container-fluid" id = "wrapper">
<div class = "row">
{% load i18n %}
{% block head %}
{{ wizard.form.media }}
{% endblock %}
{% block content %}
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action = "" method = "post" id = "formGrafico" data-data-url="{% url 'ajax_load_duto' %}" data-data2-url="{% url 'ajax_load_data2' %}" novalidate>
{% csrf_token %}
<table>
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form }}
{% endfor %}
{% else %}
{{ wizard.form }}
{% endif %}
</table>
{% if wizard.steps.prev %}
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.first }}">{% trans "first step" %}</button>
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">{% trans "prev step" %}</button>
{% endif %}
<input type="submit" value="{% trans "submit" %}"/>
</form>
{% endblock %}
我希望获得 detail.html 中的值并以不同方式显示数据。但是,我收到以下错误:'int' 对象没有属性 'pk'。 POST return 如下:
POST
Variable Value
csrfmiddlewaretoken
'TArU7O0laFVnRiWp9rEpUOE4bUoPNYulB2zNkFbwnLFxbVBwr4Qmp7ZQ5FfhJ3r7'
index_view-current_step
'opcao1'
opcao1-codigoDuto
'177'
opcao1-dateDataInicial
'03/05/2018 10:19:00'
opcao1-dateDataFinal
'01/07/2018 10:20:00'
opcao1-codigoExtremidade
'2,127000000000000'
整个错误回溯:
Environment:
Request Method: POST
Request URL: http://127.0.0.1:8000/
Django Version: 2.1.7
Python Version: 3.6.7
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',
'compressor',
'django_extensions',
'solid',
'sekizai',
'formtools']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback:
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
34. response = get_response(request)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
126. response = self.process_exception_by_middleware(e, request)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
124. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/views/generic/base.py" in view
68. return self.dispatch(request, *args, **kwargs)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/formtools/wizard/views.py" in dispatch
248. response = super(WizardView, self).dispatch(request, *args, **kwargs)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/views/generic/base.py" in dispatch
88. return handler(request, *args, **kwargs)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/formtools/wizard/views.py" in post
301. if form.is_valid():
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/forms/forms.py" in is_valid
185. return self.is_bound and not self.errors
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/forms/forms.py" in errors
180. self.full_clean()
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/forms/forms.py" in full_clean
381. self._clean_fields()
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/forms/forms.py" in _clean_fields
399. value = field.clean(value)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/forms/models.py" in clean
1293. qs = self._check_values(value)
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/forms/models.py" in _check_values
1326. pks = {str(getattr(o, key)) for o in qs}
File "/home/luiz/Projeto/Solid/venv/lib/python3.6/site-packages/django/forms/models.py" in <setcomp>
1326. pks = {str(getattr(o, key)) for o in qs}
Exception Type: AttributeError at /
Exception Value: 'int' object has no attribute 'pk'
所以数据是从 SessionWizardView 传递过来的,但是中间有些东西是错误的。为了测试 'int' 问题,我将 str() 设置为 "cod_id" 并且仍然收到 'int' 错误消息。我在 Stack 中搜索了一些与之相关的内容,但我一无所获。
错误是因为你的 ModelMultipleChoiceField
有一个 queryset
属性设置为一个整数列表,这是错误的,你的查询集应该是一个对象列表:PRINCIPAL.objects.all()
。 ModelMultipleChoiceField
接收一个整数作为输入(发布的数据),但想要一个对象 (PRINCIPAL
) 作为 value
。
如果您想自定义值向用户显示的方式,您应该继承 ModelMultipleChoiceField
并覆盖 label_from_instance
方法:
class IDModelMultipleChoiceField(ModelMultipleChoiceField):
def label_from_instance(self, instance):
return instance.pk
并在您的表单中
cogidoID = IDModelMultipleChoiceField(queryset=..., label=...)