Passing table values from template to view - python

I have template with table which is dynamically created by javascript. Then I want retrieve with submit button only value within <td name="plu"></td> tags and process it in view to save as json into CharField in model. I tried to use form tag with method post and request.POST.get('plu') in view but it won't work. I want to get that values and then process it with model methods.
Here are parts of code:
#login_required()
def cash_register(request):
"""plus = [123,345,567]
newtrans = Transaction()
newtrans.set_plu_list(plus)
newtrans.save()"""
if request.method == 'POST':
x = request.POST.get('plu', False)
# ???
try:
products = Product.objects.all().values_list('plu_num', 'art_name', 'sales_price_brutto')
products_json = json.dumps(list(products), cls=DjangoJSONEncoder)
except Product.DoesNotExist:
raise Http404('Products cant\'t be found!')
return render(request, 'panel/cash_register.html', {'products_json': products_json})
class Transaction(models.Model):
plu_list = models.CharField(max_length=255)
transaction_date = models.DateField(auto_now_add=True)
is_ksk = models.BooleanField(default=False)
ksk_num = models.IntegerField(null=True)
def set_plu_list(self, x):
self.plu_list = json.dumps(x)
def get_plu_list(self):
return json.loads(self.plu_list)
And html: https://pastebin.com/RFn5qNn2

This isn't a thing you can do. <td> elements are not form fields; you can't "submit" them.
If you want values to be submitted to the backend, you either have to use actual form inputs, or use Ajax to send the data.

Related

Python, Django, HTMX, is it possible to save data, when a user clicks <button>

When a user click <button> on index page, can save data immediately?
views.py
def index(request):
...
...
context = { ... }
response = render(request, 'docu/index.html', context)
### Save visitors' IP and Keywords to KeyLOG table ###
ip = request.META.get('REMOTE_ADDR')
keywords = request.META.get('HTTP_REFERER', '')
keylog = KeylogForm(request.GET)
keylog = keylog.save(commit=False)
keylog.ipaddr = ip
keylog.keyquery = keywords
keylog.svae()
return response
def keylog(request):
if request.method == "GET":
keylog_list = list(Keylog.objects.all().order_by()\
.values('idpaddr', 'keywords', 'tel_log', 'regtime'))
return JsonResponse(keylog_list, safe=False)
return JsonResponse({'message':'error'})
forms.py
class KeylogForm(forms.ModelForm):
class Meta:
model = Keylog
fields = ['ipaddr','keyquery','tel_log']
models.py
class Keylog(models.Model):
ipaddr = models.CharField(max_length=32,null=True, blank=True) #save IP addr
keyquery = models.CharField(max_length=128,null=True, blank=True) #save keywords
tel_log = models.CharField(max_length=256,null=True, blank=True) #save tel_log
regtime = models.DateTimeField(auto_now_add=True) #created time
Currently, it makes table as below;
Ipaddr
keyquery
tel_log
regtime
192.168.x.yy
?query=apple
2023.01.01.12.24.56
192.168.a.bb
?query=banana
2023.01.01.11.22.33
I hope to save Tel_log data in the above table, when a user clicks <butto>...</button>.
So I made an index.html as below;
index.html
<div id="tel_log">
<button class="btn btn-danger">
hx-get="keylog/"
hx-vals="[tel_log='CALL']"
hx-trigger="click">
Phone NUMBER
</button>
</div>
My expectation is that when I clicked [Phone NUMBER] on the index page, "CALL" is appeared on the "tel_log" column of the above table, but it didn't work, just shows {message:error}
I'm a newbie on programming, so my approach for my needs may be wrong, but I'm really eager to make a web site for now, especially on this question. I also did try to use Ajax, but I didn't get any response also.
Thank you for all.
Click [button], save data in real time on the column of the table.

Django - Populating Edit/Update Form With an Object's Preexisting Data

