POST 400: Bad request - Using Django REST API and React - django

I'm pretty new to web development so please forgive me in advance for my ignorance.
I'm using React to try to post data to server endpoint managed by Django using this method:
sendData(data) {
const url = "http://127.0.0.1:8080/api/filtros/1/";
const requestOptions = {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
};
fetch(url, requestOptions);
}
On the onClick of a NavDropdown React component:
<NavDropdown.Item
key={item.id}
onClick={() =>
this.sendData({
id: 0,
dimension_id: dimension.id,
item_id: item.id,
usuario_id: 1
})
}
>
{item.descripcion}
</NavDropdown.Item>
This is how I register the url on the router using Django:
router.register('api/filtros/1', FiltroUsuariosViewSet, 'filtro')
My Django ModelViewSet looks like this:
class FiltroUsuariosViewSet(viewsets.ModelViewSet):
queryset = FiltroUsuarios.objects.all()
permission_classes = [
permissions.AllowAny
]
serializer_class = FiltroUsuariosSerializers
And my Django Serializer looks like this:
class FiltroUsuariosSerializers (serializers.ModelSerializer):
class Meta:
model = FiltroUsuarios
fields = ('id', 'dimension_id', 'item_id', 'usuario_id')
def create(self, validated_data):
post = FiltroUsuarios.objects.create(**validated_data)
When I click on the Component I get this:
POST http://127.0.0.1:8080/api/filtros/1/ 400 (Bad Request)
and apparently the error is on the fetch request.
Do you guys have any idea on whats the problem?
Thanks a lot in advance!

The best way to understand and get rid of 400 Bad Request errors when wiring Django and React, is to run Django in development mode and then fire up your browser's Network tab while sending the request.
Switch into the Network -> Response tab and call sendData(). Since you are running on Django's development server, you will get the specific exception on your 400 Bad Request error. To simulate this, see the screenshot below and notice:
{"user": ["Incorrect type. Expected pk value, received str."]}
Back to your problem, you have the following in your .sendData():
x = {
id: 0,
dimension_id: dimension.id,
item_id: item.id,
usuario_id: 1
}
Which you then call JSON.stringify() on. If dimension.id and item_id are both integer (a reasonable assumption), then you're passing the following as a payload:
JSON.stringify(x)
# returns:
"{"id":0,"dimension_id":1,"item_id":2,"usuario_id":3}"
Your Django Model for FiltroUsuarios defined these columns / fields, so you now need to check both your models and FiltroUsuariosSerializers that these are expected value / value types mapping to these columns.

Related

Form POST using Ajax doesn't populate database in Django, but gives success message

VIEW:
class AddFoo(BSModalCreateView):
template_name = 'qualitylabs/add_foo.html'
form_class = AddFooForm
success_message = 'Success: Foo was created'
success_url = reverse_lazy('Home')
FORM:
class AddFooForm(BSModalModelForm):
class Meta:
model = Foo
fields = '__all__'
widgets = {
'part_number': PartNumberWidget,
'operation': OperationNumberWidget,
}
JAVASCRIPT:
function sendToServer(machine, before, after) {
var modified_form_data = before + "&inspection_machine=" + encodeURIComponent(machine) + after
$.ajax({
type: $('#AddFooForm').attr('method'),
url: $('#AddFooForm').attr('action'),
data: modified_form_data,
success: function (data) {
console.log('did it!!!!!')
}
});
}
I'm trying to post a form to the server, which should populate the database. I have to send it in Ajax because I have to iterate multiple times, changing variables each time (poorly set up database). The weirdest thing is that when I run the code, I get:
"POST /add_foo/ HTTP/1.1" 302 0
which is the same result that you get when the server responds properly. The page does not redirect to the success_url, and when I check the data in the admin page, the items have not been added. However, in the admin page I do get the success message of "Sucess: Foo was created"
Any ideas? It's quite strange.
I was copying off of some previous code that had used BSModalModelForm because they were using modal forms, but I wasn't. Once I changed it to CreateView it worked.

Django RF: POST geometry from Leaflet Draw to PostGIS

