Django smart selects doesn't work with JS cloning - javascript

I'm trying to create a page with ability to add any amount of form-copy.
I use django-smart-selects to make my form's field chained. It works fine if I have only 1 form on page.
Then I'm using javascript to make a function to clone form instance by pressing button and addind new form's ids to these clones.
The problem is when I press "+" button I get new cloned form on page, but chained-selection doesn't work anymore(only first one still works), and it seems that this clone copying all my choices from the firs form and remembering this state.
I see in terminal this response every time I choose any selection in chained fields:
[31/Oct/2022 16:42:27] "GET /chaining/filter/cash_table/LevelOne/flowtype/cash_table/CashFlowPattern/level_one/1/ HTTP/1.1" 200 115
[31/Oct/2022 16:42:29] "GET /chaining/filter/cash_table/LevelOne/flowtype/cash_table/CashFlowPattern/level_one/2/ HTTP/1.1" 200 105
But in cloned forms it doesn't happen.
My Formset is:
forms.py
from django import forms
from .models import CashFlowPattern
from django.forms import modelformset_factory
class CashFlowForm(forms.ModelForm):
class Meta:
model = CashFlowPattern
fields = '__all__'
CashFowFormSet = modelformset_factory(
CashFlowPattern,
fields=(
'flow_type',
'level_one',
'level_two',
'eom',
'amount',
'comment'
),
extra=1
)
views.py
class FormAddView(TemplateView):
template_name = 'cash_table/index.html'
def get(self, *args, **kwargs):
formset = CashFowFormSet(queryset=CashFlowPattern.objects.none())
return self.render_to_response({'formset': formset})
def post(self, *args, **kwargs):
end_of_month = (datetime.datetime.now() + relativedelta(day=31)).strftime('%Y-%m-%d')
formset = CashFowFormSet(data=self.request.POST)
if formset.is_valid():
forms = formset.save(commit=False)
for form in forms:
form.eom = end_of_month
form.user = self.request.user
form.save()
# return redirect(reverse_lazy("bird_list"))
return self.render_to_response({'formset': formset})
template:
<form id="form-container" method="POST">
{% csrf_token %}
{{ formset.management_form }}
<div class="empty-form">
{% for form in formset %}
{{ form.media.js }}
<p>{{ form }}</p>
{% endfor %}
</div>
<button id="add-form" type="button">+</button>
<button type="submit" class="btn btn-primary">Отправить</button>
</form>
<script>
let emptyForm = document.querySelectorAll(".empty-form")
let container = document.querySelector("#form-container")
let addButton = document.querySelector("#add-form")
let totalForms = document.querySelector("#id_form-TOTAL_FORMS")
let formNum = emptyForm.length-1
addButton.addEventListener('click', addForm)
function addForm(e) {
e.preventDefault()
let newForm = emptyForm[0].cloneNode(true) //Clone the form
let formRegex = RegExp(`form-(\\d){1}-`,'g') //Regex to find all instances of the form number
formNum++ //Increment the form number
newForm.innerHTML = newForm.innerHTML.replace(formRegex, `form-${formNum}-`) //Update the new form to have the correct form number
container.insertBefore(newForm, addButton) //Insert the new form at the end of the list of forms
totalForms.setAttribute('value', `${formNum+1}`) //Increment the number of total forms in the management form
}
</script>

Related

I have a problem in submitting comments to server using json and fetch in django

