Adding two numbers and show the output on the same page - django

I am new to Django, I am not sure if I could do action and show result on the same page.
For this page I want to add two numbers that are entered on textarea a1 and a2 together, and output it on textarea a3.
Now, the error is showing Page not found (404), I guess it is something to do with my routing.
And if I am doing dynamic content like this, should I use VueJS or react instead?
Here is my view:
def add(request):
"""The Cipher and Decipher page"""
res = 0
val1 = int(request.GET.get('a1', 0))
val2 = int(request.GET.get('a2', 0))
res = val1 + val2
return render(request, 'morse_logs/add.html', {'result': res})
my html (add.html):
{% block content %}
<h1>Addition</h1>
<form action="add">
<textarea rows="10" cols="50" name='a1' ></textarea>
<textarea rows="10" cols="50" name='a2' ></textarea>
<button type="submit" name="add">Calculate</button>
<textarea rows="10" cols="50" name="a3" >{{result}} </textarea>
</form>
{% endblock content %}
my url.py:
app_name = 'morse_logs'
urlpatterns = [
# Home Page
path('', views.index, name='index'),
# Page that shows all topics
path('topics/', views.topics, name='topics'),
# Page that do addition
path('add/', views.add, name='add'),
]

You specify in form's action attribute url where form should be send. You have add here which is not valid url. Instead you can just put "" here to show that form shoul be send to the current url:
{% block content %}
<h1>Addition</h1>
<form action="" method="get">
<textarea rows="10" cols="50" name='a1' ></textarea>
<textarea rows="10" cols="50" name='a2' ></textarea>
<button type="submit" name="add">Calculate</button>
<textarea rows="10" cols="50" name="a3" >{{result}} </textarea>
</form>
{% endblock content %}

Related

how to make sure a certain django url path is only checked if all the other paths have been checked

I am building an app where users can access their archives through a simple slug, as follows:
lekha.cc/<archive_slug>
This is exactly as instagram does it. However, whenever I go to any other page, such as
lekha.cc/dashboard
The code for the archive view runs, saying that it has not found an archive with that slug. This is an issue for 2 reasons: we dont want any excess code to run, and if a user chooses to name their archive 'dashboard', the entire website would potentially break down since no one would be able to access their dashboard.
My urls.py folder is as follows:
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('main.urls'), name='index'),
path('onboarding/', account_views.onboarding, name='onboarding'),
path('register/', account_views.register, name='register'),
path('login/', auth_view.LoginView.as_view(authentication_form=LoginForm, template_name='accounts/login.html'), name="login"),
path('logout/', account_views.logout_view, name='logout'),
path('dashboard/', archival_views.dashboard, name='dashboard'),
path('account_settings/', account_views.account_settings, name='account_settings'),
path('<str:slug>/', main_views.archive, name='archive'),
path('item/<str:slug>/', main_views.work, name='work'),
]
Does anyone have any solutions to this issue?
EDIT:
Here is the code for the dashboard view
def dashboard(request):
user = get_current_user()
archive = Archive.objects.get(creator=user)
filesystem = Folder.objects.get(archive=archive)
if request.method == "POST":
if 'addCategory' in request.POST:
category_name = request.POST['folderName']
filesystem = Folder.objects.get(pk=filesystem.pk)
filesystem.add_child(name=category_name)
return render(request, "archival/dashboard.html", {'filesystem': filesystem, "archve": archive, "fileSystemParse": filesystem.get_annotated_list()})
And the archive view
def archive(request, slug):
# retrieve archive with the corresponding slug requested (lekha.cc/dhruva will return the archive with slug='dhruva')
archive = Archive.objects.get(archive_slug=slug)
filesystem = Folder.objects.get(archive=archive)
return render(request, 'archive.html', {'archive': archive, 'filesystem': filesystem})
And the dashboard template:
<html lang="en">
<head>
<style>
</style>
</head>
</html>
{% extends 'navbar.html' %}
{% block content %}
{% load static %}
<div style="height: 200px; width: 100%;"></div>
<p>
archive: {{ archive.archive_slug }}, filesystem: {{ filesystem.name }}
</p>
<div id="folder_view">
{% include 'partials/folder_view.html' %}
</div>
<input type="button" value="addFolder">
<input type="button" value="addFile">
<form action="/dashboard/" method="post">
{% csrf_token %}
<input type="text" name="folderName">
<input type="submit" value="Add Category" name="addCategory">
</form>
<!-- Popups -->
<div id="new_folder_popup" class="dashboard-popup">
<div class="dashboard-popup-content">
<span class="close">×</span>
<!-- <form action="/dashboard/" method="post">
{% csrf_token %}
<input type="text" name="folderName">
<input type="submit" value="Add Category" name="addCategory">
</form> -->
</div>
</div>
The issue was caused by the browser requesting /favicon.ico/ which django was passing through my view. The url.py file should in theory look through all the URLs in order until it finds the right view, so by default django already checks URLs only once.
The real issue is described further here

