2024-11-21-Thursday
created: 2024-11-21 05:47 tags: - daily-notes
Thursday, November 21, 2024
<< Timestamps/2024/11-November/2024-11-20-Wednesday|Yesterday | Timestamps/2024/11-November/2024-11-22-Friday|Tomorrow >>
🎯 Goal
- [x] Configure the blog post subscription feature
🌟 Results
- Configured the blog post subscription feature
- Created the simple
BlogSubscriber
Django Model to track people who want to be emailed when I release a new blog - Used AJAX to submit the user form without redirecting them off the page
- Created the simple
🌱 Next Time
- Configure the email workflow when I release a new blog post in the Blog App, then close out the blog post subscription.
📝 Notes
First I configured the Django Model for a subscriber to the Blog App called a BlogSubscriber
:
# Model to track current subscribers of the blog
class BlogSubscriber(models.Model):
email = models.EmailField()
date_joined = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.email
It's a simple model and only really needs to include the user's email. I'll handle the logic for sending out the emails in the blog/utils.py
file, but a list of users on the subscriber list will be mailed whenever there is a new blog posted. I ran the Database Migrations to include this new model in my database via
python manage.py makemigrations
python manage.py migrate
Next I'll need a way to add the email the user entered into the subscribe option into this model. Then I can add fancier features like AJAX commands and email validation of input.
First I added a forms.py
file to generate the proper Django Form to handle user input. I hooked this Django Form up to the Django Model in the following configuration:
from django import forms
from .models import BlogSubscriber
class BlogSubscriberForm(forms.ModelForm):
class Meta:
model = BlogSubscriber
fields = ['email']
widgets = {
'email': forms.EmailInput(attrs={'placeholder': 'Your email', 'class': 'form-control'}),
}
Then I updated the Django Template to route the user to the subscribe
Django Route on POST:
<form action="{% url 'subscribe' %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="text" placeholder="Your email">
<input class="sidebar-widget__subscribe-submit" type="submit" value="Submit">
</form>
Which corresponds to the subscribe function in the Django View:
def subscribe(request):
if request.method == 'POST':
form = BlogSubscriberForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, "Thank you for subscribing!")
return redirect('home') # Redirect to a relevant page after submission
else:
messages.error(request, "Please enter a valid email address.")
else:
form = BlogSubscriberForm()
return render(request, 'subscribe.html', {'form': form})
Which is called by adding that function to the Django Routes:
path('subscribe/', subscribe, name='subscribe'),
I got a Django Template redirect error because there was no subscribe.html
template. However, since I wanted to execute this form via AJAX anyways I decided to proceed that way. I created a new Javascript file called blog/static/js/subscribe.js
and added the following js:
$(document).ready(function() {
// Get the CSRF token from the form
var csrftoken = $('[name="csrfmiddlewaretoken"]').val();
// Handle blog subscription form submission
$('#subscribe-form').submit(function(event) {
event.preventDefault(); // Prevent default form submission
var form = $(this);
var messageDiv = $('#subscribe-message'); // Div to display messages
// Perform AJAX POST request
$.ajax({
type: 'POST',
url: form.attr('action'), // Get the form's action attribute
data: {
email: form.find('[name="email"]').val(), // Get the email input
csrfmiddlewaretoken: csrftoken, // Include the CSRF token
},
success: function(response) {
if (response.success) {
messageDiv.html(`<p style="color: green;">${response.message}</p>`);
form[0].reset(); // Clear the form inputs
} else {
messageDiv.html(`<p style="color: red;">${response.message}</p>`);
}
},
error: function() {
messageDiv.html('<p style="color: red;">An error occurred. Please try again later.</p>');
}
});
});
});
Which uses JQuery. Then I updated the Django View for the subscribe
function:
def subscribe(request):
if request.method == 'POST':
form = BlogSubscriberForm(request.POST)
if form.is_valid():
form.save()
return JsonResponse({"success": True, "message": "Thank you for subscribing!"})
else:
return JsonResponse({"success": False, "message": "Invalid email address. Please try again."})
return JsonResponse({"success": False, "message": "Invalid request method."})
I had to make sure to include this Javascript in my Django Template so that it would be served to the webpage and was able to do so by adding
{% block extra_js %}
<script src="{% static 'blog/js/subscribe' %}.js"></script>
{% endblock %}
to the home.html
file. Once the appropriate js was served, I was able to add subscribers to my Blog App:
--redacted--
Thankfully this input form also prevents invalid inputs of non-email:
--redacted--
And non-unique email:
--redacted--
Now I just have to configure the email routing / system to alert users of new blog posts:
--redacted--
I could also adapt this subscription button for users who are logged in. If a user is logged in and not subscribed they won't have to enter their email, it's just a button they click to subscribe (or unsubscribe if they are already subbed).
Notes created today
List FROM "" WHERE file.cday = date("2024-11-21") SORT file.ctime asc
Notes last touched today
List FROM "" WHERE file.mday = date("2024-11-21") SORT file.mtime asc