1

I have put together a chat application using Django & jQuery. However, I can't seem to refresh the application after a short interval so that the other person sending a message is shown in the window. Here is the code:

urls.py

urlpatterns = [
    url(r'^home/$', views.home),
    url(r'^post/$', views.post),
]

views.py

def home(request):
    m = Msgs.objects.all()
    return render(request, "alpha/home.html", {'messages': m})

def post(request):
    if request.method == "POST":
        msg = request.POST.get('msg')
        if msg != '':
            m = Msgs(msg=msg, usr=request.user)
            m.save()
            return JsonResponse({"msg" : m.msg, "user" : m.usr.username})
    else:
        return JsonResponse({"nothing to see" : "this isn't happening"})

home.html

<div class="chatContainer">
    <div class="chatHeader">
        <h3>Welcome {{ request.user }}</h3>
    </div>
    <div id="chatMessages" class="chatMessages">
        <ul id="talk">

            {% for obj in messages %}
                {% if obj.usr == request.user %}
                    <li class=cm>{{ obj.msg }}</li>
                {% else %}
                    <li class=cm-other>{{ obj.msg }}</li>
                {% endif %}
            {% empty %}
                <li class="cm">No previous messages to display.</li>
            {% endfor %}
        <script>
            var objDiv = document.getElementById("chatMessages");
            objDiv.scrollTop = objDiv.scrollHeight;
        </script>
        </ul>
    </div>
    <div class="chatBottom">
        <form method="post" action="/post/" id="chatForm">
            <input type="text" name="msg" id="msg" placeholder="Write something..." />
            <input type="submit" id="submit" value="Post" />
        </form>
    </div>

main.js

$('#chatForm').on('submit', function(event) {
    event.preventDefault();
    console.log("form submitted!");
    create_post();
});

function create_post() {
    console.log("create post is working!")

    $.ajax({
        url : "/post/",
        type : "POST",
        data : { msg : $('#msg').val() },

        success : function(json) {
            $('#msg').val('');
            console.log(json);
            $('#talk').append("<li class=cm>" + json.msg + "</li>");
            var objDiv = document.getElementById("chatMessages");
            objDiv.scrollTop = objDiv.scrollHeight;
            console.log("success");
        },
    });
};

// This function enables/disables the post button
$(document).ready(function() {
     $('#submit').attr('disabled','disabled');
     $('#msg').keyup(function() {
        if($(this).val() != '') {
           $('#submit').removeAttr('disabled');
        }
        else {
        $('#submit').attr('disabled','disabled');
        }
     });
 });


// This function gets cookie with a given name
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) == (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');

/*
The functions below will create a header with csrftoken
*/

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function sameOrigin(url) {
    // test that a given url is a same-origin URL
    // url could be relative or scheme relative or absolute
    var host = document.location.host; // host + port
    var protocol = document.location.protocol;
    var sr_origin = '//' + host;
    var origin = protocol + sr_origin;
    // Allow absolute or scheme relative URLs to same origin
    return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
        (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
        // or any other URL that isn't scheme relative or absolute i.e relative.
        !(/^(\/\/|http:|https:).*/.test(url));
}

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
            // Send the token to same-origin, relative URLs only.
            // Send the token only if the method warrants CSRF protection
            // Using the CSRFToken value acquired earlier
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

1 Answer 1

1

You're basically asking: how to build a chat with javascript and Django.

The easiest way is to retrieve just the messages with a simple GET request with javascript, and do this every 3 seconds or so. Look up the javascript setTimeout() method.

view.py

# add this method
def messages(request):
    m = Msgs.objects.all()
    return render(request, "alpha/messages.html", {'messages': m})

messages.html

        {% for obj in messages %}
            {% if obj.usr == request.user %}
                <li class=cm>{{ obj.msg }}</li>
            {% else %}
                <li class=cm-other>{{ obj.msg }}</li>
            {% endif %}
        {% empty %}
            <li class="cm">No previous messages to display.</li>
        {% endfor %}

main.js

function getMessages() {
    $.get("/messages/", function(messages) {
        $("#talk").html(messages);
    });
    // repeat this method after 3 seconds
    setTimeout(getMessages, 3000);
}

And then, with javascript, overwrite the current messages with the newly retrieved.

Thats the most simple method. You'll probably notice that this is quite redundant, as you could also just retrieve NEW messages. This is commonly done by doing a GET-request with a 'last_message_id' parameter, and then you'll just do a query like

Msgs.objects.all().filter(id > last_message_id)

There are tons of tutorials on this topic (not just specific django). I think you'll be able to figure it out now.

5
  • Can you please clarify what you mean by the Django view that returns the mentioned part? My home view is querying m = Msgs.objects.all() and then passing that as context {"messages" : m}. I thought I WAS returning that part. I am very weak in JS. Sorry.
    – MiniGunnR
    Commented Oct 6, 2015 at 9:48
  • You're actually returning return render(request, "alpha/home.html", {'messages': m}) It renders alpha/home.html, with the data provided in 'messages'. You could create a new template with just the html in my answer, and have just that returned. Commented Oct 6, 2015 at 9:50
  • Got it. And then just refresh the whole queryset every 3 seconds on the chat app.
    – MiniGunnR
    Commented Oct 6, 2015 at 10:27
  • The js function doesn't work somehow. I have tried setInterval too. :-/ Also used console.log(messages), the <li> doesn't show on the dev console.
    – MiniGunnR
    Commented Oct 6, 2015 at 11:34
  • 1
    Got it to work finally function getMessages() { $.get("/messages/", function(messages) { $('#talk').html(messages); var objDiv = document.getElementById("chatMessages"); objDiv.scrollTop = objDiv.scrollHeight; }); } setInterval(function(){ getMessages() }, 3000);
    – MiniGunnR
    Commented Oct 6, 2015 at 11:49

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.