I am working on a bookstore project using django and javascript. I want to allow user to add comments on each book and send the comment without reloading the page using JSON
html:
<h3 id="authorname">{{book.authorname}}</h3>
<h1 id="bookname"> {{book.name}}</h1>
<p id="slogan">-{{book.slogan}}-</p>
<h2 id="price">Price:- <span>${{book.price}}</span></h2>
<form id="addcomment">
{% csrf_token %}
<input hidden name='thecommentuser' value="{{ request.user.id }}" id="commentsubmitter">
<input hidden name='thecommentbook' value="{{ book.id }}" id="commentbook">
<textarea name='thecomment'id="comment"></textarea>
<input type="submit">
</form>
script:
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('#addcomment').onsubmit = function() {
fetch('/comments', {
method: 'POST',
body: JSON.stringify({
thecomment: document.querySelector('#comment').value,
thecommentuser: document.querySelector('#commentsubmitter').value,
thecommentbook: document.querySelector('#commentbook').value,
})})}});
models.py:
class books(models.Model):
bookuser= models.ForeignKey('User', on_delete=models.CASCADE, default= None, blank=True)
name = models.CharField(max_length=80)
slogan = models.CharField(max_length=200, null=True,
price = models.IntegerField()
authorname= models.CharField(max_length=30)
class comments(models.Model):
comment = models.CharField(max_length= 100)
commentuser = models.ForeignKey('User', on_delete=models.CASCADE, default=None)
commentbook = models.ForeignKey('books', on_delete=models.CASCADE, default=None)
def serialize(self):
return {
'thecomment': self.comment,
'thecommentuser': self.commentuser,
'thecommentbook': self.commentbook
}
urls.py:
urlpatterns = [
path('book/<int:id>', views.book, name='book'),
path('comments', views.addcomments, name='comments')
]
views.py:
from django.views.decorators.csrf import csrf_exempt
from .models import *
from django.contrib.auth.decorators import login_required
import json
def book(request, id):
submitedbook = books.objects.get(id=id)
bkchapters = chapters.objects.filter(chapterbook=submitedbook)
bkrewards = rewards.objects.filter(rewardbook = submitedbook)
return render(request, 'network/book.html', {'book':submitedbook, 'chapters':bkchapters, 'rewards':bkrewards})
#csrf_exempt
#login_required
def addcomments(request):
if request.method == 'POST':
print('posted')
data= json.loads(request.body)
comment = data.get('thecomment', '')
commentuser = data.get('thecommentuser')
commentbook = data.get('thecommentbook', '')
cuser = User.objects.get(id = commentuser)
cbook = books.objects.get(id = commentbook)
thecommentt = comments(
thecomment=comment,
thecommentuser=cuser,
thecommentbook=cbook
)
thecommentt.save()
when I open the comments in the admin page I don't find any submitted data and the page reload upon submitting a comment. the order of print('posted') in views.py isn't displayed to me upon adding a comment and that means that the request isn't sent but I don't know why
this appears to me in the terminal window upon adding the comment:
[30/Oct/2022 01:47:19] "GET /book/1?csrfmiddlewaretoken=9QgGiDOUnVxMlxZQ6UkSmiO4auq5BLojV6iWW55qE9LER929Qj7WB8LVtkBfpnJ4&thecommentuser=1&thecommentbook=1&thecomment=Book HTTP/1.1" 200 14927
I tried to delete if request.method == 'POST': in views and to print in views but nothing changed. Also I tried to console.log('submitted') on submitting the comment but nothing appeared
new update:
I find that the error comes from the browser itself as I find that data is sent upon submitting from another browser so although the two browsers are updated. so how could I solve this?

How to prefill django form Dynamically

I am trying to display a form in django and pre-filling it dynamically.
I want the user of my sample news gathering site to modify an entry.
I have my Manual Input form class
#forms.py
class ManualInputForm(forms.Form):
source = forms.CharField(label="Source:", widget = forms.TextInput(attrs={'size': 97}))
topic = forms.CharField(label="Topic:", widget = forms.TextInput(attrs={'size': 97}))
news = forms.CharField(widget = forms.Textarea(attrs={"rows":5, "cols":100}))
link = forms.CharField(label="Link (optional):", required = False, widget = forms.TextInput(attrs={'size': 97}))
In the HTML I am going manually because I would like to pre-fill all fields with data coming in from the related function in views.py.
#html file
<form method="post" class="form-group">
{% csrf_token %}
<div class="input-group mb-3">
<div class="container">
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }}
<br>
{{ field }}
</div>
{% endfor %}
</div>
<div class="input-group">
<p> </p>
<button type="submit" class="btn btn-success" name="Submit">Save</button>
</div>
</div>
</form>
How do I do it? It's driving me crazy o.O
I would like to keep using django's forms because of its integrated error manager (not all fields are required but some are and I'd like for django to keep managing it).
Thank your for your suggestions!
EDIT:
as requested I'll post the views.py related function:
#views.py
def editnews(response, id):
form = ManualInputForm(response.POST or None)
#tableToView is a dataframe retrieved by querying an external DB
#data cannot be stored in django's buit in because of reasons ;-)
#checking the dataframe is correct and it is:
#IT IS MADE OF A SINGLE LINE
print(tableToView)
#THIS IS PROBABLY NOT THE WAY TO DO IT
form.source = tableToView.loc[0, 'Source']
form.topic = tableToView.loc[0, 'Topic']
form.news = tableToView.loc[0, 'News']
form.link = tableToView.loc[0, 'Link']
return render(response, 'manual/editnews.html', {"form":form})
In the image the text should be pre-filled.
Try something like that:
def editnews(response, id):
data = {k.lower(): v for k, v in tableToView.loc[0].to_dict().items()}
form = ManualInputForm(response.POST or None, initial=data)
return render(response, 'manual/editnews.html', {'form': form})
when you are declaring or rendering form in view and sending it to template. use initial argument and pass dictionary in it with key as name of field and value as the text which you want prefilled.
like this
context['form'] = NameofForm(initial={'Source':'mysite', 'Topic':'mytopic'})
return context
Update
> def test_view(request, pk):
> template_name = 'form.html'
> form = MyForm(initial={"test":"initialize with this value"})
> if request.method == 'POST':
> form = MyForm(request.POST)
> if form.is_valid():
> form.save()
> return HttpResponseRedirect(reverse('list-view'))
>
> return render(request, template_name, {'form': form})
Try this:
#views.py
def editnews(response, id):
data = {}
data["source"] = tableToView.loc[0, 'Source']
data["topic"] = tableToView.loc[0, 'Topic']
data["news"] = tableToView.loc[0, 'News']
data["link"] = tableToView.loc[0, 'Link']
form = ManualInputForm(response.POST or None, initial=data)
return render(response, 'manual/editnews.html', {"form":form})
You could do it with jQuery if you're using one. You'll need to set the attribute of id to the form field.
jQuery code example:
$('#topic').val("Prefilled text goes here");