Why is Django product editing not working. Reverse for 'edit' not found?

I'm trying to edit a product (without using forms.py) but I get an error Reverse for 'edit' not found. 'edit' is not a valid view function or pattern name.
vievs.py
def edit(request, id):
if (request.method == 'POST'):
obj, update = Posts.objects.update_or_create(title=request.POST.get("title"))
obj.text=request.POST.get("text")
obj.date=request.POST.get("date")
obj.image=request.POST.get("image")
obj.save()
return render(request, 'edit.html')
html
<form action="{% url "blog:edit" %}" method="post">
{% for el in posts %}
{% csrf_token %}
<input type="text" placeholder="Название" name="title" value="{{ el.title }}"><br>
<textarea placeholder="Текст статьи" rows="8" cols="80" name="text"></textarea><br>
<input type="file" name="image"><br>
<button type="submit">Добавить статью</button>
{% endfor %}
</form>
You need to define the view in your blog app's urls.py file. Something like this:
urlpatterns = [
# ... other patterns
path('<int:id>/edit/',views.edit,name='edit'),
]

How to call a django function on click that doesn't involve changing page [duplicate]

My application currently flows through 3 pages:
User selects question in index page
User submits answer in answer page
User is presented with result in results page.
I want to compress that down to a single page where the user submits an answer to the question and result is shown on the same page.
The following django-template code separates questions with Bootstrap accordion. How do I post the form without refreshing the whole page? I want to be able to display the result on the page, update CSS styling with Javascript etc.
<h2>{{ category.title }}</h2>
<div class="accordion" id="accordion{{category.title}}">
{% for challenge in category.challenge_set.all %}
<div class="card">
<div class="card-header" id="heading{{challenge.id}}">
<h2 class="mb-0">
<button class="btn btn-link btn-block text-left" type="button" data-toggle="collapse" data-target="#collapse{{challenge.id}}" aria-expanded="true" aria-controls="collapse{{challenge.id}}">
{{ challenge.question_text }} - {{ challenge.point_value }} points
</button>
</h2>
</div>
<div id="collapse{{challenge.id}}" class="collapse in" aria-labelledby="heading{{challenge.id}}" data-parent="#accordion{{category.title}}">
<div class="card-body">
<p>{{ challenge.description }}</p>
<form action="{% url 'challenges:answer' challenge.id %}" method="post">
{% if challenge|is_answered:request %}
<label for="answered">Answer</label>
<input type="text" name="answered" id="answered" value="{{ challenge.answer_text }}" readonly>
{% else %}
{% csrf_token %}
<label for="answer">Answer</label>
<input type="text" name="answer" id="answer">
<input type="submit" value="Submit">
{% endif %}
</form>
</div>
</div>
{% endfor %}
</div>
Here is the view:
def index(request):
context = {'challenges_by_category_list': Category.objects.all()}
return render(request, 'challenges/index.html', context)
def detail(request, challenge_id):
challenge = get_object_or_404(Challenge, pk=challenge_id)
return render(request, 'challenges/detail.html', {'challenge': challenge})
def results(request, challenge_id, result):
challenge = get_object_or_404(Challenge, pk=challenge_id)
return render(request, 'challenges/results.html', {'challenge':challenge, 'result':result})
def answer(request, challenge_id):
challenge = get_object_or_404(Challenge, pk=challenge_id)
result = "Incorrect, try again!"
if challenge.answer_text.lower() == request.POST['answer'].lower():
current_user = request.user
session = User_Challenge(user=current_user, challenge=challenge, answered=True)
session.save()
points = Profile(user=current_user, points=challenge.point_value)
points.save()
result = "Correct!"
return HttpResponseRedirect(reverse('challenges:results', args=(challenge.id, result)))
You can try this:
Add the below script in your template:
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
write a script and a function inside it to submit the form data.
<script type="text/javascript">
function submitData( challenge_id ){
// Get answer from the input element
var answer = document.getElementById("answer").value;
// add the url over here where you want to submit form & challenge_id is also taken as a parameter.
var url = "<your_url>";
$.ajax({
url: url,
data: {
'answer': answer,
},
dataType: 'JSON',
success: function(data){
// show an alert message when form is submitted and it gets a response from the view where result is provided and if url is provided then redirect the user to that url.
alert(data.result);
if (data.url){
window.open(data.url, '_self');
}
}
});
}
</script>
Change type of the submit button and add an onclick event to call the submitData() function and pass the challenge id to it. And remove the action attr from the form.
see below:
<form method="post">
{% csrf_token %}
{% if challenge|is_answered:request %}
<label for="answered">Answer</label>
<input type="text" name="answered" id="answered" value="{{ challenge.answer_text }}" readonly>
{% else %}
<label for="answer">Answer</label>
<input type="text" name="answer" id="answer">
// over here
<button type="button" onclick="submitData({{ challenge.id }})">
Submit
</button>
{% endif %}
</form>
Return a JsonReponse to the ajax call from the views.
views.py
def answer(request, challenge_id):
answer = request.GET.get('answer', False)
url = False
if challenge.objects.filter(id=challenge_id).exists() and answer:
challenge = Challenge.objects.get(id=challenge_id)
if challenge.answer_text.lower() == answer.lower():
current_user = request.user
session = User_Challenge(user=current_user, challenge=challenge, answered=True)
session.save()
points = Profile(user=current_user, points=challenge.point_value)
points.save()
result = "Correct!"
# specify the url where you want to redirect the user after correct answer
url = ""
else:
result = "Incorrect, try again!"
data = {
'result': result,
'url': url
}
return JsonResponse(data)

