Sending Django requests to NextJS with data - django

I am looking at integrating NextJS into an existing Django project. The project makes heavy use Django templates for most of its pages and I am looking at modernising the project by taking advantage of React and building out a design / component system. The idea is that we would look at replacing Django with NextJS eventually.
I have been able to use Django to proxy a request through to NextJS, and it works great! I have also been able to send data directly to the NextJS route so that I do not have to call back to Django to get data. This approach annoyingly has the limitation of only sending key/value data.
Here is the working code.
# django
def get(self, request, *args, **kwargs):
data = request.GET
return self._handle_request(data, requests.post)
def _handle_request(self, data, make_request):
data = {"hello": "world"}
response = make_request("http://localhost:3000", data=data)
return HttpResponse(response)
//nextjs
import parse from "urlencoded-body-parser";
export async function getServerSideProps(context) {
const { req } = context;
const props = await parse(req);
return { props };
};
So with this in mind, is there a better way to achieve sending data to a NextJS route without having to do a callback?

After some research I was able to achieve this by using application/json content type.
class NextJsView(WhiteLabelMixin, View):
def get(self, request, *args, **kwargs):
data = request.GET
return self._handle_request(data, requests.post)
def _handle_request(self, data, make_request):
data = {"hello": {"dark": "world"}}
response = make_request("http://localhost:3000", json=json.dumps(data))
return HttpResponse(response)
import getRawBody from "raw-body";
export async function getServerSideProps(context) {
const { req } = context;
let props = {};
if (req.method == "POST") {
const body = await getRawBody(req);
props = JSON.parse(JSON.parse(body));
}
return { props };
}

Related

Pass List of UUID to django endpoint url as param

I have this code
#VIEWS
def report_pdf(request, queryset):
if request.method == "GET":
trans = Transaction.objects.filter(id__in=queryset)
return something
#URLS
path("pdf/<uuid:queryset>", views.report_pdf, name="get_pdf")
#FRONT END
const handlePDFDownload = (ids) => {
const body = ids
axios.get(`/calc/pdf/`,body , {
responseType: 'blob',
}).then(res => {
fileDownload(res.data, 'filename.zip');
console.log(res, 'downloading');
}).catch(err => {
console.log(err);
})
}
Now from my frontend react iam sending a get request to this endpoint with a list of UUID values.
I cant find a way to access that list in my view coming from frontend.
Would appreciate any suggestions!
I would suggest you pass the uuids as query params to the url as
../pdf?queryset=<uuids here>
then get the list in your view as
queryset = request.GET.get('queryset')
and then use queryset further in view.
You are sending list of uuid's from frontend but in your urls expects one uuid so that you need to change it like this:
urls.py:
path("pdf/", views.report_pdf, name="get_pdf")
views.py:
def report_pdf(request):
if request.method == "GET":
uuid_list = request.GET.getlist("queryset[]")
trans = Transaction.objects.filter(id__in=uuid_list)
return something

Django - Passing a json or an array in URL for an API call

I want to pass a number off variables (either as a JSON or Array) via an API, such as:
{'age': 35, 'gender':'female', ...etc}
I am not sure how to pass this information into the Djano URL. I could set up individual parameters in the URL, but I got quite a few to pass. there must be an easier way of doing it
SOLUTION:
Solved by switching of a POST Call in the API and setting up the serializers for each variable so that they can be passed through the request.
I am using axios to make calls from django backend. In my case I can do:
js.file:
function search(token, status, q) {
return (dispatch) => {
dispatch(start(token));
axios
.get(`${serverIP}/invoices/sales-invoice/`, {
params: {
status: status,
q: q,
},
})
.then((res) => {
dispatch(successSearch(res.data, status));
})
.catch((err) => {
dispatch(fail(err));
});
};
}
Here I am sending 2 params, but you can actually send object, for example user info.
And than in views get them
views.py:
def list(self, request, *args, **kwargs):
status = request.query_params.get('status')
q= request.query_params.get('q')
These is exapmple with DRF model viewset

How to Sync Django HTTP Login Session with Websocket Session/Cookie?

