I have a all_products_page.html(super admin side) where i'm getting products of all the user.
In this page there is a column named 'status'. on which i'm sending an ajax request to approve or unapprove product.
I want whenever super admin approve or unapprove a product a notification to be send to that particular user.
How can i achieve that, as i can only send one room_name.
models.py
#receiver(post_save, sender=BroadcastNotification)
def notification_handler(sender, instance, created,update_fields, **kwargs):
# if seen field is not updated in DB , i.e if message is created or updated then send notifiction
if created or update_fields is None:
channel_layer = get_channel_layer()
# call group_send function to send notifications
async_to_sync(channel_layer.group_send)(
"notification_" + "admin" if not instance.from_admin
else "notification_" + str(instance.notification_receiver_id),
{
'type': 'send_notification' ,
'message': json.dumps(str(instance.id) + ">" + instance.message + ">"
+ instance.notification_link)
}
)
In models.py i'm calling notification on post save of data
consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class NotificationConsumer(AsyncWebsocketConsumer):
async def connect(self):
# get user id of notification receiver
self.room_name = self.scope['path'].split('/')[3]
self.room_group_name = 'notification_%s' % self.room_name
print(self.room_group_name)
# Join room group
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
# Leave room group
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
# Receive message from room group
async def send_notification(self, event):
message = json.loads(event['message'])
print("msg",message)
# Send message to WebSocket
await self.send(text_data=json.dumps(message))
main.js
const notificationSocket = new WebSocket(
'ws://'
+ window.location.host
+ '/ws/notification/'
+ roomName
+ '/'
);
//-----------------If any message for websocket , append message to dropdown and update badge number----------
notificationSocket.onmessage = function(e) {
const data = JSON.parse(e.data);
console.log(data);
let notif_id = data.split('>')[0];
let msg = data.split('>')[1];
let link = data.split('>')[2];
if(roomName == "admin")
{
document.getElementById(`notifications-dropdown`).innerHTML
= `<a class="dropdown-item notification_msg_drpdwn" msg_id="${notif_id}"
href="${link}" >${msg}</a>` +"</li><hr class='dropdown-divider'>" +
document.getElementById(`notifications-dropdown`).innerHTML;
document.getElementById(`notification-badge`).innerHTML
= parseInt(document.getElementById(`notification-badge`).innerHTML) + 1;
}
else
{
document.getElementById(`notifications-dropdown_${roomName}`).innerHTML
= `<a class="dropdown-item notification_msg_drpdwn" msg_id="${notif_id}"
href="${link}" >${msg}</a>` +"</li><hr class='dropdown-divider'>" +
document.getElementById(`notifications-dropdown_${roomName}`).innerHTML;
document.getElementById(`notification-badge_${roomName}`).innerHTML
= parseInt(document.getElementById(`notification-badge_${roomName}`).innerHTML) + 1;
}
};
Related
I just want to send message to particular group via async to sync,
Here is my consumers file
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class ChatRoomConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.chat_box_name = self.scope["url_route"]["kwargs"]["chat_box_name"]
self.group_name = "chat_%s" % self.chat_box_name
await self.channel_layer.group_add(self.group_name, self.channel_name)
await self.accept()
async def disconnect(self, close_code):
await self.channel_layer.group_discard(self.group_name, self.channel_name)
# This function receive messages from WebSocket.
async def receive(self, text_data):
text_data_json = json.loads(text_data)
message = text_data_json["message"]
username = text_data_json["username"]
await self.channel_layer.group_send(
self.group_name,
{
"type": "chatbox_message",
"message": message,
"username": username,
},
)
# Receive message from room group.
async def chatbox_message(self, event):
message = event["message"]
username = event["username"]
#send message and username of sender to websocket
await self.send(
text_data=json.dumps(
{
"message": message,
"username": username,
}
)
)
async def chat_message(self, event):
message = event["message"]
# Send message to WebSocket
await self.send(text_data=json.dumps({"message": message}))
And this is my code for sending message to specific group
import channels.layers
from asgiref.sync import async_to_sync
channel_layer = channels.layers.get_channel_layer()
async_to_sync(channel_layer.group_send)("chat_groupone", {"type": "chatbox_message","message":"STOP","username":"admin"})
I don't know what i am doing wrong in this, it returns me none without any error
I am expecting by running this code, group should have recieved the message
Version-
Django- 4.0
channels - 3.0.4
python - 3.9
EDIT: correction after #Ken4scholars comment below
I have the following consumer which fails right after connecting
consumers.py
from channels.generic.websocket import AsyncJsonWebsocketConsumer
#...
class ListGeneratedTokensByFileConsumer(AsyncJsonWebsocketConsumer):
stop = False
async def websocket_connect(self,event):
await self.accept()
self.stop = False
async def websocket_receive(self,event):
await self.send_json({"text":"received","accept": True})
await self.send_tokens_list()
async def websocket_disconnect(self,event):
self.stop = True
async def send_tokens_list(self):
some_path = "..."
while self.stop == False:
await asyncio.sleep(2)
the_message = {}
if os.path.isfile("some_file.json")):
with open(os.path.join(some_path ,"some_file.json"),'r') as new_tok:
the_message = json.load(new_tok)
if not the_message:
print("waiting...")
else:
await self.send_json(the_message)
await self.close()
It always throws the error: ERR_CONNECTION:RESEST and the websocket disconnects with code 1006. This might seem familiar to recent changes in django-channels but since I am sending a text once the websocket opens and send a message back from the consumer it should do the trick. Or is there something wrong?
routing.py
url(r'^myapp/sub_path/(?P<pk>\d+)/sub_sub_path/',ListGeneratedTokensByFileConsumer)
and the websocket endpoint in js is:
.js
var loc = window.location;
var wsStart = "ws://";
if (loc.protocol == "https:") {
wsStart = "wss://";
}
var endpoint = wsStart + loc.host + loc.pathname + "sub_sub_path" + "/";
for info, with channels-redis==2.3.2, channels==2.3.0, asgiref==3.2.2, daphne==2.3.0, django==2.0.8
If you see something like in django logs:
WebSocket HANDSHAKING /ws/your_route
WebSocket REJECT /ws/your_route
WebSocket DISCONNECT /ws/your_route
And you wrapped websocket router with AllowedHostsOriginValidator in the asgi.py like:
application = ProtocolTypeRouter({
"http": django_asgi_app,
"websocket": AllowedHostsOriginValidator(
URLRouter(
chat_websocket_urlpatterns
))
})
Then you definetely should check the ALLOWED_HOSTS variable in the settings.py, maybe you forgot to put something in there. In my case it was just because I didn't specify my IP address, only localhost.
This is most likely not that the asker looked for, but I thought it may come handy to someone else, as there is not much info about the django channels in this site.
There is a tutorial page I'm following on WebSockets and Django Channels.
Below is the front end code:
var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
var chat_socket = new ReconnectingWebSocket(ws_scheme + '://' + window.location.host + "/chat" + window.location.pathname);
URLs.py
urlpatterns = [
url(r'^$', views.about, name='about'),
url(r'^new/$', views.new_room, name='new_room'),
url(r'^(?P<label>[\w-]{,50})/$', views.chat_room, name='chat_room'),
]
views.py
def chat_room(request, label):
# If the room with the given label doesn't exist, automatically create it
# upon first visit (a la etherpad).
room, created = Room.objects.get_or_create(label=label)
# We want to show the last 50 messages, ordered most-recent-last
messages = reversed(room.messages.order_by('-timestamp')[:50])
return render(request, "chat/room.html", {
'room': room,
'messages': messages,
})
Why are we using the following?
"/chat" + window.location.pathname);
I understand that this URL is the location of the WebSocket server. But how does this URL locate that as we did not specify any such pattern anywhere?
I have a Django view that I want to integrate with an Ajax call. The call is happening cross domain. I have this code running by itself and making the request cross-domain.
def myview(_request):
response = HttpResponse(json.dumps({"key": "value", "key2": "value"}))
response["Access-Control-Allow-Origin"] = "*"
response["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS"
response["Access-Control-Max-Age"] = "1000"
response["Access-Control-Allow-Headers"] = "*"
return response
I am wondering how to integrate this into my existing view. You will see what I have tried in the code below:
def american_time(request):
#Calling the HTML Source from the URL
sock = urllib.urlopen("http://apps.cbp.gov/bwt/index.asp")
htmlSource = sock.read()
sock.close()
#create a soup object
soup = BeautifulSoup(htmlSource)
#find the tags we need and their content
bridge = soup.findAll('td', limit=215)[194]
tunnel = soup.findAll('td', limit=250)[208]
#new variables to be passed
contents_of_tunnel = tunnel.getText(', ')
contents_of_bridge = bridge.getText(', ')
#check to see if there is a delay for the bridge
if 'no delay' in contents_of_bridge:
time_to_cross_the_bridge = 0
else:
inside_of_bridge = re.split(r', ', contents_of_bridge)
number_inside_of_bridge = inside_of_bridge[1]
list_for_time_to_cross_the_bridge = re.findall(r"\d+", number_inside_of_bridge)
time_to_cross_the_bridge = list_for_time_to_cross_the_bridge[0]
if 'no delay' in contents_of_tunnel:
time_to_cross_the_tunnel = 0
else:
inside_of_tunnel = re.split(r', ', contents_of_tunnel)
number_inside_of_tunnel = inside_of_tunnel[1]
list_for_time_to_cross_the_tunnel = re.findall(r"\d+", number_inside_of_tunnel)
time_to_cross_the_tunnel = list_for_time_to_cross_the_tunnel[0]
response = HttpResponse(json.dumps({"bridge_time": time_to_cross_the_bridge, "tunnel_time": time_to_cross_the_tunnel}))
response["Access-Control-Allow-Origin"] = "*"
response["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS"
response["Access-Control-Max-Age"] = "1000"
response["Access-Control-Allow-Headers"] = "*"
#finally, return as Ajax
return HttpResponse(response)
AJAX:
$.get( "http://localhost:8000/us", function(json){
$('#timeone').html(json.bridge_time + "min delay");
$('#timetwo').html(json.tunnel_time + "min delay");
})
.fail(function(){
alert('We can\'t get data right now! Please try again later.');
})
.done(function(){
alert('Success!');
});
However, I am still getting the message XMLHttpRequest cannot load http://localhost:8000/us. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. in the console. How can I integrate this header into my view?
Try add this middleware.
How to add see documentation https://docs.djangoproject.com/en/dev/topics/http/middleware/
Currently I am trying to implement a login validation system. I am using ajax so that users can get a response without being redirected to another page. My ajax function sends email and password that user has inputted, and get message in callback function, which can be in three types: email, password, or the actual HttpResponse object. But I have no idea how to render the given http response object using ajax and jquery. Is location.href an option? I am pasting the code below.
In javascript:
function loginSubmit(email, password) {
var d= "email=" + email + "&password=" + password;
$.ajax({
url: "/login",
type: "POST",
dataType: "text",
data: d,
success: function(m) {
if (m == "email") {
$("#emailMessage").html("There is no account associated with this email address.");
$("#emailError").show();
$("#emailError").fadeOut(5000, function() {});
} else if (m == "password") {
$("#emailMessage").html("There is no account associated with this email address.");
$("#emailError").show();
$("#emailError").fadeOut(5000, function() {});
} else {
}
}
});
}
in view function:
def login(request):
json = request.POST
e = json['email']
p = json['password']
u = User.objects.filter(email=e)
if (len(u)):
up = User.objects.filter(email=e, password=p)
if (len(up)):
return render_to_response('profile.html', context_instance=RequestContext(request))
else:
data = "password"
c = RequestContext(request, {'result':data})
t = Template("{{result}}")
datatype=u"application/javascript"
return HttpResponse(t.render(c), datatype)
else:
data = "email"
c = RequestContext(request, {'result':data})
t = Template("{{result}}")
datatype=u"application/javascript"
return HttpResponse(t.render(c), datatype)
p.s. Currently I am using a dummy template and HttpResponse to send data to the ajax success callback function. Is there a more efficient way to accomplish this (send back json data)? I will wait for your replies guys!
from django.contrib.auth import authenticate, login as auth_login
def login(request):
# Use authentication framework to check user's credentials
# http://djangosnippets.org/snippets/1001/ for auth backend
user = authenticate(
email = request.POST['email'],
password = request.POST['password'], )
if user is not None:
# Use Auth framework to login user
auth_login(request, user)
return render_to_response('profile.html',
context_instance=RequestContext(request))
else:
# Return Access Denied
# Never return bad email/bad password. This is information leakage
# and helps hackers determine who uses your platform and their emails.
return HttpResponse("Failed: Bad username or password", status=403)
function loginSubmit(email, password) {
$.ajax({
url: "/login",
type: "POST",
data: {email:email, password:password},
success: function(data) {
var returned_html = $(data);
$("#target_profile_area").clear().append(returned_html);
},
error: function(jqXHR) {
if (jqXHR.statusCode == 403) {
$("#loginMessage").text("Your login details are incorrect");
} else {
$("#loginMessage").text("Error Contacting Server");
}
$("#loginError").show();
$("#loginError").fadeOut(5000, function() {});
}
});
}