Merge Login and Signup into one view in django - 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.

Related

how to i save data in django after i filter in forms using kwargs.pop?

When a try to filter category to match user, it works but I can't save data to the form anymore and it shows no error but the data didn't save? ..
forms.py:
from django import forms
from django.forms import ModelForm
from .models import Createservice
from .models import Category
class Serviceform(ModelForm):
class Meta:
model = Createservice
fields = ['user', 'Service_name',
'description', 'your_sertificate', 'category']
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
super(Serviceform, self).__init__(*args, **kwargs)
print(self.user)
if self.user is not None:
self.fields['category'].queryset = Category.objects.filter(
wilaya=self.user.wilaya)
views.py:
#login_required
def createservice(request):
if request.method == 'POST':
user = request.user
services = Serviceform(request.POST,request.FILES, user=user)
if services.is_valid():
servicess = services.save(commit=False)
servicess.user = user
servicess.save()
return redirect('index')
else:
user = request.user
services = Serviceform(user=user)
context = {"service": services}
return render(request, 'services/createservice.html', context)
createservice.html:
<form action="{% url 'create-service' %}" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-row">
<div class="col form-group">
<label>Service_name</label>
{{service.Service_name}}
</div> <!-- form-group end.// -->
<div class="col form-group">
<label>Description</label>
{{service.description}}
</div> <!-- form-group end.// -->
</div> <!-- form-row end.// -->
<div class="form-row">
<div class="form-group col-md-6">
<label>your_sertificate </label>
{{service.your_sertificate}}
</div> <!-- form-group end.// -->
<!-- form-group end.// -->
</div> <!-- form-row.// -->
<!-- form-row.// -->
<div class="form-row">
<div class="form-group col-md-6">
<label>select your category </label>
{{service.category}}
</div> <!-- form-group end.// -->
<!-- form-group end.// -->
</div> <!-- form-row.// -->
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block"> Send </button>
</div> <!-- form-group// -->
</form>
urls.py:
path('createservice', views.createservice, name='create-service'),

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

Issues with two forms submission in django one after another

