Python Django Edit HTML rows and update database - python

I have a table and I wish to add an edit button that updates the certain record both visually and in the database.
The HTML I have.
{% for work_entry in work_entries %}
{% if work_entry.date == date.date %}
<form action="{% url 'work_entries:object_edit' work_entry.id %}" method="post">
{% csrf_token %}
<tr>
<td>
<button onclick="return confirm('Are you sure you want this edit?')">Edit
</button>
</td>
<td> <form action="{% url 'work_entries:object_delete' work_entry.id %}" method="post">
{% csrf_token %}
<button onclick="return confirm('Are you sure you want to delete this record?')">Delete
</button>
</form>
</td>
<td>{{ work_entry.id }}</td>
<td><input type="text" value="{{ work_entry.description }}" name="description"></td>
<td><input type="number" value="{{ work_entry.num_hours }}" name="hours"></td>
</tr>
</form>
{% endif %}
{% endfor %}
The views.py
def object_edit(request, object_id):
record = get_object_or_404(WorkEntry, pk=object_id)
if request.method == "POST":
record.description = request.POST["description"]
record.num_hours = request.POST["hours"]
record.save()
return redirect("/employeePage")
return render(request, "employeePage.html")
And urls.py
app_name = "work_entries"
urlpatterns = [
path("", views.employee_view, name="employeePage"),
url(r"^delete/(?P<object_id>[0-9]+)/$", views.object_delete, name="object_delete"),
url(r"^edit/(?P<object_id>[0-9]+)/$", views.object_edit, name="object_edit"),
]
I used an input tag in the as I thought that would allow me to change data and save it. However this is giving me MultiValueDictKeyError at /employeePage/edit/14/
'description' error. I am not too experienced with jquery which from research I saw that could work but I don't seem to get it right. Can someone help or even suggestions on how I should approach this would be useful.
Note: there is already a button to delete the record which works, I tried a similar approach for editing, but it doesn't work.

I fully encourage you to use the forms provided by Django, it will make your life easier.
And I fully encourage you as well to not use a form for your delete stuff, it should be a simple link, it would avoid to have a form in a form. I think your problem is here. Having a form in a form with the button in the middle make impossible for your browser to know which parts of the form you want to submit.
As well you have two buttons but none of them is submit type.
If you don't want to use the Django forms a way to do it would be
{% for work_entry in work_entries %}
{% if work_entry.date == date.date %}
<form action="{% url 'work_entries:object_edit' work_entry.id %}" method="post">
{% csrf_token %}
<tr>
<td>
<button>
Delete
</button>
</td>
<td> <button type="submit" onclick="return confirm('Are you sure you want to update this record?')">
Update
</button>
</td>
<td>{{ work_entry.id }}</td>
<td><input type="text" value="{{ work_entry.description }}" name="description"></td>
<td><input type="number" value="{{ work_entry.num_hours }}" name="hours"></td>
</tr>
</form>
{% endif %}
{% endfor %}
It's not the most beautiful way to do it I tried to keep your achitecture

Related

Problems with edit button in Django