I have an edit/update values form in Django, in which you need to choose the object you want to change its details from a drop down menu and then enter the new information you wanted to edit/update.
When you choose an object from the dropdown menu the form looks like this:
I am trying to populate the edit form with the pre existing fields of the object that I chose from the dropdown menu to make it easier to make changes.
it should look like this screenshot:
Any ideas how I can achieve that?
Views.py Code:
def tasks(request):
if request.user.is_superuser:
context = {
'tasks':Task.objects.all(),
'title': 'Tasks',
'addForm':AddNewTask(prefix = 'add'),
'editForm':EditTask(prefix = 'edit'),
}
else:
context = {
'tasks':Task.objects.filter(created_by=request.user),
'title': 'Tasks',
'addForm':AddNewTask(prefix = 'add'),
'editForm':EditTask(prefix = 'edit'),
}
if request.method =='POST':
if 'addNew'in request.POST:
addForm = AddNewTask(request.POST,prefix = 'add')
if addForm.is_valid():
task = addForm.save(commit=False)
task.created_by = request.user
task.save()
messages.success(request, f' Task Created Successfully ')
else:
messages.warning(request, 'Something Went Wrong !')
elif 'editExisting' in request.POST:
editForm = EditTask(request.POST,prefix = 'edit')
if editForm.is_valid():
taskID = editForm.cleaned_data['existing_task'].id
new_title = editForm.cleaned_data['title']
new_desc = editForm.cleaned_data['description']
new_status = editForm.cleaned_data['status']
object = Task.objects.get(id=taskID)
object.title = new_title
object.description = new_desc
object.status = new_status
object.save()
messages.success(request, f'Task #{taskID} Has Been Edited Successfully!')
else:
messages.warning(request, 'Something Went Wrong !')
return render(request,'ticketing/tasks.html',context)
forms.py Code:
class EditTask(forms.Form):
existing_task = forms.ModelChoiceField(Task.objects.order_by('id'),label= 'Existing Task')
title = forms.CharField(max_length=100,required=True,label ='Title')
description = forms.CharField(widget=forms.Textarea,label='Description')
status = forms.ChoiceField(choices=Status,label='Change Status')
models.py Code:
class Task(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=100)
description = models.TextField()
last_modified = models.DateTimeField(auto_now=True)
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(User,on_delete=models.PROTECT)
status = models.CharField(choices=Status,max_length=2,default='O')
def __str__(self):
return str(self.title)
Here's the issue.
You load the page and render the form. Then you choose an object representing a row of data with which to populate the form. At this point the form is already rendered.
You have two options:
Restructure your workflow so that the choice field and the edit form are on separate page loads. You load the dropdown field, choose an object, and submit the form, which then re-renders the form (200 on POST or redirect) with the data populated.
Handle the data through JavaScript on the client side. You will need to watch the dropdown field and then populate the form with data through JavaScript.
A. You can either pass ALL of the data for all of the choices to the JavaScript on the initial page load, which could be a lot of data for a large table, or...
B. You can retrieve the data through an API when the dropdown is changed.
I would favour the first option. Present the user with the dropdown and a next button (/edit/). Use that form data to redirect to a page with the edit form and a save button (/edit/<id>/). Use that form data to update the object and redirect back to the dropdown page (/edit/).

Why does my Submit button renders a page that is blank when it is supposed to contain the data that was just updated?