I'm trying to store some geometry in a PostGIS DB which is created using Leaflet Draw.
The following answer only covers the first part: how to transform the drawn shape into GeoJSON, i.e.:
map.on(L.Draw.Event.CREATED, function (e) {
var type = e.layerType
var layer = e.layer;
// Do whatever else you need to. (save to db, add to map etc)
drawnItems.addLayer(layer);
//Export to DB (source: https://stackoverflow.com/a/24019108/3976696)
var shape = layer.toGeoJSON()
shape_for_db = JSON.stringify(shape);
For example, shape_for_db contains:
{
"type": "Feature",
"properties": {},
"geometry": {
"type":"Polygon",
"coordinates":[[[-0.217073,51.918784],[-0.361362,51.101904],[-0.96918,53.4925],[-0.217073,51.018784]]]
}
}
However, I can't find any solution to successfully insert the geometry in the DB.
So far, based on this, I've tried the following:
$.ajax({
type: "POST",
dataType: "json",
contentType: "application/json",
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
},
url: "/en/api/geomtable/",
data: JSON.stringify({"description":"this is a test", "geom":shape_for_db}),
success : function(result) {
console.log(result);
}
});
This returns a 400 Bad Request with the following error:
Unable to convert to python object: Invalid geometry pointer returned
from "OGR_G_CreateGeometryFromJson"."
What should I make of this error? Should I parse the GeoJSON first or something?
UPDATE:
I narrowed a bit the problem, but still haven't succeeded to store GeoJSON in a PostGIS geometry column.
First, I figured out how to do it via SQL:
INSERT INTO citydb.cityobject (gmlid, objectclass_id, envelope)
VALUES
(
'This is a test insert',
23,
ST_SetSRID(ST_GeomFromGeoJSON
(
'{
"type":"Polygon",
"coordinates":[
[7.814375,52.743552],
[12.9375,51.886624],
[7.375,52.520452]
]
}'
),2056)
)
Next, I confirmed that the Ajax above successfully posts non-geometry data to PostgreSQL (i.e. when I remove "geom":shape_for_db from the posted geojson), and fails as soon as I include the geometry (i.e. I get 400 Bad request).
Therefore, I suppose I have to setup my serializer or something in Django to do the equivalent of ST_SetSRID(ST_GeomFromGeoJSON(...)).
I found that the equivalent in Django should be GEOSGeometry, but I am quite unsure on how/where to set this up.
Could anyone provide some guidance on how to set up this
"geojson-to-geometry" conversion?
And more generally, should I really be doing this conversion in the Django Rest Framework, or are there compelling reasons to do it in the Javascript part, or even directly in the PostgreSQL database (e.g. a function triggered when a geojson is written in the geometry column)?
Currently, my Django/DRF setup is as follows:
views.py
#Viewsets and serializers based on https://www.django-rest-framework.org/tutorial/quickstart/
class CityobjectViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows Cityobject information to be viewed or edited.
"""
lookup_field = 'id'
queryset = Cityobject.objects.all()
serializer_class = CityobjectSerializer
# filter_backends = [DjangoFilterBackend] #allows Django-ORM filters in URL
filter_fields = ('id','gmlid','name',)
urls.py
router = routers.DefaultRouter()
router.register(r'cityobject', views.CityobjectViewSet, 'cityobject')
urlpatterns = [
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
serializers.py
class CityobjectSerializer(GeoFeatureModelSerializer):
class Meta:
model = Cityobject
#Provide only relevant fields for frontend
fields = (
"objectclass",
"gmlid",
"name",
"description",
"envelope",
"creation_date",
"xml_source"
)
geo_field = 'envelope'

Unable to get POST or GET form data while using AJAX

Have been trying to filter data using django-filters. The code is working when I send a separate POST or GET request from the template. I want to avoid that extra reload that's taking place to filter the table of information.
Here's the view:
def search(request):
dynamic_filter = [f.name for f in Controlpanel._meta.get_fields()]
class UserFilter(django_filters.FilterSet):
class Meta:
model = Controlpanel
fields = dynamic_filter
user_list = Controlpanel.objects.all()
user_filter = UserFilter(request.GET.get("filters[]"),
queryset=user_list)
chart = list(user_filter.qs.values())
return JsonResponse(chart, safe=False)
Here's the AJAX code that calls this above view:
$('#filter-data').on('submit', function (event) {
event.preventDefault();
var dynamic = $('#filter-data').serialize();
console.log($('#filter-data').serializeArray())
$.ajax({
url: '/search/',
type: 'GET',
data: {
filters : dynamic
},
dataType: 'json',
success : function(json) {
console.log(json); // log the returned json to the console
console.log("success"); // another sanity check
},
// handle a non-successful response
error : function(xhr,errmsg,err) {
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
The request.GET(or POST) currently stays empty even if I add a CSRF token and make it a POST request.
I came across some question on SO stating that use of request.body solves the issue but even that was a fail.
The issue was that the POST request was being passed as a string.
This solved the issue:
user_filters = request.POST.get('filters', '')
user_filters = user_filters.split("&")
user_filters = {item.split("=")[0]: item.split("=")[1].replace("%20", " ")
for item in user_filters}
user_filters.pop('csrfmiddlewaretoken')

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)

Tastypie Django POST error

I use Tastypie for Django's API. but it returns error.
my code is bellow.
$.ajax({
type : "POST",
url : "http://192.168.1.130:8000/api/user/author/",
data : '{"first_name": "111","second_name": "222"}',
success: function(){
alert('Submit Success')
},
dataType : 'json',
contentType : 'application/json',
processData: false
});
my api.py like this:
class AuthorResource(ModelResource):
class Meta:
queryset = Author.objects.all()
resource_name ='author'
fields = ['first_name','last_name']
filtering = {
'first_name': ALL,
}
authentication = Authentication()
authorization = Authorization()
it returns 200 and post nothing.How can I reslove it?
This is a dupe of Returning data on POST in django-tastypie.
Add always_return_data = True to your Resource meta
If object created successfully, the object uri will be shown in Location field in response headers.
Shouldnt the url be http://192.168.1.130:8000/api/author/ instead of http://192.168.1.130:8000/api/user/author/