Django UpdateView not Updating
I have created a Django app that allows users to enter their stock trades, as a journaling tool. When a user clicks on an individual journal entry from the index page, they will be taken to a detail page showing all the information on that individual entry (single_entry.html). This page is handled by an UpdateView. From this page, a user can edit/update any info, as well as DELETE that specific entry. There are two buttons on the form, one for 'Delete' and another for 'Update'.
The deleting works fine. The updating used to work, but now is not for some reason! Nothing updates in the Entry. Also I can't figure out why the 'messages' middleware is not being output to the screen. Same with all my print() statements, nothing is coming out on the console.
Thanks for your help!
Here's my views.py:
from django.forms.models import BaseModelForm
from django.shortcuts import render, redirect
from django.http import HttpResponse, HttpResponseRedirect
from django.views import View
from django.contrib import messages
from django.urls import reverse_lazy
from .forms import EntryForm
from .models import Entry
from django.views.generic.edit import UpdateView, DeletionMixin
from django.views.generic import DeleteView
# Create your views here.
class EntryView(View):
def get(self, request):
entries = Entry.objects.all().order_by("entered_date")
form = EntryForm()
return render(request, "entries.html", {"form":form, "entries":entries})
def post(self, request):
form = EntryForm(request.POST, request.FILES) #must add request.FILES for uploads
print(request.FILES)
if form.is_valid():
form.save()
messages.success(request, "Entry created!")
return redirect("/")
else:
messages.error(request, "Please correct the errors below.")
return render(request, "entries.html", {"form":form})
class SingleEntryView(UpdateView):
template_name = "single_entry.html"
model = Entry
fields = ['ticker', 'strategy', 'result', 'comments', 'image']
success_url = '/'
form = EntryForm
def post(self, request, *args, **kwargs):
if 'delete_button' in self.request.POST:
self.object = self.get_object()
self.object.delete()
messages.success(request, "Entry has been deleted")
return HttpResponseRedirect(self.get_success_url())
return redirect('/')
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
Here is urls.py:
from django.urls import path
from django.contrib import admin
from . import views
urlpatterns = [
path("", views.EntryView.as_view(), name="index"),
path("entries/<int:pk>/", views.SingleEntryView.as_view(), name="single-entry"),
path("admin/", admin.site.urls)
]
Here is single_entry.html:
{% extends 'base.html' %}
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% block title %}
Trading Journal - Entry
{% endblock title %}Trading Journal
{% block content %}
<form method="POST" action="">
{% csrf_token %}
{% for field in form %}
{{field.label_tag}}
{{field}}
{% if field.errors %}
<small class="error">{{ field.errors|striptags }}</small>
{% endif %}
{% endfor %}
<button type="submit" name="update_button">Save</button>
<button tyupe="submit" name="delete_button">Delete</button>
</form>
<!-- {% if entry.image.url != Null %} -->
<img src="{{ entry.image.url }}" alt="{{ entry.result }}">
<!-- {% else %} -->
<img src="", alt="{{ entry.result }}">
<!-- {% endif %} -->
{% endblock content %}
Models.py:
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator
from django.urls import reverse
from django.utils.text import slugify
class Entry(models.Model):
ONEORB="1-Min ORB"
FIVEORB="5-Min ORB"
ABCD="ABCD"
REVERSAL="Reversal"
PROFIT="Profit"
LOSS="Loss"
RESULT_CHOICES = (
(PROFIT, "Profit"),
(LOSS, "Loss")
)
STRATEGY_CHOICES = (
(ONEORB,"1-Min ORB"),
(FIVEORB,"5-Min ORB"),
(ABCD,"ABCD"),
(REVERSAL,"Reversal")
)
entered_date=models.DateField(auto_now_add=True)
ticker=models.CharField(max_length=8, default="")
strategy=models.CharField(max_length=12, choices=STRATEGY_CHOICES, default="ONEORB")
result=models.CharField(max_length=6, choices=RESULT_CHOICES, default="PROFIT")
comments=models.TextField(max_length=300, blank=True)
image = models.ImageField(upload_to="", null=True, blank=True) #will save to default BASE_DIR which is 'uploads'
def __str__(self):
return f"{self.result} {self.entered_date}"
Forms.py:
from django import forms
from .models import Entry
class EntryForm(forms.ModelForm):
class Meta:
model=Entry
fields='__all__'
I was expecting the UpdateView to update the Entry information with new information.
You are using an UpdateView while actually performing a self.object.delete(). That’s uncanny isn’t it?
An update should be handled in an UpdateView and a delete in a DeleteView. Then use HTML5 <button formaction />.
views.py
from django.views.generic.edit import UpdateView, DeleteView
from django.contrib.messages.views import SuccessMessageMixin
from django.urls import reverse_lazy
# •••Rest of your views•••
class SingleEntryView(UpdateView, SuccessMessageMixin):
template_name = "single_entry.html"
form = EntryForm
fields = ['ticker', 'strategy', 'result', 'comments', 'image']
model = Entry
success_url = reverse_lazy("index")
success_message = "Entry has been updated"
class DeleteEntry(DeleteView, SuccessMessageMixin):
model = Entry
success_url = reverse_lazy("index")
success_message = "Entry has been deleted"
urls.py
urlpatterns = [
# •••Rest of your paths•••
path("entry/delete/<int:pk>/", views.DeleteEntry.as_view(), name="delete-entry")
# •••Rest of your paths•••
]
single_entry.html
<form method="POST" action="{% url 'single-entry' entry.pk %}">
<!--•••Rest of your form•••-->
<button type="submit" formaction="{% url 'delete-entry' entry.pk %}">Delete</button>
</form>