Crispy-forms form.name renders rubbish - django

I'm trying to render a form but the {{form.name}} renders rubbish. The problem is that I can't even debug this to figure where the thing gets crooked.
The form:
class ActionItemForm(forms.ModelForm):
class Meta:
model = ActionItem
fields = ('project', 'portfolio', 'name', 'description', 'resolution', 'parent', 'priority', 'status', 'assignee', 'due_date')
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout()
super(ActionItemForm, self).__init__(*args, **kwargs)
The view:
def action_item_actions(request, action_item_id, action_code):
def enrich_form(wf_item, form):
form.id = 'edit_action_item'
form.name = form.id
form.title = wf_item.name
form.action = '/forms/action_item/edit/%s' % action_item_id
return form
action_item = ActionItem.objects.get(id=action_item_id)
wf_item = action_item.wf_get_action_by_code(action_code)
if wf_item:
if wf_item.trans_to:
form = ActionItemForm(instance=action_item, initial={action_item.get_wf_field(): type(getattr(action_item, action_item.get_wf_field())).objects.get(id=wf_item.trans_to)})
else:
form = ActionItemForm(instance=action_item)
form = enrich_form(wf_item, form)
for field in form.Meta.fields:
if field not in wf_item.fields:
form.helper.layout.fields.append(Field(field, type='hidden'))
return render_to_response('forms/modal_form.html', {'form': form}, template.RequestContext(request))
else:
return render_to_response('forms/message.html', {'message': Message('Error', 'WF Descriptor not found')}, template.RequestContext(request))
When the form exists the view, the form.name is correct:
Now when the form enters the template, it's still ok:
The view is quite simple:
{% load crispy_forms_tags %}
<form id="{{ form.id }}" role="form" class="small" name="{{ form.name }}">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">{{ form.title }}</h4>
</div>
<div class="modal-body">
{% crispy form %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<input type="button" class="btn btn-primary" value="Save" id="" onclick="submit_form('{{ form.id }}','{{ form.action }}')">
</div>
</div>
</div>
</form>
However, the form tag is rendered as this:
<form id="edit_action_item" role="form" class="small" name="<input id="id_name" maxlength="256" name="name" type="text" value="Test action item" />">
How can I track down where this gets broken? I kind of suspect that it gets broken because form may be potentially mixing the 'name' field with the form.name attribute.

You have field name in your form. So {{ form.name }} returns output for field name. You can put form name to other variable in __init__:
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.layout = Layout()
super(ActionItemForm, self).__init__(*args, **kwargs)
self.form_name = self.name # this line added
and call {{ form.form_name }} in template

<section class="form">
<h5>Contact Form</h5>
<h6>Let Us Know</h6>
<form action="{% url 'web:contact' %}" method="post" class="ajax">
{% csrf_token %}
<p class="left">
<label for="{{form.name.label.id_for_label}}">
{{form.name.label}}
{% if form.name.field.required %}
<small class="star">*</small>
{% endif %}
</label>
{{form.name}}
{% if form.name.errors %}
<span class="error">{{form.name.errors.as_text}}</span>
{% endif %}
</p>
</form>
</section>

Related

passing instance to Django modal form

I want to do edit on a modal pop up form, edit is working but cant see the existing instance, how I can do it? any help is appreciated.
Here I have passed the form as below
class DomainListView(ListView):
model = Domain
template_name = 'super_admin/domain_list.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
form = DomainEditForm(self.request.POST or None)
context['form'] = form
return context
and the template is as follows
<div class="modal fade" id="domain-edit-{{ item.pk }}">
<div class="modal-dialog" role="document">
<form class="form-valide" action="{% url 'domain_edit' item.pk %}" method="POST" id=""
enctype="multipart/form-data">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"> Edit Domain </h5>
<button type="button" class="close" data-dismiss="modal"><span>×</span>
</button>
</div>
<div class="modal-body">
<div class="basic-form">
<div class="form-group">
{% csrf_token %}
{{ form.errors }}
{{ form | crispy }}
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">submit</button>
</div>
</div>
</form>
</div>
</div>
this is inside for loop along with list items, I tried to fetch the instance as follows in get context data override, but it gives key error
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
obj = get_object_or_404(Domain, kwargs={'pk': self.kwargs['pk']})
form = DomainEditForm(self.request.POST or None, instance=obj)
context['form'] = form
return context

How to add multiple lines of the Formset?

i work on the form for users.
They have to add many model objects in the appropriate form.
one line is displayed when entering the GET method,
they will type in input name = "add-rows-number" the number should be displayed the number of forms in the formset
I tried with formset and with model formsetfactory
class AddCostCenters(View):
def __init__(self, *args, **kwargs):
super(AddCostCenters, self).__init__(*args, **kwargs)
self.FormSet = modelformset_factory(CostCenter, form=CostCenterAddForm, extra=self.get_form_size)
def get_form_size(self, request):
extra_rows_num = 1
if 'add-rows' in request.POST:
extra_rows_num += int(request.POST.get('add-rows-number'))
return extra_rows_num
def get(self, request, proceeding_id):
costcenter_model = CostCenter.objects.filter(
participation__provider__user=request.user,
participation__proceeding=proceeding_id
)
return TemplateResponse(request, 'costcenteradd.html', context)
def post(self, request, proceeding_id):
costcenter_model = CostCenter.objects.filter(
participation__provider__user=request.user,
participation__proceeding=proceeding_id
)
# if 'add-rows' in request.POST:
# try:
# rows_to_show = int(request.POST.get('add-rows-number'))
# except ValueError:
# rows_to_show = 0
# self.extra_rows_number += rows_to_show
if 'save_form' in request.POST:
new_cost_centers = []
post_formset_data = self.FormSet(request.POST)
if post_formset_data.is_valid():
instances = post_formset_data.save(commit=False)
new_cost_centers.append(instance)
# do something
else:
post_form = post_formset_data
context = {
'form': post_form,
}
return render(request, 'costcenteradd.html', context)
form
class CostCenterAddForm(forms.ModelForm):
# helper = CostCenterAddFormSetHelper()
def __init__(self, *args, **kwargs):
super(CostCenterAddForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_show_labels = False
for field_name, field in self.fields.items():
field.help_text = None
class Meta:
model = CostCenter
fields = (
'id',
'cost_center_account_no',
'cost_center_account_name',
'departmental_code',
'values_for_year',
'only_total_cost_of_cost_center',
)
exclude = (
'participation',
'to_check',
'is_checked',
'accepted',
'use_in_calculations',
)
html
<div class="container-fluid ">
<form method="post">
{% csrf_token %}
{{ form.management_form }}
<div class="row sticky-top text-center form-nav">
<div class="col-md-2 content_center"> Numer Konta OPK </div>
<div class="col-md-4 content_center"> Nazwa konta OPK </div>
<div class="col-md-2 content_center"> Kod resortowy </div>
<div class="col-md-1 content_center"> Rok za który jest postępowanie </div>
<div class="col-md-1 content_center"> Uproszczone dane finansowe </div>
<div class="col-md-2 content_center"> Usuń </div>
</div>
<div class="section sticky-top my-2 form-panel ">
<div class="row sticky-top my-2">
<div class="col-md-2">
<button class="btn btn-success btn-block" type="submit" name="save_form">Zapisz</button>
</div>
<div class="col-md-4">
<div class="input-group mb-3">
<input class="form-control" min="1" type="number" name="add-rows-number"
value={{form.total_form_count }}
placeholder="number" aria-label="add form rows ">
<div class="input-group-append">
<button class="btn btn-info" type="submit" name="add-rows">show_rows</button>
</div>
</div>
</div>
</div>
</div>
<hr>
{% for field in form %}
<div class="row text-center">
<div class="col-md-2 paste-in">
{{field.cost_center_account_no | as_crispy_field}}
</div>
<div class="col-md-4 paste-in">
{{field.cost_center_account_name | as_crispy_field}}
</div>
<div class="col-md-2 paste-in">
{{field.departmental_code | as_crispy_field}}
</div>
<div class="col-md-1 paste-in">
{{field.values_for_year | as_crispy_field}}
</div>
<div class="col-md-1">
{{field.only_total_cost_of_cost_center | as_crispy_field}}
</div>
<div class="col-md-2">
<input type="submit" name="del_btn{{ field.instance.id }}" value="del"
{% if field.instance.id == None %}
class="btn btn-outline-secondary" disabled
{% else %}
class="btn btn-outline-danger"
{% endif%} />
</div>
</div>
You need to create the formset in both your get() and post() methods and add it to your context. You use the queryset attribute to populate it with existing instances:
formset = self.FormSet(queryset=CostCenter.objects.filter(...))
# or
formset = self.FormSet(queryset=CostCenter.objects.filter(...), data=request.POST)
Then in your template, you loop through your formset (what you call form in your template is actually a formset):
{{ formset.management_form }}
{% for form in formset %}
{{ form.cost_center_account_no|as_crispy_field }}
...
{% endfor %}
In your definition of self.FormSet, set extra=1 so users have at least one extra row. Remove the calculation, because that cannot work. request isn't available in the __init__() of a View (it gets added with as_view()).
Now I would not have users submit the number of extra rows, you can just deduct it from the input data. Write some javascript to let users add rows themselves directly, like you see in the admin:
Add a + button to add an extra row
The javascript clones the previous row, adds it to the list of forms (with empty input fields)
The javascript also updates the value for TOTAL_FORMS and MAX_FORMS input fields (hidden fields in the management form)
This way when users submit the formset, it will have the extra rows.

Simple Django form and get value submitted

I would like to create a Django form very easy, than I would like to pick up the value from both fields.
This is my form :
class SettingsForm(forms.Form):
download_validity = forms.CharField(label='Expiry Download')
flag_validity = forms.CharField(label='Expiry Flag')
def __init__(self, *args, **kwargs):
super(SettingsForm, self).__init__(*args, **kwargs)
Then, I have a view :
class SettingsView(FormView):
template_name = 'settings.html'
form_class = SettingsForm
def get_context_data(self, **kwargs):
subtitle = _("Manage Settings")
context_data = super(SettingsView, self).get_context_data(**kwargs)
context_data['subtitle'] = subtitle
return context_data
def form_valid(self, form):
download_validity = form.cleaned_data['download_validity']
flag_validity = form.cleaned_data['flag_validity']
print(download_validity)
print(flag_validity)
return super(SettingsView, self).form_valid(form)
And finally my template view :
{% block main %}
<div class="container">
<div class="row">
<form autocomplete="off" method="get" action="">
<fieldset>
<legend class="title"><span class="name">{% trans 'Expiry Download link' %}</span></legend>
</fieldset>
{{ form.download_validity|as_crispy_field }}
<input type="submit" class="btn btn-default" name="UpdateDownload" value="{% trans 'Update' %}"/>
</form>
</div>
<div class="row">
<form autocomplete="off" method="get" action="">
<fieldset>
<legend class="title"><span class="name">{% trans 'Expiry New Publication' %}</span></legend>
</fieldset>
{{ form.flag_validity|as_crispy_field }}
<input type="submit" class="btn btn-default" name="UpdateFlag" value="{% trans 'Update' %}"/>
</form>
</div>
</div>
{% endblock main %}
I don't know why, but I would like to get value thanks to cleaned_data but the print function doesn't display anything. I don't know if I missed something but all seems to be right.
I have to create 2 forms in my forms.py file instead of one ?
In your template you should create the form outside of your rows, like so:
<form ...>
<div class="row">
<input .../>
</div>
<div class="row">
<input .../>
</div>
</form>
Have you made sure if your form is both valid and also being posted? (You could just simply debug inside your view and a few more prints that check if the request is POST etc. Maybe you are also missing your CSRF-Token as it isn't defined in your template (https://docs.djangoproject.com/en/2.1/ref/csrf/)
You could also let the form render itself. For example via {% crispy form %} in your case (https://django-crispy-forms.readthedocs.io/en/latest/crispy_tag_forms.html)

Merge Login and Signup into one view in django

Merging login/signup view into one view, say LoginSignupView because I have login, signup form in one template.
I refered https://gist.github.com/jamesbrobb/748c47f46b9bd224b07fbut think that it doesn't work (Actually I don't know how it works)
My views.py :
from django.views.generic.base import ContextMixin, TemplateResponseMixin
from django.views.generic.edit import ProcessFormView
from django.http.response import HttpResponseRedirect, HttpResponseForbidden
from django.contrib.auth.forms import AuthenticationForm
from users.forms import MyUserCreationForm
class MultiFormMixin(ContextMixin):
form_classes = {}
prefixes = {}
success_urls = {}
grouped_forms = {}
initial = {}
prefix = None
success_url = None
def get_form_classes(self):
return self.form_classes
def get_forms(self, form_classes, form_names=None, bind_all=False):
return dict([(key, self._create_form(key, klass, (form_names and key in form_names) or bind_all)) \
for key, klass in form_classes.items()])
def get_form_kwargs(self, form_name, bind_form=False):
kwargs = {}
kwargs.update({'initial':self.get_initial(form_name)})
kwargs.update({'prefix':self.get_prefix(form_name)})
if bind_form:
kwargs.update(self._bind_form_data())
return kwargs
def forms_valid(self, forms, form_name):
form_valid_method = '%s_form_valid' % form_name
if hasattr(self, form_valid_method):
return getattr(self, form_valid_method)(forms[form_name])
else:
return HttpResponseRedirect(self.get_success_url(form_name))
def forms_invalid(self, forms):
return self.render_to_response(self.get_context_data(forms=forms))
def get_initial(self, form_name):
initial_method = 'get_%s_initial' % form_name
if hasattr(self, initial_method):
return getattr(self, initial_method)()
else:
return self.initial.copy()
def get_prefix(self, form_name):
return self.prefixes.get(form_name, self.prefix)
def get_success_url(self, form_name=None):
return self.success_urls.get(form_name, self.success_url)
def _create_form(self, form_name, klass, bind_form):
form_kwargs = self.get_form_kwargs(form_name, bind_form)
form_create_method = 'create_%s_form' % form_name
if hasattr(self, form_create_method):
form = getattr(self, form_create_method)(**form_kwargs)
else:
form = klass(**form_kwargs)
return form
def _bind_form_data(self):
if self.request.method in ('POST', 'PUT'):
return{'data': self.request.POST,
'files': self.request.FILES,}
return {}
class ProcessMultipleFormsView(ProcessFormView):
def get(self, request, *args, **kwargs):
form_classes = self.get_form_classes()
forms = self.get_forms(form_classes)
return self.render_to_response(self.get_context_data(forms=forms))
def post(self, request, *args, **kwargs):
form_classes = self.get_form_classes()
form_name = request.POST.get('action')
if self._individual_exists(form_name):
return self._process_individual_form(form_name, form_classes)
elif self._group_exists(form_name):
return self._process_grouped_forms(form_name, form_classes)
else:
return self._process_all_forms(form_classes)
def _individual_exists(self, form_name):
return form_name in self.form_classes
def _group_exists(self, group_name):
return group_name in self.grouped_forms
def _process_individual_form(self, form_name, form_classes):
forms = self.get_forms(form_classes, (form_name,))
form = forms.get(form_name)
if not form:
return HttpResponseForbidden()
elif form.is_valid():
return self.forms_valid(forms, form_name)
else:
return self.forms_invalid(forms)
def _process_grouped_forms(self, group_name, form_classes):
form_names = self.grouped_forms[group_name]
forms = self.get_forms(form_classes, form_names)
if all([forms.get(form_name).is_valid() for form_name in form_names.values()]):
return self.forms_valid(forms)
else:
return self.forms_invalid(forms)
def _process_all_forms(self, form_classes):
forms = self.get_forms(form_classes, None, True)
if all([form.is_valid() for form in forms.values()]):
return self.forms_valid(forms)
else:
return self.forms_invalid(forms)
class BaseMultipleFormsView(MultiFormMixin, ProcessMultipleFormsView):
"""
A base view for displaying several forms.
"""
class MultiFormsView(TemplateResponseMixin, BaseMultipleFormsView):
"""
A view for displaying several forms, and rendering a template response.
"""
class LoginSignupView(MultiFormsView):
template_name = 'users/login_signup.html'
form_classes = {'login': AuthenticationForm,
'signup': MyUserCreationForm}
success_url = '/'
def get_login_initial(self):
return {'email':'dave#dave.com'}
def get_signup_initial(self):
return {'email':'dave#dave.com'}
def get_context_data(self, **kwargs):
context = super(LoginSignupView, self).get_context_data(**kwargs)
context.update({"some_context_value": 'blah blah blah',
"some_other_context_value": 'blah'})
return context
def login_form_valid(self, form):
return form.login(self.request, redirect_url=self.get_success_url())
def signup_form_valid(self, form):
user = form.save(self.request)
return form.signup(self.request, user, self.get_success_url())
template : login_signup.html
{% extends 'chacha_dabang/skeleton/base.html' %}
{% load pipeline%}
{% block content %}
<div class="container">
<div id="loginbox" class="mainbox">
<div class="panel panel-info">
<div class="panel-heading">
<div class="panel-title">Sign In</div>
</div>
<div class="panel-body">
<div id="login-alert" class="alert alert-danger col-sm-12"></div>
<form id="loginform" class="form-horizontal" role="form" method="post" action="{% url 'users:login_signup' %}">
{% csrf_token %}
<!-- id / pw -->
<div class="input-group">
<span class="input-group-addon"><i class="icon-user"></i></span>
<input id="id_username" type="text" class="form-control" name="username" value="" placeholder="username">
</div>
<div class="input-group">
<span class="input-group-addon"><i class="icon-lock"></i></span>
<input id="id_password" type="password" class="form-control" name="password" placeholder="password">
</div>
<div class="form-group">
<!-- Button -->
<div class="btn-controls">
<div class="row">
<input id="btn-login" class="btn btn-success" type="submit" name="login_submit" value="로 그 인" />
<a id="btn-fblogin" href="{% url 'social:begin' backend='facebook' %}" class="btn btn-primary col-xs-12"><i class="icon-facebook"></i> 1초만에 페이스북으로 로그인 </a>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-12 control">
<div class="signup">
아직 차차다방 회원이 아니세요? &nbsp
가입하기
</div>
<div class="forget">
비밀번호를 잊어버리셨나요?
</div>
</div>
</div>
</form>
</div> <!-- <div class="panel-body" > -->
</div> <!-- <div class="panel panel-info"> -->
</div> <!-- <div id="loginbox"> -->
<!-- Sign up Form -->
<div id="signupbox" class="mainbox">
<div class="panel panel-info">
<div class="panel-heading">
<div class="panel-title">Sign Up</div>
</div>
<div class="panel-body">
<form id="signupform" class="form-horizontal" role="form" method="post" action="{% url 'users:login_signup' %}">
{% csrf_token %}
<!-- signup -->
<div id="signupalert" class="alert alert-danger">
<p>Error:</p>
<span></span>
</div>
{{ forms.signup.as_p }}
<!--
<div class="form-group">
<label for="id_username" class="col-md-3 control-label"> 아이디: </label>
<div class="col-md-9">
{{ form.username }}
</div>
</div>
-->
<div class="form-group">
<!-- Button -->
<div class="btn-controls">
<div class="row">
<input id="btn-signup" class="btn btn-success" type="submit" name="signup_submit" value="가 입 하 기" />
<a id="btn-fblogin" href="{% url 'social:begin' backend='facebook' %}" class="btn btn-primary col-xs-12"><i class="icon-facebook"></i>1초만에 페이스북으로 로그인</a>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-12 control">
<div class="login">
이미 차차다방 회원이신가요? &nbsp
로그인하기
</div>
</div>
</div>
</form>
</div> <!-- <div class="panel-body"> -->
</div> <!-- <div class="panel panel-info"> -->
</div> <!-- <div id="signupbox"> -->
</div> <!-- <div class="container"> -->
{% endblock %}
{% block custom_js %}
{% javascript "account" %}
{% endblock %}
First, I test creating user (signup) but when I submit the button, it doesn't create new user.
What am I missing?
Your code is too much to go through, and has a lot of lines for a simple challenge. There are many options.
Create custom views instead of using Form Mixins. They would be a lot easier to write and understand. Identify the form submitted by a hidden input in each form.
Create 2 views using the Mixins, each for login and signup and modify the action part of your forms to submit to the correct view respectively.
Hope it helps.

Django - 405 POST not allowed

I have a form like so:
{% extends "interface/base.html" %}
{% load subscribertags %}
{% block title %}{{ object }}{% endblock %}
{% block center %}
<div class="page-header">
<h1>Редактирование меню <small>{% operator_name object.operator %}: {{ object }} ({{ object.slug }})</small></h1>
</div>
<!-- Modal -->
<div class="modal fade" id="itemModal" tabindex="-1" role="dialog" aria-labelledby="itemModalTitle" aria-hidden="true">
<form method="post">{% csrf_token %}
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="itemModalTitle">Добавить пункт</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="item_name">Действие</label>
<select class="form-control" name="action">
<option value="">----------</option>
{% for value, action in actions %}
<option value="{{ value }}">{{ action }}</option>
{% endfor %}
</select>
</div>
<div class="checkbox">
<label>
<input id='is_hidden' type="checkbox" name='is_hidden' > Спрятать
</label>
</div>
<div class="checkbox">
<label>
<input id='allow_back' type="checkbox" name='allow_back' > Пункт назад
</label>
</div>
<div class="form-group">
<label for="label">Метка</label>
<input type="text" class="form-control" id="label" placeholder="Название метки" name='slug'>
</div>
<div class="form-group">
<label for="params">Доп параметры</label>
<textarea type="text" class="form-control" id="params" placeholder="Дополнительные параметры" name='params'></textarea>
</div>
{% for code, language in languages %}
<div class="form-group">
<h5>{{ language }}</h5>
{% if code = object.default_language %}
<label for="text">Текст</label>
<input type="text" class="form-control" id="text" placeholder="Текст" name='text'>
<label for="result_text">Текст результата</label>
<input type="text" class="form-control" id="result_text" placeholder="Текст результата" name='result_text'>
{% else %}
<label for="text-{{ code }}">Текст</label>
<input type="text" class="form-control" id="text-{{ code }}" placeholder="Текст" name='text-{{ code }}'>
<label for="result_text-{{ code }}">Текст результата</label>
<input type="text" class="form-control" id="result_text-{{ code }}" placeholder="Текст результата" name='result_text-{{ code }}'>
{% endif %}
</div>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Отмена</button>
<button type="subbmit" class="btn btn-primary">Сохранить</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</form>
</div><!-- /.modal -->
<div class="tree">
{% if object.item_set.count %}
<ul>
{% with object.item_set.all.0 as item %}
{% include "interactive/interface/menu_item.html" %}
{% endwith %}
</ul>
{% endif %}
</div>
{% endblock %}
SECOND PART:
{% load interactivetags %}
<li class="element-interactive-item{% if not item.is_visible %} i-hidden{% endif %}">
<span data-toggle="tooltip" title="{{ item.params }}" class='name'><i class="glyphicon glyphicon-{% item_icon item %}"></i> ({{ item.id }}) {{ item }} {% if item.slug %}({{ item.slug }}){% endif %}
<a class='tool item-tool' data-values='{% item_to_json item %}' data-toggle="modal" data-target="#itemModal" data-label="Редактировать: {{ item }}" href="#" data-href="{% url "interactive.views.item_update" pk=item.pk %}"><i class="glyphicon glyphicon-edit"></i></a>
<a class='tool item-tool' data-toggle="modal" data-target="#itemModal" data-label="Добавить пункт" href="#" <data-href="{% url "interactive.views.item_create" pk=object.pk parent_pk=item.pk %}"><i class="glyphicon glyphicon-plus"></i></a>
{% if item.is_leaf_node and not item.is_root_node%}
<a class='tool confirm' href="{% url "interactive.views.item_delete" pk=item.pk %}"><i class="glyphicon glyphicon-remove"></i></a>
{% endif %}
<a class='tool confirm' href="{% url "interactive.views.item_up" pk=item.pk %}"><i class="glyphicon glyphicon-arrow-up"></i></a>
<a class='tool confirm' href="{% url "interactive.views.item_down" pk=item.pk %}"><i class="glyphicon glyphicon-arrow-down"></i></a>
</span>
<ul>
{% for item in item.get_children %}
{% include "interactive/interface/menu_item.html" %}
{% endfor %}
</ul>
</li>
When I hit the Save/Сохранить button data isn't updated in the database for this form and I get
"POST /interactive/1/ HTTP/1.1" 405 0
Code that handles the request:
# -*- coding: utf-8 -*-
from django.core.urlresolvers import reverse
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.contrib.contenttypes.models import ContentType
from django.http import HttpResponseRedirect
from interactive.models import Menu, Item
from interactive.forms import UpdateItemForm
from interface.views import InterfaceMixin
from interactive.processors import ProcessorManager
from subscribers.models import Subscriber
from languages.models import Translate
class MenuList(InterfaceMixin, ListView):
model = Menu
name = u'Интерактивные меню'
index = MenuList.as_interface_view(template_name='interactive/interface/index.html')
class MenuItem(InterfaceMixin, DetailView):
""" Редактирование интерактивного меню """
model = Menu
def get_context_data(self, **kwargs):
kwargs['actions'] = ProcessorManager.actions()
kwargs['languages'] = Subscriber.LANGUAGES
return super(MenuItem, self).get_context_data(**kwargs)
menu = MenuItem.as_interface_view(item=MenuList, template_name='interactive/interface/item.html')
class ItemMixin:
#classmethod
def update_language(cls, attribute, text, context):
if text:
o, _ = Translate.objects.get_or_create(attribute=attribute, **context)
o.text = text
o.save()
class CreateItemView(ItemMixin, InterfaceMixin, CreateView):
menu = None
parent = None
model = Item
form_class = UpdateItemForm
auth = False
def get_success_url(self):
return reverse("interactive.views.menu", kwargs={'pk': self.menu.pk})
def post(self, request, *args, **kwargs):
pk = kwargs.get('pk')
parent_pk = kwargs.get('parent_pk')
self.menu = Menu.objects.get(pk=pk)
self.parent = Item.objects.get(pk=parent_pk)
return super(CreateItemView, self).post(request, *args, **kwargs)
def form_valid(self, form):
form.instance.menu = self.menu
form.instance.insert_at(self.parent, position='last-child')
form.instance.save()
ct = ContentType.objects.get_for_model(form.instance)
for code, _ in Subscriber.LANGUAGES:
text = self.request.POST.get('text-%s' % code)
result_text = self.request.POST.get('result_text-%s' % code)
context = dict(content_type=ct, object_id=form.instance.pk, language=code, operator=self.menu.operator)
self.update_language('text', text, context)
self.update_language('result_text', result_text, context)
return super(CreateItemView, self).form_valid(form)
def form_invalid(self, form):
return super(CreateItemView, self).form_valid(form)
item_create = CreateItemView.as_view()
class UpdateItemView(ItemMixin, InterfaceMixin, UpdateView):
""" Изменение пункта меню """
model = Item
form_class = UpdateItemForm
auth = False
def get_success_url(self):
return reverse("interactive.views.menu", kwargs={'pk': self.object.menu.pk})
def form_valid(self, form):
ct = ContentType.objects.get_for_model(self.object)
for code, _ in Subscriber.LANGUAGES:
text = self.request.POST.get('text-%s' % code)
result_text = self.request.POST.get('result_text-%s' % code)
context = dict(content_type=ct, object_id=self.object.pk, language=code)
self.update_language('text', text, context)
self.update_language('result_text', result_text, context)
return super(UpdateItemView, self).form_valid(form)
def form_invalid(self, form):
return super(UpdateItemView, self).form_valid(form)
item_update = UpdateItemView.as_view()
class DeleteItemView(InterfaceMixin, DeleteView):
model = Item
auth = False
def get_success_url(self):
return reverse("interactive.views.menu", kwargs={'pk': self.object.menu.pk})
def get(self, request, *args, **kwargs):
return self.delete(request, *args, **kwargs)
item_delete = DeleteItemView.as_view()
class UpDownItemVew(DetailView):
action = None
model = Item
auth = False
def get(self, request, *args, **kwargs):
item = self.get_object()
if self.action == 'left':
other = item.get_previous_sibling()
else:
other = item.get_next_sibling()
item.move_to(other, position=self.action)
return HttpResponseRedirect(reverse("interactive.views.menu", kwargs={'pk': item.menu.pk}))
item_up = UpDownItemVew.as_view(action='left')
item_down = UpDownItemVew.as_view(action='right')
URL patterns:
urlpatterns = patterns(
'interactive.views',
(r'^(?P<pk>\d+)/(?P<parent_pk>\d+)/additem/$', "item_create"),
(r'^item/(?P<pk>\d+)/delete/$', "item_delete"),
(r'^item/(?P<pk>\d+)/up/$', "item_up"),
(r'^item/(?P<pk>\d+)/down/$', "item_down"),
(r'^item/(?P<pk>\d+)/$', "item_update"),
(r'^(?P<pk>\d+)/$', "menu"),
(r'^$', 'index'),
)
This code perfectly work on a production server, but wasn't uploaded by me and uses nginx as http server.
I am running it on local server using python manage.py runserver