I'm working on forget password page in which the user first have to answer the question for enabling the textfields for creating new password.
Here, I have two forms, One for security question and second for password and confirm password.
Following is my forms.py
from django import forms
from .models import SecurityQuestions
class PasswordForm(forms.Form):
password = forms.CharField(disabled=True, widget=forms.PasswordInput(attrs={'placeholder':'New Password'}))
password_confirm = forms.CharField(disabled=True, widget=forms.PasswordInput(attrs={'placeholder':'Re-enter Password'}))
def clean(self, *args,**kwargs):
password = self.cleaned_data.get('password')
password_confirm = self.cleaned_data.get('password_confirm')
if password and password_confirm:
if password != password_confirm:
raise forms.ValidationError('Password Mismatch')
return super(PasswordForm, self).clean(*args, **kwargs)
class PasswordVerificationForm(forms.Form):
question = forms.ModelChoiceField(queryset=SecurityQuestions.objects.all(), empty_label=None, widget=forms.Select(attrs={'class':'form-control','id': 'sectxt'}))
answer = forms.CharField(label='answer', widget=forms.TextInput(attrs={'placeholder':'Answer','id': 'anstxt'}))
Following is my views.py
from django.shortcuts import render, redirect
from .forms import PasswordForm, PasswordVerificationForm
from django.contrib.auth.decorators import login_required
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.hashers import make_password
from .models import SecurityQuestions
from django.contrib import messages
#login_required
#csrf_exempt
def password_reset(request):
form = PasswordForm(request.POST or None)
form1 = PasswordVerificationForm(request.POST or None)
if request.method == 'POST':
if request.POST.get("verify", False):
question = request.POST.get('question')
answer = request.POST.get('answer')
print("question",question)
print("answer",answer)
check = SecurityQuestions.objects.get(id=question) #id=1
print(check.answer)
if check.answer == answer:
messages.success(request, 'Enter Your New Password', 'alert-success')
form.fields['password'].disabled = False
form.fields['password_confirm'].disabled = False
else:
redirect('/')
messages.error(request, 'Incorrect Answer', 'alert-danger')
if request.POST.get("create", False):
if form.is_valid():
print("For Changing Password...")
password = form.cleaned_data.get('password')
request.user.password = make_password(password)
request.user.save()
return redirect('/')
else:
form = PasswordForm()
form1 = PasswordVerificationForm()
return render(request,"forget_password.html", {"form": form, "form1":form1})
Following is my forget_password.html
<div class="container">
<div class="main">
<div class="row justify-content-center">
<div class="col-md-4">
<div class="login-form">
<div class="row">
<div class="col-md-12">
<div class="login-title-holder">
<h4>Forgot Password</h4>
</div>
</div>
<form method="post">
<div class="form-group col-md-12">
<div class="input-group">
{{ form1.question | add_class:'form-control' }}
<span class="input-group-append">
<div class="input-group-text input-group-icon"><i class="fa fa-question" aria-hidden="true"></i></div>
</span>
</div>
</div>
<div class="form-group col-md-12">
<div class="input-group">
{{ form1.answer | add_class:'form-control' }}
<span class="input-group-append">
<div class="input-group-text input-group-icon "><i class="fa fa-comment" aria-hidden="true"></i></div>
</span>
</div>
</div>
<div class="col-md-12">
{% if messages %}
{% for message in messages %}
<div {% if message.tags %} class="alert {{ message.tags }} text-center"{% endif %}>
×
{{ message }}
</div>
{% endfor %}
{% endif %}
<input type="submit" name = "verify" formmethod="post" style="visibility: hidden;">
</div>
</form>
<form method="post">
<div class="form-group col-md-12">
<div class="input-group">
{{ form.password | add_class:'form-control' }}
<span class="input-group-append">
<div class="input-group-text input-group-icon"><i class="fa fa-key" aria-hidden="true"></i></div>
</span>
</div>
</div>
<div class="form-group col-md-12">
<div class="input-group">
{{ form.password_confirm | add_class:'form-control' }}
<span class="input-group-append">
<div class="input-group-text input-group-icon"><i class="fa fa-key" aria-hidden="true"></i></div>
</span>
</div>
</div>
<div class="col-md-12">
<div class="button-holder">
Cancel
<button class="login-btn" type="submit" formmethod="post" name="create">Create</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
If I enter the security answer first, based on the condition, if true, it enables the textfields for password and password_confirm.
But it's not creating the new password.
However, if I change the disabled = False in PasswordForm then it creating the new password successfully.
I want to know why it's not executing the code after the first form executes successfully.
Thanks!
You really should chain this into 2 urls, rather then trying 2 forms in one page. You can only submit one form and this is the problem you're facing. Once you have submitted the security question, you instantiate the form again with fields disabled:
form = PasswordForm(request.POST or None)
And now they do not get enabled, because the submit button called 'verify' from form1 is no longer present, so the code in that branch is not executed.
Let's say url is /password_reset/ - a rough outline (untested):
#login_required
#csrf_exempt
def security_question(request):
form = PasswordVerificationForm(request.POST)
if request.method == 'POST':
if form.is_valid():
token = generate_strong_token() # Implement: generate a strong token, url safe
request.session["password_reset_token"] = token
return redirect(f'/password_reset/{token}/')
else:
return render(...)
#login_required
#csrf_exempt
def change_password(request, **kwargs):
form = PasswordForm(request.POST)
token = request.session.get('password_reset_token')
if token == kwargs['token']:
if request.method == 'POST' and form.is_valid():
del request.session['password_reset_token']
# handle password change and redirect to wherever
else:
return render(...)
else:
raise SecurityError('Invalid token')
Your urls would be something like:
urlpatterns = [
re_path('password_reset/(?P<token>[0-9A-F]{32})/', change_password)
path('password_reset/', security_question)
]

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.

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