I'm trying to update the values of my database using a HTML Form.
When I Click Edit it brings me to the edit the values above.
However as I am clicking the submit button, it returns me a database but with no other values.
Is there anyone that can help me understand what I did wrong and point me to the right documentation (if any)
editclaims.html:
<div class="arrange2">
<h1>Edit Claim Form - #{{claims.id}} </h1>
</div>
<form method="POST" action="/update/{{claims.id}}">
{% csrf_token %}
views.py:
def editclaims(request,id):
context = initialize_context(request)
user = context['user']
claims = SaveClaimForm.objects.get(id=id)
if request.method == 'POST':
name = request.POST['name']
email = request.POST['email']
claim = request.POST['claim']
claimtype = request.POST.get('claimtype')
description = request.POST['description']
receipt = request.FILES['receipt']
cheque = request.POST.get('Cheque')
form = SaveClaimForm(name=name, email=email, claim=claim, claimtype=claimtype, description=description, receipt=receipt, cheque=cheque)
form.save()
return render(request, "Login/editclaims.html", {'claims':claims, 'user':user})
urls.py:
urlpatterns = [
path('existingclaims/', views.viewclaims, name='existingclaims'),
path('editclaims/<int:id>', views.editclaims, name='editclaims'),
path('update/<int:id>', views.updateclaims, name='updateclaims'),
]
It may not resolve all your problems but it will be more readable as answer.
When you get data from HTML then you create new object SaveClaimForm and it will have new ID and you will have the same object in two rows.
You have to get original Claim from database and update values in this object and save it - and then it will save it with original ID and you will have only one `object in database
def editclaims(request,id):
context = initialize_context(request)
user = context['user']
# get original object
claims = SaveClaimForm.objects.get(id=id)
if request.method == 'POST':
# update original object
claims.name = request.POST['name']
claims.email = request.POST['email']
claims.claim = request.POST['claim']
claims.claimtype = request.POST.get('claimtype')
claims.description = request.POST['description']
claims.receipt = request.FILES['receipt']
claims.cheque = request.POST.get('Cheque')
# save it with original `ID`
claims.save()
return render(request, "Login/editclaims.html", {'claims':claims, 'user':user})
BTW:
Django has special class ModelForm to create forms in HTML. It may also have methods to check if data in HTML are correct - ie. if fields are not empty, if email is correctly constructed (name#domain.com), if phone has only numbers, etc. So using ModelForm can be more useful then writing all manually in code.

Django form field update

I have a Django form that lets users choose a tag from multiple tag options. The problem I am facing is that even when the tag list gets updated, the model form does not get the updated tag list from database. As a result, new tags do not appear in options.
Here is my code in forms.py:
class EnglishTagForm(forms.Form):
tag_choices = [(x.tagName, x.tagName.upper()) for x in ClassTag.objects.filter(
agentId=Agent.objects.get(name='English Chowdhury'))]
tag = forms.CharField(widget=forms.Select(choices=tag_choices,
attrs={'class':'form-control'}))
def __init__(self, *args, **kwargs):
super(EnglishTagForm, self).__init__(*args, **kwargs)
self.fields['tag'].choices = [(x.tagName,
x.tagName.upper()) for x in ClassTag.objects.filter(
agentId=Agent.objects.get(name='English Chowdhury'))]
This form is being instantiated in view. My question is what changes should I do so that tag_choices gets updated from database on every instantiation.
How the above form is used in views.py:
```
def complaintDetail(request, complaint_id):
complaint = Complaints.objects.filter(pk=complaint_id).first()
context = {}
if request.method == 'POST':
agent = Agent.objects.get(name="English Chowdhury")
if "SubmitTag" in request.POST:
englishForm = EnglishTagForm(request.POST)
if englishForm.is_valid:
// Complaint Delete Logic
return redirect('chatbot:modComplaints')
else:
englishForm = EnglishTagForm()
context['eForm'] = englishForm
elif "SubmitBundle" in request.POST:
newTagForm = NewTagForm(request.POST)
if newTagForm.is_valid():
// Complaint Delete Logic
complaint.delete()
return redirect('chatbot:modComplaints')
else:
newTagForm = NewTagForm()
context['newForm'] = newTagForm
else:
englishForm = EnglishTagForm()
context['eForm'] = englishForm
newTagForm = NewTagForm()
context['newForm'] = newTagForm
context['complaint'] = complaint
return render(request, 'chatbot/complaintDetail.html', context)
```
Edit: (For future reference)
I decided to modify the tag attribute and convert CharField to ModelChoiceField, which seems to fix the issue.
Updated Class:
class EnglishTagForm(forms.Form):
tag = forms.ModelChoiceField(queryset=ClassTag.objects.filter(
agentId=Agent.objects.get(name='English Chowdhury')),
empty_label=None, widget=forms.Select(
attrs={'class':'form-control'}))
Please remove the list comprehension from Line 2. So that,
tag_choices = [(x.tagName, x.tagName.upper()) for x in ClassTag.objects.filter(
agentId=Agent.objects.get(name='English Chowdhury'))]
becomes
tag_choices = []

Filtering data with __range

I'm using django_tables2 thus part of the code is dependent on this package, but this should be irrelevant to the overall problem.
forms.py
class PersonForm(forms.Form):
date_from = forms.DateField(input_formats='%d/%m/%Y')
date_to = forms.DateField(input_formats='%d/%m/%Y')
views.py
def filter(request):
table = PersonTable(Person.objects.all())
if request.method == 'POST':
form = PersonForm(request.POST)
if form.is_valid():
date_from = form.cleaned_data['date_from']
date_to = form.cleaned_data['date_to']
result_filtered = table.filter(date__range=(date_from, date_to))
RequestConfig(request, paginate={"per_page": 100}).configure(table)
return render(request, "people.html", {
"table": result_filtered })
args = {}
args.update(csrf(request))
args['form'] = PersonForm()
args['table'] = table
RequestConfig(request, paginate={"per_page": 100}).configure(table)
return render(request, 'people.html', args)
Simply, filtering is not working. I can see the entire table, but when I try to filter nothing happens. Can you see what's wrong?
I'm pretty sure you need to call .filter() on the query set rather than the table. For example:
result_filtered = PersonTable(Person.objects.filter(date__range=(date_from, date_to))
Also, on this line:
RequestConfig(request, paginate={"per_page": 100}).configure(table)
You are passing in table. You should pass in result_filtered instead.
This is one way I'd do it, assuming your Person model has a date field:
def filter(request):
if 'date_from' in request.GET and 'date_to' in request.GET:
# form data has been submitted
form = PersonForm(request.GET)
if form.is_valid():
date_from = form.cleaned_data['date_from']
date_to = form.cleaned_data['date_to']
people = Person.objects.filter(date__range=(date_from, date_to))
table = PersonTable(people)
else:
table = PersonTable(Person.objects.all())
else:
form = PersonForm()
table = PersonTable(Person.objects.all())
RequestConfig(request, paginate={"per_page": 100}).configure(table)
args = {}
args.update(csrf(request))
args['form'] = form
args['table'] = table
return render(request, 'people.html', args)
This binds the form if both its expected fields are present, and limits the queryset according to the results if valid. If not valid, it renders the bound form and the table built from the unlimited table. If form data was not submitted, it renders the table built from the unlimited table.
Your form tag's method attribute should be GET rather than POST, if using this design.
This doesn't quite follow the usual Django patterns for form handling because the form isn't actually making any changes, so you can use GET and don't need to return a redirect on success.

Categories

Resources