django 2.0 work with forms without jquery

from django import forms
class Find(forms.Form):
object_name = forms.CharField()
views.py
def get_obj(request, object_name='000'):
print(object_name)
form = FindSSK()
print(request.GET)
urlpatterns = [
# path(r'ssk/<str:object_name>/', get_obj),
re_path(r'^(?P<object_name>)#$', get_obj),
path(r'', get_obj),
]
{% block find %}
<form class="form-inline ml-5" action="#" method="GET">
{% comment %} {{form}} {% endcomment %}
{% comment %} <input type="number" class="form-control" placeholder="Enter obj" aria-label="Search"> {% endcomment %}
{% comment %} <input type="text" > {% endcomment %}
<input type="text" name="object_name" />
<input class="btn btn-outline-success ml-1 fas fa-search" type="submit" >
</input>
</form>
{% endblock %}
When i push to submit on forms, he will redirect http://127.0.0.1:8000/?object_name=001
But var object_name steal 000
result print in get_obj()
000
<QueryDict: {'object_name': ['001']}>
Sorry for bad English.
You're not able to get the argument needed because you're actually sending the value as a GET argument. However object_name is passed in your view as an argument and as URL parameter for your URL pattern, means that this should be included in the URL like url/object_name/ == http://127.0.0.1:8000/001/. Not sure this is what fits better your need.
To send data to the view, you could use a POST request or a GET request as you did with http://127.0.0.1:8000/?object_name=001.
For both options above, you don't need to have object_name as a parameter neither this ^(?P<object_name>) in url pattern.
VIEW: def get_obj(request object_name='000'):
______________________
URL: re_path(r'^$', get_obj),
method="GET": If you use GET request in form <form class="form-inline ml-5" action="#" method="GET"> you could retrieve the value like the following
def get_obj(request):
object_name = request.GET.get('object_name') # object_name is the field name in form
print(object_name)
method="POST": If you use POST request in form <form class="form-inline ml-5" action="#" method="POST"> you could retrieve the value like the following
def get_obj(request):
object_name = None
if request.method == 'POST':
object_name = request.POST.get('object_name')
print(object_name)
If you use POST request, don't forget to add {% csrf_token %} in your form

Django class based view giving error

I am creating a class based view to add a new record to the db. Below is how my view looks,
class RecordCreateView(CreateView):
fields = ['name','description']
model = models.Record
success_url = reverse_lazy("index")
This is how my form looks,
<form action="{% url 'created' %}" method="post">
{% csrf_token %}
<input type="text" id="name" name="fname" placeholder="Name">
<input type="textarea" id="description" name="fdescription" placeholder="Description">
<input type="button" class="add-row" value="Add Row">
</form>
This is how my url.py file looks,
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$',views.index,name='index'),
url(r'^create/',views.RecordCreateView.as_view(),name='created'),
]
Now when I go to the admin page of django(default admin GUI) and try to add a record, I am getting the below error,
OperationalError at /admin/my_app/record/add/
no such table: abi_app_record
Any leads here will be helpful.