im very new to Javascript, Django & web development in general. Im following a cs50 web dev course by harvard and I have to design a front-end for an email client that makes API calls to send and receive emails.
Ill get mail, send mail, and update emails by using an API that is written specifically for us.
I need to send a GET request to /emails/ where is either inbox, sent, or archive, and it will return back (in JSON form) a list of all emails in that mailbox, in reverse chronological order.
How to fetch, as instructed by the course:
fetch('/emails/sent')
.then(response => response.json())
.then(emails => {
// Print emails
console.log(emails);
// ... do something else with emails ...
});
I put this exact code in my .js file and it gives me these two errors:
GET http://127.0.0.1:8000/emails/sent 500 (Internal Server Error)
load_mailbox @ inbox.js:85
(anonymous) @ inbox.js:24
127.0.0.1/:1 Uncaught (in promise) SyntaxError: Unexpected token < in
JSON at position 0
Promise.then (async)
load_mailbox @ inbox.js:87
(anonymous) @ inbox.js:6
What shows at the cmd: Is the issue at the timestamp of the model in django? I dont understand why.
Internal Server Error: /emails/sent
Traceback (most recent call last):
File "C:\Python\Python38\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
response = get_response(request)
File "C:\Python\Python38\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Python\Python38\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Python\Python38\lib\site-packages\django\contrib\auth\decorators.py", line 21, in _wrapped_view
return view_func(request, *args, **kwargs)
File "C:\Users\AG\Desktop\cs50\mail\mail\views.py", line 96, in mailbox
return JsonResponse([email.serialize() for email in emails], safe=False)
File "C:\Users\AG\Desktop\cs50\mail\mail\views.py", line 96, in <listcomp>
return JsonResponse([email.serialize() for email in emails], safe=False)
File "C:\Users\AG\Desktop\cs50\mail\mail\models.py", line 26, in serialize
"timestamp": self.timestamp.strftime("%b %-d %Y, %-I:%M %p"),
ValueError: Invalid format string
Code given by the course:
models.py:
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
pass
class Email(models.Model):
user = models.ForeignKey("User", on_delete=models.CASCADE, related_name="emails")
sender = models.ForeignKey("User", on_delete=models.PROTECT, related_name="emails_sent")
recipients = models.ManyToManyField("User", related_name="emails_received")
subject = models.CharField(max_length=255)
body = models.TextField(blank=True)
timestamp = models.DateTimeField(auto_now_add=True)
read = models.BooleanField(default=False)
archived = models.BooleanField(default=False)
def serialize(self):
return {
"id": self.id,
"sender": self.sender.email,
"recipients": [user.email for user in self.recipients.all()],
"subject": self.subject,
"body": self.body,
"timestamp": self.timestamp.strftime("%b %-d %Y, %-I:%M %p"),
"read": self.read,
"archived": self.archived
}
views.py, this function i believe it returns the emails from my request:
@login_required
def mailbox(request, mailbox):
# Filter emails returned based on mailbox
if mailbox == "inbox":
emails = Email.objects.filter(
user=request.user, recipients=request.user, archived=False
)
elif mailbox == "sent":
emails = Email.objects.filter(
user=request.user, sender=request.user
)
elif mailbox == "archive":
emails = Email.objects.filter(
user=request.user, recipients=request.user, archived=True
)
else:
return JsonResponse({"error": "Invalid mailbox."}, status=400)
# Return emails in reverse chronologial order
emails = emails.order_by("-timestamp").all()
return JsonResponse([email.serialize() for email in emails], safe=False)
urls.py:
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
# API Routes
path("emails", views.compose, name="compose"),
path("emails/<int:email_id>", views.email, name="email"),
path("emails/<str:mailbox>", views.mailbox, name="mailbox"),
]
My.js code where i use fetch:
document.addEventListener('DOMContentLoaded', function () {
// Use buttons to toggle between views
document.querySelector('#inbox').addEventListener('click', () => load_mailbox('inbox'));
document.querySelector('#sent').addEventListener('click', () => load_mailbox('sent'));
document.querySelector('#archived').addEventListener('click', () => load_mailbox('archive'));
document.querySelector('#compose').addEventListener('click', compose_email);
//code..
});
function compose_email() {
//code..
}
function load_mailbox(mailbox) {
// Show the mailbox and hide other views
document.querySelector('#emails-view').style.display = 'block';
document.querySelector('#compose-view').style.display = 'none';
// Show the mailbox name
document.querySelector('#emails-view').innerHTML = `<h3>${mailbox.charAt(0).toUpperCase() + mailbox.slice(1)}</h3>`;
//problem:
//i will change the 'sent' string in the future
fetch('/emails/sent')
.then(response => response.json())
.then(emails => {
console.log(emails);
});
}
%-dand%-I?-dand-Iwere a thing in Python 2. See my answer for details