Problems with edit button in Django - python

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

Related

Python Django Edit HTML rows and update database

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

Getting the id of a model from a button in Django

I currently have a template set up so that it loops through all of my menu items with a button that correspond to a post request in my views.py
<td>
{% for menu_items in menu %}
{{ menu_items.Menu_name }}
{% endfor %}
</td>
<td>
{% for menu_desc in menu %}
{{ menu_desc.Menu_Desc }}
{% endfor %}
</td>
<form method="post">
{% csrf_token %}
<th><input class="btn btn-success" type="submit" value="Add To Cart" name="add">.
</th>
</form>
In my views file I have a if statement that tries to get the id of the model that was clicked.
However, i'm only able to get the Query Set and not the specific ID of the model.
def ordering(request):
latest_order = Order.objects.all()
menu = Menu.objects.all()
if 'add' in request.POST:
user_order = Order.objects.get(name='')
print(menu.id)
return render(request, 'users/ordering.html', {'title':'Ordering', 'latest_order': latest_order, 'menu':menu})
When working with queryset, whatever is returned has a primary key and not id as you would occasionally think, therefore use
item.pk instead of item.id
You cannot get the id of QuerySet, in the situation, you can treat the QuerySet like an iterable, try to print this way:
menu = Menu.objects.all()
print([item.id for item in menu])

Django-Filter: Dynamically Create Queryset on Search or Hide Queryset until Search

I am using django-filter to search a model. Here is the code:
filters.py:
class PersonFilter(django_filters.FilterSet):
lastName = django_filters.CharFilter(lookup_expr='icontains')
firstName = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = Person
fields = ['lastName', 'firstName']
views.py:
def search(request):
people = Person.objects.all()
people = PersonFilter(request.GET, queryset=people)
context = {'filter': people}
return render(request, 'myapp/template.html', context)
template.html:
<form method="get">
{{ filter.form.as_p }}
<button type="submit">Search</button>
</form>
<table>
{% for field in filter.qs %}
<tr>
<td>
{{ field.idno }}
</td>
<td>
{{ field.lastName }}
</td>
<td>
{{ field.firstName }}
</td>
<td>
{{ field.status }}
</td>
</tr>
{% endfor %}
</table>
{% endblock %}
</body>
</html>
Right now, this results in a table that mirrors my model with search boxes for first name and last name. The search works perfectly.
How do I prevent the table of data from showing up initially? Logically, this could be done superficially (hide) or, better yet, substantially (dynamically create queryset). Is this possible?
You can leverage the FilterSet's is_bound property, although you would need to change the view code to only provide the request query params when the form has been submitted.
def search(request):
submitted = 'submitted' in request.GET
data = request.GET if submitted else None
people = PersonFilter(data, queryset=Person.objects.all())
return render(request, 'myapp/template.html', {'filter': people})
<form method="get">
{{ filter.form.as_p }}
<button type="submit" name="submitted">Search</button>
<!-- ^^^^ added 'name' parameter -->
</form>
{% if filter.is_bound %}
<table>
{% for person in filter.qs %}
...

'dict' object has no attribute 'all_aircraft'

I have a list of posts that the user is able to favorite and save to their to their account. However, I keep getting the error message above. Does anybody have any idea as to where the issue lies?
views.py:
def AircraftFavourite(request, id=None):
instance = get_object_or_404(Aircraft, id=id)
queryset = Aircraft.objects.all()
context = {'all_aircraft' : queryset}
try:
selected_aircraft = context.all_aircraft.get(pk=request.POST['context'])
except(KeyError, Aircraft.DoesNotExist):
return render(request,'aircraft.html', {
"aircraft" : instance,
"error_message" : "You did not select a valid aircraft",
})
else:
selected_aircraft.is_favorite = True
selected_aircraft.save()
return render(request,'aircraft.html', context)
urls.py
urlpatterns = [
url(r'^detail/(?P<id>\d+)/$', AircraftDetail, name='AircraftDetail'),
url(r'^(?P<id>\d+)/favourite/$', AircraftFavourite, name='AircraftFavourite'),]
aircraft.html
{% block content %}
{% for a in all_aircraft %}
<table>
<tr>
<th> {{ a.title }}
</th>
</tr>
<tr>
<td>
<form action="{% url 'AircraftFavourite' id=a.id %}" method="post">
{% csrf_token %}
<input type="submit" id="aircraft{{ forloop.counter }}" name ="aircraft" value="{{ a.id }}">
<label for="aircraft{{ forloop.counter }}"
{% if aircraft.is_favourite %}
<img src="http://i.imgur.com/b9b13Rd.png" />
{% endif %}
<input type="submit" value="Favourite"><br>
</form>
</td>
</tr>
</table>
{% endfor %}
{% endblock %}
In django templates attribute access and item access are equivalent:
template.html
#rendered with context = dict(a=dict(something=5), b=SomeObject))
<body>
{{ a.something }} vs {{ b.something }}
</body>
Both will work and django figures out whether to access the attribute or get the item.
However in Python, the attribute access with the . is not equivalent to item access with the brackets [ ].
Your script should be changed to reflect this:
try:
selected_aircraft = context['all_aircraft'].get(pk=request.POST['context'])
Or ideally just access the queryset directly, so the code better reflects what you're doing:
try:
selected_aircraft = queryset.get(pk=request.POST['context'])
Change to this:
selected_aircraft = get_object_or_404(Aircraft, id=request.POST['context'])

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".

Categories