Pop up message in Django

I have a form in Django where I upload many files and then perform some data processing on those files. I want to display a loader message while it's still processing in the backend.
I know we can use messages in django but it only shows after the processing is complete, I want to display a little animation while data is being processed. I didn't use ajax to post the form since it was easier with the simple method.
Is there any other way to achieve this?
Forms.py
class UploadFileForm(forms.Form):
file_A = forms.FileField(label= "Upload File-A ")
file_B = forms.FileField(label= "Upload File-B ")
year = forms.IntegerField()
Views.py
def display_uploadpage(request):
if request.method == 'POST':
form = BudgetForm(request.POST, request.FILES)
if form.is_valid():
file_A = form.cleaned_data["file_A"]
file_B = form.cleaned_data["file_B"]
year = form.cleaned_data["year"]
fs = FileSystemStorage()
file_A_name = fs.save(file_A.name, file_A)
file_B_name = fs.save(file_B.name, file_B)
p = ProcessData(year, file_A,file_A_name, file_B, file_B_name)
msg = p.process()
messages.info(request, msg )
return render(request, 'website/upload.html')
else:
form = UploadFileForm()
context = {'form': form}
return render(request, 'website/upload.html', context)
upload.html
<form method="post" enctype="multipart/form-data"> <!-- form method -->
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-danger" id="upload">Upload</button>
</form>
I wanted to add this animation in the page while it's still processing.

Error while sending JavaScript generated image to Django ModelForm

I’m trying to use https://github.com/szimek/signature_pad to attach a signature to a form and send it to the server. I’ve been able to successfully upload images with a standard ImageField, and have also used szimek/signature_pad to download the signature. But when I try to get the signature to the server, I get "(Hidden field signature) No file was submitted. Check the encoding type on the form." So I think I’m at least successfully sending an image to the field, but am not sure how to encode it.
HTML
<form id="form" action="{% url ‘my_app:testFormPage' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<div id="signature-pad">
<canvas></canvas><br>
</div>
 <input type="hidden" name="signature" value=“signatureImage”>
<button type="submit" data-action="formSig">Submit</button>
</form>

