There are some data which would be sent frequently from a django server to the angularjs, this is a data which would be modified frequently and the modification would be updated at the front end when the changes are made at the backend
At the point where the data is made available I have inserted
views.py
send_event('test', 'message', {'text': dataModifiedFrequently})
asgi.py
application = ProtocolTypeRouter({
'http': URLRouter([
url(r'^event_url/', AuthMiddlewareStack(
URLRouter(django_eventstream.routing.urlpatterns)
), { 'channels': ['test'] }),
url(r'', get_asgi_application()),
]),
})
angular.js
$scope.EventSourceScope = function(){
if (typeof(EventSource) !== "undefined") {
var source = new EventSource('event_url');
source.onmessage = function (event) {
$scope.openListingsReport = event.data;
$scope.$apply();
console.log($scope.openListingsReport);
};
}
else {
// Sorry! No server-sent events support..
alert('SSE not supported by browser.');
}
}
I used the Django EventStream package and followed the example I do not seem to see any result in the angularjs. but in my
browser it gave me the error
EventSource's response has a MIME type ("text/html") that is not "text/event-stream". Aborting the connection.
I followed the example in https://github.com/fanout/django-eventstream.
Please how can I get django to send data to angularjs as it occurs
Related
My POST requests to flask backend only work with JWT_COOKIE_CSRF_PROTECT = False, but GET requests work
config:
CSRF_ENABLED = True
CORS_SUPPORTS_CREDENTIALS = True
JWT_TOKEN_LOCATION = ['cookies']
I access flask through axios from the Vue app
const path1 = `/limit_engine/balance`;
axios
.post(path1, { withCredentials: true })
.then((response) => {
console.log(response.data["balance"]);
})
.catch((error) => {
console.error(error);
});
https://flask-jwt-extended.readthedocs.io/en/stable/options/#jwt-cookie-csrf-protect
suggests JWT_COOKIE_CSRF_PROTECT should be always True in production, so I cannot keep it False then
Try to debug the request by examining headers. If you are sending requests from the browser, you can use any of Dev Tools (Chrome for example). Take a look at the Network tab, look for your POST request, find out which cookies are sent.
If you can't find CSRF token in the request then you should pass it from the backend to the frontend and keep it in cookies storage.
After whole morning having trouble with this I realized CSRF token is only read from request headers as seen here: https://flask-jwt-extended.readthedocs.io/en/stable/_modules/flask_jwt_extended/view_decorators/ not from cookies, so in Vue you need to manually append this header to your requests.
Relevant source code to add to your flask app and to your Vue app:
In flask app:
app.config['JWT_ACCESS_CSRF_HEADER_NAME'] = "X-CSRF-TOKEN"
app.config['JWT_REFRESH_CSRF_HEADER_NAME'] = "X-CSRF-REFRESH-TOKEN"
app.config['JWT_CSRF_IN_COOKIES'] = False
In your flask app login function:
from flask_jwt_extended import (
jwt_required, create_access_token,
jwt_refresh_token_required, create_refresh_token,
get_jwt_identity, set_access_cookies,
set_refresh_cookies, get_raw_jwt, get_csrf_token
)
new_token = create_access_token(identity=current_user.id, fresh=False)
new_refresh_token=create_refresh_token(identity=current_user.id)
response = jsonify({
'data': {
'message':'Ok',
'type': 'user',
'id': current_user.id,
'meta': {
'accessToken': new_token,
'access_csrf_token': get_csrf_token(new_token),
'refreshToken': new_refresh_token,
'refresh_csrf_token': get_csrf_token(new_refresh_token)
}
}
})
set_refresh_cookies(response, new_refresh_token)
set_access_cookies(response, new_token)
return (response)
In your Vue app in your login fuction "edit according if you use or not refresh token logic":
axios.defaults.headers.common['X-CSRF-TOKEN']=response.data.data.meta.access_csrf_token
axios.defaults.headers.common['X-CSRF-REFRESH-TOKEN']=response.data.data.meta.refresh_csrf_token
And lastly do the same in yout Vue TokenRefreshPlugin or the method you use
I guess there are more approaches like getting the CSRF headers from the cookies, but this one seems to work for me for now at least. The important point is adding this headers manually in Vue requests, because using axios.defaults.withCredentials = true is not enough.
Also check header includes csrf token in the requests as akdev suggests.
you can add csrf exception for request.
or follow:-
https://flask-jwt-extended.readthedocs.io/en/3.0.0_release/tokens_in_cookies/
I developed a small prototype in django with one model: Profile, and 2 templates with 2 views (a list of profiles, and an edit profile page), with a form in forms.py. I want to test creating a PWA with Django and this is the additional things I did: 1) pip install django-progressive-web-app, 2) added 'pwa' to installed apps, 3) added a render view for the base.html that will be using the service worker!
def base(request):
return render(request,'app/base.html')
4) added it to the urls:
urlpatterns = [
path(r'', profiles, name="profiles"),
path('user/<pk>', profile, name="profile"),
path('', include('pwa.urls')),
]
5) added this to recognise the service worker:
PWA_SERVICE_WORKER_PATH = os.path.join(BASE_DIR, 'posts/static/js', 'serviceworker.js')
6) added the tags:
{% load pwa %}
<head>
...
{% progressive_web_app_meta %}
...
</head>
7) and added this to a serviceworker.js file, situated in the app/static/js:
var staticCacheName = 'djangopwa-v1';
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(staticCacheName).then(function(cache) {
return cache.addAll([
'/base_layout'
]);
})
);
});
self.addEventListener('fetch', function(event) {
var requestUrl = new URL(event.request.url);
if (requestUrl.origin === location.origin) {
if ((requestUrl.pathname === '/')) {
event.respondWith(caches.match('/base_layout'));
return;
}
}
event.respondWith(
caches.match(event.request).then(function(response) {
return response || fetch(event.request);
})
);
});
What happened is that the service worker is running under Chrome developer tool, but in the django console it displays this error: Not Found: /base_layout, and the homepage is accessible through the Offline mode, but the other path (/user) isn't. And Google Chrome's console displays this error:
The FetchEvent for "http://localhost:8000/manifest.json" resulted in a network error response: the promise was rejected.
Promise.then (async)
(anonymous) # serviceworker.js:19
serviceworker.js:1 Uncaught (in promise) TypeError: Failed to fetch
Also, images are not being loaded.
What did I do wrong?
For the images, add the images url to the array passed to the cache.addAll method. Like so:
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(staticCacheName).then(function(cache) {
return cache.addAll([
'/base_layout',
'/static/img-1.png',
'/static/img-2.png',
]);
})
);
});
To ensure your css and js files load, also add their paths to the array.
I'm working on a react-native-based mobile application and doing some operations with python in the background. I wanted to do both these transactions and connect to the database via Django rest api. But I get connection error.
I have used other rest-api and tried it. I also tried the rest api on the postman and it worked smoothly.
I tried everything, but I couldn't find a solution.
local rest url: http://localhost:8000/api/venues/
and fetch code:
componentDidMount() {
return fetch('http://localhost:8000/api/venues/?format=json')
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
isLoading: false,
dataSource: responseJson,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
also my django setting:
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = [
'http://localhost:3030',
]
CORS_ORIGIN_REGEX_WHITELIST = [
'http://localhost:3030',
]
add these configurations after adding cors as middleware (change to your port number)
https://stackoverflow.com/a/69186898/12497001 provides a very good answer!
As mentioned in the Android Studio documentation, emulators use a special address network (https://developer.android.com/studio/run/emulator-networking.html).
To address requests to your own machine, you can use the address http://10.0.2.2
I am trying to use ReactJS to build a simple website that pulls data from my Django REST Framework API. The issue I am running into, is that my data is not being output by React. I am certain that my Django backend is running flawlessly. I get no errors when running it, and can view my API data via "http://127.0.0.1:8000/api/".
Here is my frontend ReactJS code:
import React, { Component } from 'react';
class App extends Component {
state = {
usernames : []
};
async componentDidMount() {
try {
const res = await fetch('http://127.0.0.1:8000/api/');
const usernames = await res.json();
this.setState({
usernames
});
} catch (e) {
console.log(e);
}
}
render() {
return(
<div>
{this.state.usernames.map(item => (
<div key={item.id}>
<h1>{item.username}</h1>
</div>
))}
</div>
);
}
}
export default App
I have tried updated my CORS_ORIGIN_WHITELIST via settings.py and includes all variations of localhost.
When scripting with Python, I am able to make a request and retrieve my API data. This is the output:
[{'username': 'testname', 'created_at': '2019-12-06T00:03:50.833429Z'}, {'username': 'testname2', 'created_at': '2019-12-06T00:04:01.906974Z'}, {'username': 'testname3', 'created_at': '2019-12-06T00:04:05.330933Z'}, {'username': 'testname4', 'created_at': '2019-12-06T00:04:08.144381Z'}]
And though no ID is present in the output (Which I'm not sure why) I can still access the correct data by making a request like this: "http://127.0.0.1:8000/api/3/"
Any help is appreciated.
Set Access-Control-Allow-Origin: to * just for the purposes of local development. For security reasons you don't want to do that in production, but doing it on your local machine while you're dev'ing is fine. See here if you are unsure of how to: techiediaries.com/django-cors
To solve this issue, I had to install django-cors-headers. This can be done via pip install django-cors-headers
After that, I had to add the following to my settings.py file:
INSTALLED_APPS = [
##...
'corsheaders'
]
MIDDLEWARE_CLASSES = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.BrokenLinkEmailsMiddleware',
'django.middleware.common.CommonMiddleware',
#...
]
CORS_ORIGIN_ALLOW_ALL = True
I'm building a web app with Django on back-end and Backbone.js on front-end
I have problems with IE when I'm trying to fetch data from the server. When I run my HTML page in IE, the collection fetch always invoke the error func.
My code:
$(function(){
var Chapter = Backbone.Model.extend({});
var Chapters = Backbone.Collection.extend({
model: Chapter,
url: 'http://ip.olya.ivanovss.info/chapters'
});
var chapters = new Chapters();
var Router = new (Backbone.Router.extend({
routes: {
"": "choose_activity",
"/": "choose_activity"
},
choose_activity: function () {
chapters.fetch({
success: function () {
AppView.render();
},
error: function() {
alert('error');
}
});
}
}))();
var AppView = new (Backbone.View.extend({
el: '.popup',
templates: {
choose_activity: Handlebars.compile($('#tpl-activities').html())
},
render: function () {
this.$el.html(this.templates["choose_activity"]({ chapters: chapters.toJSON()}));
}
}))();
Backbone.history.start();
});
Django's View:
def chapters(request):
chapters = list(Chapter.objects.order_by('id'))
response = HttpResponse(json.dumps(chapters, default=encode_myway), mimetype='text/plain')
if request.META.get('HTTP_ORIGIN', None) in ('http://localhost', 'http://html.olya.ivanovss.info', 'http://10.0.2.2'):
response['Access-Control-Allow-Origin'] = request.META['HTTP_ORIGIN']
return response
Thank you in advance
IE7 doesn't support CORS.
There are 2 ways around this. The EASY way is Proxy over your API. My Python is rusty (I'm a Node/PHP dev), but I'm sure that there are a million and one resources on how do do this. The good thing about this is you don't have to touch the API. But it means your local server has to CURL and return every single request from your API server.
And second (and much less server intensive way) is JSONP! The idea of JSONP is that it appends a <script> to the document with the URL you specify. jQuery appends a ?callback=jQueryNNN where NNN is a random number. So effectively when the <script> loads, it calls jQueryNNN('The Response Text') and jQuery knows to parse the response from there. The bad thing about this is you have to wrap all of your responses on the API side (which is super easy if you're just starting, not so easy if you already have an infrastructure built out).
The annoying things about JSONP is that by it's nature you can't do a POST/PUT/DELETE. BUT you can emulate it if you have access to the API:
Backbone.emulateHTTP = true;
model.save(); // POST to "/collection/id", with "_method=PUT" + header.
To integrate JSONP with Backbone is pretty simple (little secret Backbone.sync uses jQuery's $.ajax() and the options parameters forwards over to jQuery ;)).
For each one of your models/collections which access a cross origin you can add a su
var jsonpSync = function (method, model, options) {
options.timeout = 10000; // for 404 responses
options.dataType = "jsonp";
return Backbone.sync(method, model, options);
};
In each collection and model what does cross-origin:
var MyCollection = Backbone.Collection.extend({
sync : jsonpSync
});
Or just overwrite the whole Backbone sync
Backbone.__sync = Backbone.sync;
var jsonpSync = function (method, model, options) {
options.timeout = 10000; // for 404 responses
options.dataType = "jsonp";
return Backbone.__sync(method, model, options);
};
Backbone.sync = jsonpSync;
On the server side you can do: this to return a JSONP response (copy pasted here):
def randomTest(request):
callback = request.GET.get('callback', '')
req = {}
req ['title'] = 'This is a constant result.'
response = json.dumps(req)
response = callback + '(' + response + ');'
return HttpResponse(response, mimetype="application/json")