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


🌟 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

🌱 Next Time


📝 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

(Template referenced from Dann Berg, can be found here)


Previous Note 2024-11-20-Wednesday Next Note 2024-11-22-Friday