I've implemented TinyMCE with the django-tinymce package. However, my submit button which worked fine without TinyMCE now has become rather useless since I can't submit the form, once everything is filled out.
I can use Ctrl + S inside of TinyMCE (I discovered that by accident) and everything will get submitted correctly. Also, I can use the save-button of the TinyMCE "save" plugin to submit.. Do I have to configure the submit button to make it work with TinyMCE?
Template:
{% extends 'medisearch/header.html' %}
{% load crispy_forms_tags %}
{% block header %}
{{ form.media }}
{% endblock %}
{% block content %}
▷⋅⋅⋅⋅⋅⋅⋅<form action="{{ url }}" method="post">
▷⋅⋅⋅⋅⋅⋅⋅ <div class="form-group">
▷⋅⋅⋅⋅⋅⋅⋅ {% csrf_token %}
▷⋅⋅⋅⋅⋅⋅⋅ {{ form|crispy }}
▷⋅⋅⋅⋅⋅⋅⋅ </div>
▷⋅⋅⋅⋅⋅⋅⋅ <input type="submit" class="btn btn-primary" value="Speichern" />
▷⋅⋅⋅⋅⋅⋅⋅</form>
{% endblock %}
views.py
class EntryDetail(DetailView):
model = Mediwiki
slug_field = 'non_proprietary_name'
template_name = 'mediwiki/entry.html'
class MediwikiForm(FormView):
template_name = 'mediwiki/create.html'
form_class = MediwikiForm⋅
success_url = "/" #TODO user get's redirected to page he's created⋅
def form_valid(self, form):
form.save()
return super(MediwikiForm, self).form_valid(form)
class EntryDisplay(View):
def get(self, request, *args, **kwargs):
try:
view = EntryDetail.as_view()
return view(request, *args, **kwargs)
except Http404: # If there's no entry in db:
if check_user_editor(request.user) == True:
view = MediwikiForm.as_view()
return view(request, *args, **kwargs)
else:
pass
def post(self, request, *args, **kwargs):
view = MediwikiForm.as_view()
return view(request, *args, **kwargs)⋅
forms.py
class MediwikiForm(ModelForm):
wiki_page = forms.CharField(widget=TinyMCE(attrs={'cols': 80, 'rows': 30}))
class Meta:
model = Mediwiki⋅
fields = '__all__'
TinyMCE is in urls.py and under INSTALLED_APPS..
I know it's probably too late for you, but it seems that i had the same issue, just now and my solution might help someone in the future.
You are using crispy, which includes the javascript files for the form on it's own.
Therefore the django_tinymce/init_tinymce.js will be referenced twice.
This will break the submittion of your content, since the form is initialized twice.
In order to fix this you may just remove the call of {{ form.media }}.
I had a similar issue and learned that it has to do with the way that TinyMCE deals with text areas. The following init script worked for me:
<script>
tinymce.init({
selector:'.editor',
setup: function (editor) {
editor.on('submit', function (e) {
editor.save();
});
}
});
</script>
#artifex_knowledge answers makes sense and it works.
To build up on it, besides calling editor.save() on submit (or on change), keep in mind that if users don't fill the text area, they won't be able to submit the form, but the this field is required error message won't be displayed.
This is because the text area field (in this case wiki_page) is required by default, so in the html it will be rendered with required. But TinyMCE hides the text area (and replaces it with an iframe :( ), so if you try to submit the form with an empty required, it won't, but the error message will keep hidden.
(A possible solution is to use JS to remove the required attribute and check it in django later).
Just delete required field from textarea element, which is used as editor.
Deleting the 'required' field in the textarea element solved my problem (like Krysits mentioned)
I also had the same issue as yours, and I just removed for instance: "wiki_page" charfield from the subclass of Modelform, and put Tinymce widget in the Meta class.
class MediwikiForm(ModelForm):
class Meta:
model = Mediwiki⋅
fields = '__all__'
widgets = {
'wiki_page': TinyMCE(attrs={'cols': 80, 'rows': 30})
}
Related
Hello everyone I have an HTML form as follows:
and after clicking on post i am redirecting it to views.py. can any one tell me how to get the field values of all the fields of the form into views.py.
here's the output
i want the field value in key value pair like shown in above pic i.e. API=hello&Area=hello1 so on...
i know we can do that using this
if html:
<div class="form-group col-md-2">
<label for="param">TAF Parameter</label>
<input type="text" name="inputdata_API" class="form-control" id="inputapi_param" value="API" readonly>
</div>
and view:
def register(request):
api = request.GET.get['inputdata_API']
But in that case i have to write each and every input name in my view
To get form input without individual access, Django provide ModelForm
For resume :
Define a model to store your form informations
class MyModel(models.Model):
api = models.CharField()
# ...
Define a model form linked to the previous model
from django import forms
class MyModelForm(forms.Form):
class Meta:
model = MyModel
fields = ['api', # all others fields you want to display]
In the views.py
from django.http import JsonResponse
from django.shortcuts import redirect
def register(request):
if request.method == 'POST':
# Instanciate the form with posted data
form = MyModelFor(request.POST)
# Check if form is valid
if form.is_valid:
# Create a new MyModel object if the form is valid
form.save() # This is the most benefit line, save you from request.POST['field_name']
# You can eventually return to the same page
return redirect('.')
else: # The form is invalid return a json response
return JsonResponse({"Error": "Form is invalid"}, status=400)
At the end render the form fields in the template like this :
<form action="{% url 'url_to_register' %}" method="post" novalidate>
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-success">Register</button>
</form>
But the downside of this approach is the style of the form on the frontend :
You need to add some Bootstrap class for example in the right place to make it nice to look, it is a a counterpart...
Django form documentation.
I'm working on an app that displays a form on the index page, into which you can enter information to eventually calculate a gross total and output other details based on the form inputs.
My form inherits from form.Forms.
A button, "Add row", creates as many copies of this row as needed.
Each form contains a form with the ID "calc-form". My problem is that only one form is included in the POST method. I would like to process all forms with one click.
How can I include all additional forms in the POST method when I click "Calculate"?
index.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
{% load static %}
<script type="text/javascript" src="{% static 'app.js' %}"></script>
<table id="table-id">
<tr id='table-row'>
<form id="calc-form" action="{% url 'result' %}" method="post">
{% csrf_token %}
{% for field in form %}
<td>{{ field|as_crispy_field }}</td>
{% endfor %}
</form>
</tr>
</table>
<br>
<input type="submit" value="Calculate" form="calc-form">
<button type="button" id="add-row-btn" onclick="addRow()">Add row</button>
<button type="button" id="delete-row-btn" onclick="deleteRow()">Delete last row</button>
{% endblock content %}
views.py
from django.shortcuts import render
from .forms import TariffCalcForm
def index(request):
form = TariffCalcForm
context = {'form': form}
return render(request, 'clickapp/index.html', context)
def result(request):
context = {}
if request.method == 'POST':
for r in request:
form = TariffCalcForm(request.POST)
if form.is_valid():
context['form'] = form
return render(request, 'result.html', context)
else:
return render(request, 'index.html', context)
app.js
function addRow() {
const formTable = document.getElementById('table-id');
const formRow = document.getElementById('table-row');
const formRowCopy = formRow.cloneNode(true);
formTable.appendChild(formRowCopy);
}
The form wizard may be appropriate. It allows you to progress through a sequence of forms, storing the results of submitting each in the client's session. This is of course in the database, but it can be made transient, and can be an anonymous session. The final submit can process the data from all the forms and delete it from the session (which may be automatic, not sure) before rendering a results page for the user.
There is limited capacity for skipping some forms based on the data in the previous ones.
The other approach is to go client-based. You use one huge form, but with Javascript of some sort to steer the user through it section by section. "Submit" on earlier parts does not involve the server, but just hides the sub-form and reveals the next (or switches between tabs, which the user may also do for himself). Methods can range from simple Jquery up to enormous Javascript frameworks.
I have a Django project that has a Students model with multiple fields, and I have implemented a ModelChoiceField form which drops down and allows for selecting a particular record in the Students table.
forms.py:
class StudentChoiceField(forms.Form):
students = forms.ModelChoiceField(
queryset=Student.objects.values_list().order_by("last_name"),
empty_label="(select student)",
widget=forms.Select(attrs={"onChange":'refresh()'})
)
def __init__(self, *args, **kwargs):
super(StudentChoiceField, self).__init__(*args, **kwargs)
# without the next line label_from_instance does NOT work
self.fields['students'].queryset = Student.objects.all().order_by("last_name")
self.fields['students'].label_from_instance = lambda obj: "%s %s" % (obj.last_name, obj.first_name)
The label_from_instance method is overridden, so that the drop-down form displays just two model fields (there are eleven total in the model).
When a student is selected, I want to update some textfields in the page to display the remaining fields of the model. Currently, have implemented a javascript function refresh() which is invoked for the onChange event of the StudentChoiceField form.
index.html (all_students_choice is the StudentChoiceField form):
{% extends "base.html" %}
{% block content %}
<body>
<script>
function refresh(){
var id = document.getElementById("id_students").value;
console.log(id);
}
</script>
<div class="container">
<form method=POST action="">
{% csrf_token %}
{{ all_students_choice }}
</form>
</div>
</body>
{% endblock %}
I have confirmed through the browser console that the javascript function is getting called, and printing the value of the ModelChoiceField form. As expected, after selecting an instance from the dropdown menu the value of the form element is the primary key of the table.
I need advice on the best approach to populate the textfields which I will be adding to display the remaining Student model fields (aside from first and last name). Should these be passed as parameters to the javascript function? Is there a best way to approach this problem.
Answering this question with the approach that that was eventually used, in case it would be of assistance to someone else. Decided to render the same template, but with additional element in the context to reference the selected student. In the initial index home page, the selected_student is None:
def index(request):
....
context = {
'students_choice_ln': students_choice_ln,
'students_choice_fn': students_choice_fn,
'selected_student': None
}
return render(request, 'awards/index.html', context)
For the select function, the selected_student is passed in through the context:
def select(request):
if request.method == "GET":
...
student_id = ...
selected_student = Student.objects.get(pk=student_id)
...
context = {
...
'students_choice_ln': students_choice_ln,
'students_choice_fn': students_choice_fn,
'selected_student': selected_student,
...
}
return render(request, 'awards/index.html', context)
The template can then check whether the selected_student variable is available or not, and then accordingly display the additional fields in a separate div.
If there are any experienced web developers / django developers who see problems with this structure, perhaps they can point them out.
I'm creating a website using Django, and using Ajax to prevent site reload after submitting a form. Right now, I have orders being displayed on the site with an x button beside each order. Clicking the x cancels the order on the database (a post request that changes a value rather than simply deleting it) and also reloads the div in which the orders are housed. I have other forms on this website that are working correctly (they do have fields, though and use crispyforms). The problem I'm facing is that the script isn't detecting that the form is submitted.
Here are the pertinent parts of my project:
views.py
class CancelForm(ModelForm):
class Meta:
model = Order
fields = ['Filled']
...
def cancelorder(request, pk):
form = CancelForm(request.POST)
if request.is_ajax and request.method == "POST":
order = Order.objects.get(pk=pk)
order.Filled = "C"
instance = order.save(update_fields=["Filled"])
return JsonResponse({"canceled": pk}, status=200)
return JsonResponse({"error": ""}, status=400)
urls.py
urlpatterns = [
path('', views.orderpage, name="order-index"),
path('cancel_order/<int:pk>/', views.cancelorder, name="cancel_order"),
path('post/ajax/order/', views.postorder, name = "post_order"),
path('yourorders/', views.yourorders, name="your_orders"),
path('allorders/', views.allorders, name="all_orders"),
]
orderpage.html (this is my main page, with the div that is to be reloaded on yourorders.html)
<div class="container-fluid ActiveOrderInfoDiv" id="YourOrdersDiv">
{% include 'order/yourorders.html' %}
</div>
yourorders.html
{% for order in all_orders %}
<div class="row">
...
<div class="col">{{ order.OrderID }}</div>
<form action="{% url 'order:cancel_order' pk=order.OrderID %}" id="cancel_button" method="POST">
{% csrf_token %}
<button type="submit" class="close" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</form>
</div>
{% endfor %}
Javascript (here, check 2 is never logged)
$(document).ready(function () {
$("#cancel_button").submit(function (e) {
console.log("check 2");
e.preventDefault();
console.log("check 3");
$.ajax({
url: "{% url 'order:your_orders' %}",
success: function (response) {
$("#YourOrdersDiv").load("/order/yourorders/");
},
error: function (response) {
}
});
});
});
What I've tried
Moved the script to yourorders.html (I thought maybe the JS wasn't seeing the cancel_button ID)
Used console.log to see where the flow stopped (it doesn't seem to pick up that the cancel button was submitted)
Added the CancelForm modelform (previously I was updating the DB without a modelform)
Generally poking around with Ajax syntax and order
Looking at other questions here on StackOverflow - I seem to be following them, and my syntax may just be right, it's just not picking up that the cancel_button form is being submitted
You should delegate the event handler to the document level so that when the form is reloaded the event is still handled. When you "reload" the form you are inserting a new element into the DOM that does not have the event handler attached to it
$(document).on("submit", "#cancel_button", function(e) {
...
I see that forms without buttons are very popular (like here). How to create a form that will be automatically submit for two different fields in Django, after the user selects the field (example 1) or type in the text and clicks something (it means completes typing) (example 2):
1.) ChoiceField
forms.py
class Search(forms.Form):
field = forms.ChoiceField(choices=MY_CHOICES)
views.py
if request.method == "GET":
form = Search(request.GET)
if form.is_valid():
print('it's work')
template.html
<form method="GET">
{% csrf_token %}
{{ form }}
</form>
2.) CharField
forms.py
class Search(forms.Form):
field = forms.CharField(max_length=10)
* other files like above
You may simply change forms.py:
class Search(forms.Form):
field = forms.ChoiceField(choices=MY_CHOICES,
widget=forms.Select(attrs={'onchange': 'submit();'}))
Nothing else to add, no jquery needed.
See also here.
You can use jquery in your template like this:
$('#search_field').change(function(){
$('#your_form').submit()
});
or when user click on something:
$('#something').click(function(){
$('#your_form').submit()
});