I am using Django DjangoChannelsGraphqlWs which is Graphene version of Django Channels. (https://github.com/datadvance/DjangoChannelsGraphqlWs) It allows me to transfer data using graphql style. I wrote a login login on my mutation schema.
class Login(graphene.Mutation):
class Arguments:
email = graphene.String()
password = graphene.String()
ok = graphene.Boolean()
user = graphene.Field(UserType)
def mutate(root, info, email, password, **kwargs):
ok = False
user = authenticate(info.context, username=email, password=password)
if user is not None:
login(info.context, user)
update_or_create_user_login_info(info=info)
ok = True
return Login(ok=ok, user=user)
else:
return Login(ok=ok)
And I wrote my client side Websocket using Apollo-client like this:
class WebSocketService {
static instance = null;
callbacks = {};
static getInstance() {
if (!WebSocketService.instance)
WebSocketService.instance = new WebSocketService();
return WebSocketService.instance;
}
constructor() {
this.socketRef = null;
this.connect();
}
connect() {
const client = new SubscriptionClient(BASE_URL + '/graphql/', {
reconnect: true,
});
const link = new WebSocketLink(client);
const cache = new InMemoryCache();
this.socketRef = new ApolloClient({
link,
cache,
});
}
query = (query, variables={}, context={}, fetchPolicy='no-cache', errorPolicy='all') =>
this.socketRef.query({
query: gql`${query}`,
variables,
context,
fetchPolicy,
errorPolicy
})
mutate = (mutation, variables={}, context={}, fetchPolicy='no-cache', errorPolicy='all') =>
this.socketRef.mutate({
mutation: gql`${mutation}`,
variables,
context,
fetchPolicy,
errorPolicy
})
}
const WebSocketInstance = WebSocketService.getInstance();
export default WebSocketInstance;
Lastly, here is my consumer.
class MyGraphqlWsConsumer(channels_graphql_ws.GraphqlWsConsumer):
"""Channels WebSocket consumer which provides GraphQL API."""
schema = schema
send_keepalive_every = 60
I attempted to log in using the WebSocketInstance. However, Django's login function fails when I hand over info.context and authenticate(info.context, user) parameters. It throws error saying "types.SimpleNamespace' object has no attirbute 'META'". After stumbling upon with the error, I gave up with logging in with a websocket and decided to just use axios and normal http request.
But here is another issue. The session and cookies are not synced. When I use axios and normal http request, the login itself does work well, but websocket connection does not reflect the logged in session/cookies.
I found that it takes some time to reflect the change and it happens after disconnecting and reconnecting the websocket.
How should I sync the login information?
try overing the graphl_jwt
class ObtainJSONWebToken(graphql_jwt.JSONWebTokenMutation):
user = graphene.Field(UserType)
session = graphene.String()
#classmethod
def resolve(cls, root, info, **kwargs):
user=info.context.user
if user:
login(info.context,user)
session=info.context.session
session.save()
if session.session_key:
#print(session.session_key)
return cls(user=user,session=session.session_key)
else:
raise Exception('try it again')
in mutation
class Mutation(graphene.ObjectType):
token_auth=ObtainJSONWebToken.Field()

AngularJS/Django Post Response Data

I'm using AngularJS for the front-end and Django for the backend of a web app I'm working on. Right now I'm working on logging in users and I'm having a strange problem. Heres the relevant Angular code:
app.factory('AuthService', ["$http", "$q", "Session", "URL", function($http, $q, Session, URL) {
return {
login: function(credentials) {
var deferred = $q.defer();
$http.post(URL.login, credentials)
.then(function(data, status, headers, config) {
data=data.data; //WHY DOES THIS WORK?
if (data.success == true) {
alert("logged in");
Session.create(credentials.username, data.api_key);
deferred.resolve();
}
else {
deferred.reject("Login failed!");
}
}, function(data, status, headers, config) {
deferred.reject("Login failed!");
});
return deferred.promise
},
And here is the corresponding Django view:
def login_user(request):
'''
Given a username and password, returns the users API key.
'''
if request.method == 'POST':
username = request.POST.get('username',None)
password = request.POST.get('password',None)
user = authenticate(username=username,password=password)
if user is not None:
api_key = ApiKey.objects.get(user=user)
response_data = {}
response_data["api_key"] = str(api_key).split(" ")[0]
response_data["success"] = True
return HttpResponse(json.dumps(response_data), content_type="application/json")
else:
return HttpResponse(json.dumps({"username":username,"success":False}),content_type="application/json")
return HttpResponseBadRequest()
When the user logs in a POST request is sent and handled by the above Django code. The response is then picked up by the AngularJS code above. As you can see the then() method in the Angular code takes the usual four parameters: data, status, config and headers. I expect to see data contain the dictionary output from the Django code, appropriately serialized into a JSON object.
However what happens is that the only parameter of the then() method which is not undefined is data, and this contains EVERYTHING; headers, data, status code,etc.
The line commented 'WHY DOES THIS WORK' fixes the problem, by accessing the data inside. However, I want to know why this is happening and if there is any way to avoid this. My best guess is that it has something to do with the way Django serializes a response but I'm not sure.
I'm using Django 1.6.5.
That is actually how Angular promises work according to the docs. Here is the relevant quote.
Since the returned value of calling the $http function is a promise,
you can also use the then method to register callbacks, and these
callbacks will receive a single argument – an object representing the
response. See the API signature and type info below for more details.
The emphasis was mine.

can't call django json view with angularjs

i'm new in django and also in angularjs.
I wants to use Django for a REST api and angularjs for frontend view.
I have a django view that returns a json response:
class MyView(View):
def get(self, request):
data = serializers.serialize('json', MyModel.objects.order_by('name'))
return HttpResponse(data, mimetype='application/json')
def options(self, request):
response = HttpResponse()
response['allow'] = ','.join(['get', 'post', 'put', 'delete', 'options'])
return response
calling
http://localhost:8000/myapp/myview
i get the right json response
If in an angularjs controller (controllers.js) i try to call that view like this:
angular.module('myApp.controllers', []).
controller('MyCtrl', ['$scope', '$http', function($scope, $http) {
$scope.test = "Hola";
delete $http.defaults.headers.common['X-Requested-With'];
$http.get('http://localhost:8000/myapp/myview').success(function(data) {
$scope.results = data;
console.log(data);
}).error(function(data, status) {
$scope.data = data || "Request failed";
$scope.status = status;
console.log(data);
});
}]);
"test" value is correctly printed in the template
in django log i have: "GET /myapp/myview/ HTTP/1.1" 200 853
but in angular i don't retrieve any data. If i put a break point in error method, i have data empty and status = 0.
Any hints?
Am i missing something?
Been struggling with the same. The problem is with CORS. The solution is here
$http.get('http://localhost:8000/myapp/myview/').success(function(data)
The URL needs to drop the trailing /, then append .json. Like so:
$http.get('http://localhost:8000/myapp/myview.json').success(function(data)