Python
# Models.py
class testModel(models.Model):
name = models.CharField(max_length=50)
date = models.DateTimeField(default=timezone.now)
signature = models.ImageField (null=True, max_length=3000)
# Forms.py
class testForm(forms.ModelForm):
class Meta:
model = testModel
fields = ‘__all__’
widgets = { 'signature': forms.HiddenInput(),}
# Views.py
def testFormPage(request):
if request.method == 'POST':
form = testForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect('/thanks/')
else:
form = testForm()
context = {'form': form}
return render(request, 'client_visits/testFormPage.html', context)
Javascript

The full javascript app can be found at https://github.com/szimek/signature_pad/tree/master/docs/js. Here’s just what I added
var formSig = wrapper.querySelector("[data-action=formSig]");
formSig.addEventListener("submit", function (event) {
var signatureImage = signaturePad.toDataURL();
});

Possible to incorporate select tag in django form?

I have a django form being rendered on an html page, and I have a select dropdown menu which performs a filtering function. I was wondering if it was possible to incorporate this select tag as part of my form? I'd like the select tag to be part of routestep_form.
<center>
<form class ="subtitle" method = 'POST' action="{% url 'buildpage:partrequestinfo' %}" enctype="multipart/form-data">{% csrf_token %}
{{routestep_form.as_p}}
<select name = "myselect" id="id_step" onchange="getOptions(this.value)">
<option value="-----">-----</option>
{% for step in steps %}
<option value="{{ step }}">{{ step }}</option>
{% endfor %}
</select>
<br/><br/>
<select id="id_step_option">
<option value="-----">-----</option>
</select>
<input type='submit' value='Next'/>
</form>
</center>
My Form:
class RouteStepForm(forms.ModelForm):
class Meta:
model = RouteStep
fields = '__all__'
widgets = {
'step': Select,
'step_option': Select,
}
error_messages = {
NON_FIELD_ERRORS: {
'unique_together': "%(RouteStep)s %(description)s are not unique.",
}
}
Views: The other forms are forms I had on the same page, my main focus though is on RouteStepForm.
def partrequestinfo(request):
steps = Step.objects.all()
if not request.user.is_staff or not request.user.is_superuser:
raise Http404
req_form = PartRequestForm(request.POST or None, request.FILES or None)
step_form = StepForm(request.POST or None, request.FILES or None)
stepoption_form = StepOptionForm(request.POST or None, request.FILES or None)
routestep_form = RouteStepForm(request.POST or None, request.FILES or None)
if req_form.is_valid() and step_form.is_valid() and stepoption_form.is_valid() and routestep_form.is_valid():
instance = req_form.save(commit=False)
instance.user = request.user
instance.save()
step = step_form.save(commit=False)
step.save()
stepoption = stepoption_form.save(commit=False)
stepoption.save()
routestep = routestep_form.save(commit=False)
routestep.save()
messages.success(request, "Successfully Created")
return HttpResponseRedirect(instance.get_absolute_url())
else:
context = {
"req_form": req_form,
"step_form": step_form,
"stepoption_form": stepoption_form,
"routestep_form": routestep_form,
"steps": steps,
}
return render(request, "buildpage/partrequestinfo.html", context)
Models:
class Step(models.Model):
name = models.CharField(_('Step Name'), max_length=100, default='')
def __unicode__ (self):
return self.name
class StepOption(models.Model):
step = models.ForeignKey(Step, related_name = 'Step', null = True)
name = models.CharField(_('Step Option'), max_length=100, default='')
def __unicode__ (self):
return self.name + " - " + self.step.name
class RouteStep(models.Model):
step_number = models.PositiveIntegerField(_('Step Number'), default = 0)
step = models.ForeignKey(Step, related_name = 'Step+', null = True)
step_option = models.ForeignKey(StepOption, related_name = 'StepOption', null=True)
def __unicode__ (self):
return self.step_option
Try:
class RouteStepForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(forms.ModelForm, self).__init__(*args, **kwargs)
self.fields['step'].widget.choices=[ query.name for query in Step.objects.all()])
If it does not work, please post your template code that show up.
EDIT
I edit my answer, and also find this helpful.Why do I get an object is not iterable error? and this Getting object not iterable error in django form.
Another solution will be Can not iterate a ChoiceField with Select as widget

Categories

Resources