I’m currently doing CS50w,in project 1 it’s assign to create a sort of wikipedia like site, user should be able to create new entries for that wiki and edit existing ones, this is where I got stuck. On each of the entries page there’s a ‘edit’ button, whe user clicks it he’s redirected to ‘editEntry’ function seen in code below, then user should be able to edit existing text and press submit, but however I edit the entry the form.is_valid() returns false and I’m not sure why. I’m asking for tips, not straight answer because I really want to learn this, I’m confused because even print(form.errors) outputs blank line.
Sorry if this is asked incorectly, it’s my first question ever on this site and english is not my first language. Thank you
class editPageForm(forms.Form):
def __init__(self, entry_data, *args, **kwargs):
super(editPageForm, self).__init__(*args, **kwargs)
self.fields['markdown'] = forms.CharField(
widget=forms.Textarea(),
initial=entry_data
)
def editEntry(request,entry):
if request.method == "POST":
# Take in the data the user submitted and save it as form
form = editPageForm(request.POST)
print('Printing Form')
print(form)
print('Printing Form non field errors')
print(form.non_field_errors)
# Check if form data is valid (server-side)
if form.is_valid():
print('Valid')
title = entry
new_markdown = form.cleaned_data['markdown']
entryFile = open(f'./entries/{entry}.md', 'w')
entryFile.write(f"{new_markdown}")
entryFile.close()
return HttpResponseRedirect(reverse("entry", kwargs={'name':title}))
else:
print('Not Valid')
print(form.errors)
return HttpResponseRedirect(reverse("index"))
else:
entryData = util.get_entry(entry)
return render(request, "encyclopedia/edit.html",{
'title': entry,
'editPageForm': editPageForm(entryData)
})
Here’s edit.html template
{% extends "encyclopedia/layout.html" %}
{% block title %}
Create New Page
{% endblock %}
{% block body %}
<form action="{% url 'editEntry' entry=title%}" method="POST">
{% csrf_token %}
<div>{{ editPageForm.markdown }}</div>
{{editPageForm.errors}}
{{editPageForm.non_field_errors}}
<br>
<input type="submit" value="Submit">
</form>
{% endblock %}
And also urls.py which I’m not sure if is made correctly
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path('newpage', views.newpage, name='newpage'),
path("<str:name>", views.entry, name='entry'),
path('editEntry/<str:entry>',views.editEntry, name='editEntry')
]
I tried changing things around in urls.py, added ‘{{editPageForm.errors}}
{{editPageForm.non_field_errors}}’ in edit.html which I found in other similar question but it didn’t do anything im my case, leaving it anyway, maybe it will be usefull after I change some things.
Added bunch of print functions to help me understand what is going on. For example
form = editPageForm(request.POST)
print('Printing Form')
print(form)
print('Printing Form non field errors')
print(form.non_field_errors)
resulted in
Printing Form
<tr>
<th><label for="id_markdown">Markdown:</label></th>
<td>
<textarea name="markdown" cols="40" rows="10" required id="id_markdown">
<QueryDict: {'csrfmiddlewaretoken': ['BfbwJHvvyQjNpAT1kvENkUd4ArQpIZWKC7lI2JHKRVZ3sdDaAxW48kwVNto7B5RQ'], 'markdown': ['# CSS\r\n\r\nCSS is a language that can be used to add style to an [HTML](/wiki/HTML) page. !\r\n']}></textarea>
</td>
</tr>
Printing Form non field errors
<bound method BaseForm.non_field_errors of <editPageForm bound=False, valid=False, fields=(markdown)>>
I’m not sure why csrf token is there in the text area while it’s added above in edit.html template and other symbols which do not show up in other forms created earlier in the same project.
For example this part ”# CSS\r\n\r\nCSS is a language…’, whats ”#’ I do not know
>Solution :
You pass the request.POST
as entry_data
, not as the data. It is not necessary either. What you can do is define the field at class-level:
class editPageForm(forms.Form):
markdown = forms.CharField(
widget=forms.Textarea(),
)
and then in the view pass it as initial value:
def editEntry(request, entry):
if request.method == 'POST':
form = editPageForm(request.POST, request.FILES)
if form.is_valid():
title = entry
new_markdown = form.cleaned_data['markdown']
entryFile = open(f'./entries/{entry}.md', 'w')
entryFile.write(f"{new_markdown}")
entryFile.close()
return redirect('entry', name=title)
# else: rerender the form with errors
else:
entryData = util.get_entry(entry)
editPageForm(initial={'markdown': entryData})
return render(
request, 'encyclopedia/edit.html', {'title': entry, 'editPageForm': form}
)
Note: While most forms do not process media files, it is probably better to pass
request.FILES
[Django-doc] to the form anyway, such that if you later add an extra media field, all views that use the form will indeed handle the files properly.
Note: Normally the procedure is in case the form fails to rerender the template with the (failed) form, such that errors can be rendered and the user can submit the form again. By redirecting, you will create a new form where the submitted data is "gone" and the error is not displayed.