i'm novice and just trying Django functionality. I create button to edit value in db in Django, but it doesn't work write. Problem in that: when i press the button (from notes.html), it's redirect to page edit_note.html, but values in fields is empty. When i manually press adress in browser, it work's normally. I don't understand where i maked mistake.
in views.py:
class EditNoteView(UpdateView):
model = Notes
form_class = NotesForm
template_name = 'notes/edit_notes.html'
context_object_name = 'note'
def get_success_url(self):
return reverse_lazy('edit_note', kwargs={'pk': self.object.pk})
in urls.py:
urlpatterns = [
path('', home, name='home'),
path('notes/', NoteView.as_view(), name='notes'),
path('<int:pk>/edit', EditNoteView.as_view(), name='edit_note'),
in notes.html:
{% for i in all_notes %}
<tr>
<td>{{ i.notes_category }}</td>
<td>{{ i.title }}</td>
<td>{{ i.text }}</td>
<td>{{ i.reminder_data_time }}</td>
<td>
<form action="{% url 'edit_note' i.id %}" method="post">
{% csrf_token %}
<div class="btn-small-group">
<button type="submit">Edit</button>
</div>
</form>
</td>
<td>
<div class="btn-small-group">
<button type="submit">Delete</button>
</div>
</td>
{% endfor %}
in edit_notes.html:
<form action="{% url 'edit_note' note.id %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<div class="btn-small-group">
<button type="submit">Edit</button>
</div>
</form>
after press in notes.html on button "edit"
enter press adress in browser
The problem is the method you are using to access the edit form.
You are using the POST method instead of a GET method.
This make Django want to save the edited object instead of displaying the edit form. You should get some validation errors.
Solution
Change the request method to a GET method
Or use an anchor tag as below
Edit

FLASK, Requested URL not found on the server

ISSUE
I am making a CRUD in Flask. I have a user that has positions, and I would like to update a specific position.
The "URL was not found" problem occurs when I click on the anchor link in user_positions.html.
I am using WTF Forms, SQLalchemy, PostgreSQL, Bootstrap, and pgAdmin4.
I hope I have given you enough information.
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
http://0.0.0.0:5000/user/24/url_for('user_position_update',%20owner_id=current_user.id,%20position_id=position.id)%20%7D%7D
MY CODE
user_positions.html
<i class="mdi mdi-pencil"></i> Update
routes.py
#app.route("/user/<string:owner_id>/positions/<string:position_id>/update", methods=['GET', 'POST'])
def user_position_update(owner_id, position_id):
user = User.query.filter_by(id=owner_id).first()
position = Position.query.filter_by(id=position_id).first()
form = UpdatePositionForm()
if current_user.is_authenticated:
if form.validate_on_submit():
strSQl= "update position set position='"+position+"' where owner_id="+str(user.id)
db.session.execute(strSQl)
db.session.commit()
flash('Your position has been updated!', 'success')
return redirect(url_for('user_positions'))
elif request.method == 'GET':
form.position.data = position
return render_template('user_position_update.html', form=form, user=user, position=position)
forms.py
class UpdatePositionForm(FlaskForm):
position = StringField('Position',
validators=[DataRequired()])
date = DateTimeField('Date',
validators=[DataRequired()])
submit = SubmitField('Update')
user_position_update.html
{% extends "layout.html" %}
{% block content %}
<table class="table">
<tr>
<th>Position</th>
<th>Date</th>
</tr>
<tr>
<form method="POST" enctype="multipart/form-data">
{{ form.hidden_tag() }}
<td>
<div class="form-group">
{{ form.positions.label(class="form-control-label") }}
<select class="form-control form-control-sm" name="position">
<option>{{ current_user.positions[-1].position }}</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
<option>7</option>
<option>8</option>
<option>9</option>
<option>10</option>
<option>11</option>
<option>12</option>
<option>13</option>
<option>14</option>
<option>15</option>
</select>
</div>
</td>
<td>
<div class="form-group">
{{ form.position.label(class="form-control-label") }}
<input type="date" class="form-control" value="{{ position.created_date }}" name="date">
</div>
</td>
<td>
<div class="form-group">
{{ form.submit(class="btn btn-outline-info") }}
</div>
</td>
</tr>
</table>
{% endblock content %}
PostgreSQL tables
user table
position table

Accessing Radio/Checkbox button selection in Django form post request

I have a webpage form in django. I have some radio button on my webpage. After user selects the radio button and on submit I need to know which radio button was selected in my views.
I tried using following code:
Html Template:
<form action= "{% url 'rec:opt' %}" method="post">
{% csrf_token %}
{% for name in features %}
<tr>
<td>{{ name }}</td>
<td>
<input type="checkbox" name="is_obj" id={{ name }} + "_is_obj" > <br>
</td>
<td>
Lower Limit <input type="text" name="ll" id={{ name }} + "_ll">
Upper Limit <input type="text" name="ul" id={{ name }} + "_ul">
</td>
</tr>
{% endfor %}
<input type="submit" value="Submit" />
</form>
View.py
def opt(request):
print(request.POST['is_obj']) #'on'
The request.POST only returns 'on' and doesn't say which radio/check box was selected.
Also the getlist returns following
request.POST.getlist['is_obj'] # ['on']
You need to add value attribute to your checkboxes:
<input type="checkbox" name="is_obj" id={{ name }} + "_is_obj" value="{{ name|add:'_is_obj' }}">
If the value attribute was omitted, the default value for the checkbox is on.
Note you can use add filter for string concatination. But be careful strings that can be coerced to integers will be summed, not concatenated.

How to pass arguments to included html in Flask web application

I am developing a blog application in python with flask. In the view function form is passed as argument to render_template which calls 'index.html'. form works in index.html as expected. But there is a {% include '' %} tag which places 'post.htm'. Now I want to use same form repeatedly in 'post.html'. How to do that? Will the passed form to index.html available to included 'post.html' also? And if so how to identify which button is pressed in the rendered page because both forms are same? My index.html file:
{% extends "base.html" %}
{% block content %}
<h1>Hi, {{ g.user.nickname }}!</h1>
<form action="" method="post" name="post">
{{ form.hidden_tag() }}
<table>
..........
..........
<tr>
<td><input type="submit" value="Post!"></td>
</tr>
</table>
</form>
{% for post in posts.items %}
<div class="{{ post.id }}">
<div>
{% include 'post.html' %}
</div>
</div>
{% endfor %}
{% endblock %}
And my post.html as:
<table>
..........
..........
<tr valign="top">
<td>{{ post.body }}</td>
</tr>
<tr>
<form action="" method="post" name="post">
{{ form.hidden_tag() }}
<table>
.........
.........
<td><input type="submit" value="Post!"></td>
</table>
</form>
</table>
Is it possible to use same form on both html files. As there will be several form fields in the rendered web page, how to identify which button is pressed?
index.html is rendered with code:
return render_template('index.html',
title='Home',
form=form,
posts=posts)
To distinguish the different forms, you need some unique key, e.g. a hidden input-tag, which contains an ID:
<input type="hidden" name="post_id" value="{{post.id}}">
For the index-Form you can use as generic ID the value "new".

Url not changing , just render the template after login

The URL is not changing and data is not fetching after user login.
After Login the url not changed(i expected to change to 127.0.0.1:8000/employer/home)
#login_required
def home(request):
emp=Employer.objects.get(user=request.user)
jb=Job.objects.filter(employer=emp).order_by("-postdate")
return render(request,'employer/home.html',{'jobs':jb})#,{'employer':emp})
employer/home.html
<table class="table table-hover table-bordered">
<tr><th>Job ID</th><th>Title</th><th>Posted on</th></tr>
{% for job in jobs %}
<tr>
<td>{{ job.pk }}</td>
<td>{{ job.title }}</td>
<td>{{ job.postdate }}</td>
</tr>
{% endfor %}
</table>
login.html
<form class="form-signin" action="" method="post">{% csrf_token %}
<h4 class="form-signin-heading">Sign in to my account...</h4>
{% if errors %}
<p class="text-error">Sorry, that's not a valid username or password</p>
{% endif %}
<input type="text" id="username" class="input-block-level" name="username" placeholder="UserID">
<input type="password" id="password" class="input-block-level" name="password" placeholder="Password">
<p style="text-align:right;">Forgot your password?</p>
<button class="btn btn-large btn-success" type="submit" value="login">Sign in</button>
</form>
You need to tell it where to go after login using the next url parameter:
<form class="form-signin" action="{% url django.contrib.auth.views.login %}?next=employer/home/" method="post">
or set the LOGIN_REDIRECT_URL in settings:
The URL where requests are redirected after login when the contrib.auth.login view gets no next parameter.

Categories