Django - Bad request syntax or unsupported method - django

I want to post data via an api onto my django app. This is how far I got:
import pandas
import requests
excel_data_df = pandas.read_excel('workorders.xlsx')
json_str = excel_data_df.to_json(orient='records', date_format='iso')
API_ENDPOINT = "http://127.0.0.1:8000/api/create/"
API_KEY = "dF8NbXRA.94Mj2xeXT3NZOtx1b575CvNvbs8JWo0D"
data = {'api_dev_key':API_KEY,
'api_option':'paste',
'api_paste_code':json_str ,
'api_paste_format':'csv'}
r = requests.post(url = API_ENDPOINT, data = data)
Django
views.py
class PostDataView(CreateAPIView):
queryset = Workorder.objects.all()
serializer_class = WorkorderSerializer
serializers.py
class WorkorderSerializer(serializers.ModelSerializer):
class Meta:
model = Workorder
exclude = ['id']
urls.py
from django.conf.urls import url, include
from .views import *
from rest_framework.urlpatterns import format_suffix_patterns
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
url(r'^api/chart/data/$', ChartData.as_view(),name="api-data"),
url(r'^api/create/$', PostDataView.as_view(), name='create'),
url(r'^(?P<pk>\d+)/api/delete/$', DeleteDataView.as_view(), name='delete'),
url(r'^(?P<pk>\d+)/api/update/$', UpdateDataView.as_view(), name='update'),
url(r'^$', display_mobiles, name="display_mobiles"),
url(r'^(?P<pk>\d+)$', edit_mobile, name="edit_mobile"),
url(r'^delete/(?P<pk>\d+)$', delete_mobile, name="delete_mobile"),
url(r'^home/$', index, name='index'),
url(r'^sitemap/$', sitemap, name='sitemap'),
url(r'^upload/$', upload, name='upload'),
url(r'^test/$', testview, name='test')
]
if settings.DEBUG:
urlpatterns = urlpatterns + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns = urlpatterns + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns = format_suffix_patterns(urlpatterns)
models.py
class Workorder(models.Model):
label = models.CharField(max_length=200, blank=False)
start = models.DateField()
end = models.DateField()
duration = models.IntegerField()
ctype = models.CharField(max_length=20, default='bar')
werk = models.CharField(max_length=50, default='plant')
product = models.CharField(max_length=50)
train_number = models.IntegerField()
latest_start_date = models.DateField()
latest_start_timebucket = models.IntegerField()
is_start_date_fixed = models.BooleanField()
assigned_start_timebucket = models.IntegerField()
assigned_start_date = models.DateField()
costs_early_start = models.IntegerField()
costs_late_start = models.IntegerField()
resource_overall_demands = models.IntegerField()
resource_timeslots_demands = models.IntegerField()
I can enter the data manually using the post forms # api/create but when I try to post it via the api, I get this error:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Error response</title>
</head>
<body>
<h1>Error response</h1>
<p>Error code: 400</p>
<p>Message: Bad Request.</p>
<p>Error code explanation: 400 - Bad request syntax or unsupported method.</p>
</body>
</html>
This is the data I tried to post:
1)
[
{"id":null,"label":"Workorder 1","start":"2019-01-01T00:00:00.000Z","end":"2019-01-10T00:00:00.000Z","duration":9,"ctype":"bar","werk":"a","product":"a","train_number":535435.0,"latest_start_date":"2019-01-10T00:00:00.000Z","latest_start_timebucket":9,"is_start_date_fixed":false,"assigned_start_timebucket":535435.0,"assigned_start_date":"2019-01-10T00:00:00.000Z","costs_early_start":334,"costs_late_start":334,"resource_overall_demands":334,"resource_timeslots_demands":334},
{"id":null,"label":"Workorder 1","start":"2019-01-01T00:00:00.000Z","end":"2019-01-10T00:00:00.000Z","duration":9,"ctype":"bar","werk":"a","product":"a","train_number":535435.0,"latest_start_date":"2019-01-10T00:00:00.000Z","latest_start_timebucket":9,"is_start_date_fixed":false,"assigned_start_timebucket":535435.0,"assigned_start_date":"2019-01-10T00:00:00.000Z","costs_early_start":334,"costs_late_start":334,"resource_overall_demands":334,"resource_timeslots_demands":334}
]
2)
[
{"id":null,"label":"Workorder 1","start":"2019-01-01T00:00:00.000Z","end":"2019-01-10T00:00:00.000Z","duration":9,"ctype":"bar","werk":"a","product":"a","train_number":535435,"latest_start_date":"2019-01-10T00:00:00.000Z","latest_start_timebucket":9,"is_start_date_fixed":false,"assigned_start_timebucket":535435,"assigned_start_date":"2019-01-10T00:00:00.000Z","costs_early_start":334,"costs_late_start":334,"resource_overall_demands":334,"resource_timeslots_demands":334}
]
3)
{"id":null,"label":"Workorder 1","start":"2019-01-01T00:00:00.000Z","end":"2019-01-10T00:00:00.000Z","duration":9,"ctype":"bar","werk":"a","product":"a","train_number":535435,"latest_start_date":"2019-01-10T00:00:00.000Z","latest_start_timebucket":9,"is_start_date_fixed":false,"assigned_start_timebucket":535435,"assigned_start_date":"2019-01-10T00:00:00.000Z","costs_early_start":334,"costs_late_start":334,"resource_overall_demands":334,"resource_timeslots_demands":334}
4)
{"id":1}
Thank you for any help

When you do requests.post(url = API_ENDPOINT, data = data) it sends yoru data as form data.
It looks like you are trying to send data in a format which your API doesn't accept.
I think your API is configured to accept only JSON but you are trying to send it as form data.
Check settings from the docs at https://www.django-rest-framework.org/api-guide/parsers/#setting-the-parsers
Also you can try to post your data as JSON strings using requests.post(..., json=payload). Reference https://requests.readthedocs.io/en/master/user/quickstart/#more-complicated-post-requests

I don't understand what the api_... are referring to.
But given the error message, it seems that your client is not sending a proper request.
One usefull way of debugging this is to try to make it work first with generated code from the devtools:
Go to the browsable API from DRF
Open devtools, go to Network, select All
Make your POST via the browsable API
Find the corresponding request in the devtools, right click on it and select copy as fetch or copy as curl
Then try to run it on a browser (for fetch) or in bash (for curl) and see if it works.

Related

django: download filtered data as csv

Hej!
I want to download my data as a csv file.
My problem is that I can't get my filters applyed in the downloaded csv, it'll always give me the whole list.
I tried to connect the two functions but it doesn't work as expected. But they both run fine on their own.
Does anyone know how to achieve that? Or knows what I'm doing wrong?
Any help is appreciated! :)
# views.py
def download_csv(request):
institutions = Institution.objects.all()
filter = InstitutionFilter(request.GET, queryset=institutions).qs
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="institutions.csv"'
writer = csv.writer(response)
writer.writerow(['Name', "Abbreviation", "Parent Institution", "Phone Number"])
for institution in filter.values_list('name', 'abbreviation', 'parent_institution__name', 'contact_details'):
writer.writerow(institution)
return response
# filters.py
class InstitutionFilter(django_filters.FilterSet):
name = CharFilter(field_name="name", lookup_expr="icontains")
class Meta:
model = Institution
fields = "__all__"
I had to add the filter parameter to the url to get them working. So the solution lies in the template rather then in the views :)
<div class="col">
Download CSV
</div>
EDIT:
#csv_download/urls.py
app_name = "csv_download"
urlpatterns = [
path("export-institution/", download_csv_institution, name="download_institutions"),
]
# general urls.py
urlpatterns = [
path("admin/", admin.site.urls, name="admin"), # admin site
path("download_csv/", include("csv_download.urls")), # download app
]

Testing a query parameter in django restframework

I am testing a query parameter in djnago restframework to retrieve the detail of an object. The query works in the browser but not the test. I think I am not calling the response correctly with:
response = self.client.get(reverse('quote-requests:get-calculator-detail', kwargs={'calculator_code': self.calc1.calculator_code}))
the apps urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('api/v1/quote-requests/', include('quote_requests.urls')),
]
which includes the quotes.urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from quote_requests import views
router = DefaultRouter()
router.register('get-calculator', views.CalculatorCodeDetailViewSet, basename='get-calculator')
app_name = 'quote-requests'
urlpatterns = [
path('', include(router.urls)),
]
The viewset is:
class CalculatorCodeDetailViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = CalculatorCodeSerializer
lookup_field = ('calculator_code')
def get_queryset(self):
return (
Calculator.objects.filter(
calculator_code = self.request.query_params.get('calculator_code',)
)
)
The CalculatorCodeSerializer is:
class CalculatorCodeSerializer(serializers.ModelSerializer):
class Meta:
model = Calculator
fields = (
'name',
'calculator_code',
)
The test is:
def test_retrieving_calculator_detail_with_calculator_code(self):
''' test retrieving detail of a calculator '''
self.calc1 = Calculator.objects.create(
name = "Calculator 1000",
calculator_code = "HH1000",
)
response = self.client.get(reverse('quote-requests:get-calculator-detail', kwargs={'calculator_code': self.calc1.calculator_code}))
serializer = CalculatorCodeSerializer(self.calc1)
self.assertEqual(response.data, serializer.data)
This yields the error:
Traceback (most recent call last):
File "/app/quote_requests/tests/test_calculators_api.py", line 149, in test_retrieving_calculator_detail_with_calculator_code
self.assertEqual(response.data, serializer.data)
AssertionError: {'detail': ErrorDetail(string='Not found.',[14 chars]nd')} != {'name': 'Calculator 1000', 'calculator_cod[368 chars].25'}
When checking the browser link:
http://localhost:8000/api/v1/quote-requests/get-calculator/?calculator_code=HH1000
This works but test fails. Any help setting up the properly would be appreciated.
I think you are using the wrong endpoint name replace this "get-calculator-detail" with this "get-calculator"
def test_retrieving_calculator_detail_with_calculator_code(self):
# test retrieving detail of a calculator
self.calc1 = Calculator.objects.create(
name = "Calculator 1000",
calculator_code = "HH1000",
)
response = self.client.get(reverse('quote-requests:get-
calculator', kwargs={'calculator_code':
self.calc1.calculator_code}))
serializer = CalculatorCodeSerializer(self.calc1)
self.assertEqual(response.data, serializer.data)
With the help of others on Fiverr I have gotten the test to pass. I hesitate to call it answered but I am putting the detail here in case those who know a better way can comment.
TLDR - the response variable was not written correctly either the reverse does not do what I want or it cannot be done with reverse. Either way the change that worked was:
response = self.client.get('/api/v1/quote-requests/get-calculator/', {'calculator_code': self.calc1.calculator_code})
This does not return an iterable object. It returns an OrderDict which looks like this:
[{"name":"Calculator 1000","calculator_code":"HH1000","id":7,}]
I used print(response.content) to check this.
so you need to use the json function to pull the data out and match it to serializer.data - the response from the serializer.
response.data = response.json()[0]
this pulls the "[]" off and formats it like this:
{'name': 'Calculator 1000', 'calculator_code': 'HH1000', 'id': 7, }
The [0] on the end gets the object (I think) and returns it in json format.
The two fiverr users that helped me with this were:
https://www.fiverr.com/tailongk
and
https://www.fiverr.com/asipita

Django Rest Framework Reverse() Method Fails

My main urls.py is located here ahlami -> ahlami -> urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('api/accounts/', include('accounts.api.urls')),
]
My accounts app urls.py is located here ahlami -> accounts -> api -> urls.py
urlpatterns = [
path('users/<int:pk>/', views.UserView.as_view(), name='user-detail')
]
One of my accounts views.py returns
token = Token.objects.create(......)
return Response(data=AnonymousUserTokenResponseSerializer(instance=token).data)
My token model has three fields only. For simplicity, I listed one field below
class Token(rest_framework.authtoken.models.Token):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE
AnonymousUserTokenResponseSerializer is linked to the Token model and returns three json attributes
class AnonymousUserTokenResponseSerializer(serializers.ModelSerializer):
user_id = serializers.ReadOnlyField(source='user.id')
user_url = reverse(viewname='user-detail')
class Meta:
model = Token
fields = ('key',
'user_id',
'user_url')
AnonymousUserTokenResponseSerializer fails because it can't identify reverse()
user_url = reverse(viewname='user-detail')
python manage.py runserver throws the error below because of the line above
django.core.exceptions.ImproperlyConfigured: The included URLconf
'ahlami.urls' does not appear to have any patterns in it. If you see
valid patterns in the file then the issue is probably caused by a
circular import.
My settings is located here ahlami -> ahlami -> settings -> base.py and base.py has this
ROOT_URLCONF = 'ahlami.urls'
I expect to get an output that looks like but couldn't because of the error above.
{
"key": "891e388399f2fcae016fe6887107034239041478",
"user_id": 29,
"user_url": http://localhost/api/accounts/users/29
}
How can I resolve this error and make reverse() work?
django.core.exceptions.ImproperlyConfigured: The included URLconf
'ahlami.urls' does not appear to have any patterns in it. If you see
valid patterns in the file then the issue is probably caused by a
circular import.
Use serializers.HyperlinkedIdentityField
class AnonymousUserTokenResponseSerializer(serializers.ModelSerializer):
user_id = serializers.ReadOnlyField(source='user.id')
user_url = serializers.HyperlinkedIdentityField(
view_name='user-detail',
source='user.id',
lookup_field='pk'
)
class Meta:
model = Token
fields = ('key', 'user_id', 'user_url')

Django REST framework RetrieveAPIView gets empty "id" parameter and returns 404 error

I use Django 1.11 + Django REST Framework. I'm trying to get detailed data about distinct record using generic RetrieveAPIView from Django REST Framework and server returns "HTTP 404 Not Found" result, i.e. no data.
models.py file:
class TestPage( models.Model):
title = models.CharField( size = 120)
counter = models.IntegerField( default = 0)
def __unicode__(self):
return u'' + self.title
serializers.py file:
class TestPageSerializer(serializers.ModelSerializer):
class Meta:
fields = ('id', 'title', 'counter',)
model = models.TestPage
urls.py file:
urlpatterns = [
url( r'^admin/', admin.site.urls),
url( r'^api/', include( 'rest_framework.urls')),
url( r'^api/', include( 'testpages.urls')),
]
testpages/urls.py file:
urlpatterns = [
url( r'^$', views.TestPageList.as_view()),
url( r'^(?P<id>)\d+/$', views.TestPageDetail.as_view()),
]
and at last views.py file:
class TestPageList(generics.ListAPIView):
lookup_field = 'id'
queryset = TestPage.objects.all()
serializer_class = TestPageSerializer
class TestPageDetail(generics.RetrieveAPIView):
lookup_field = 'id'
queryset = TestPage.objects.all()
serializer_class = TestPageSerializer
# def get_object( self):
# print self.kwargs
If I request "http://127.0.0.1:8000/api/" for all records in the list, server returns all records. But if I want to get record by id using "http://127.0.0.1:8000/api/1/" for example, I get the empty result like in the photo below.
[![enter image description here][1]][1]
If I uncomment get_object()-function in last 2 lines, I can see {'id': u''} in terminal i.e. server gets empty parameter 'id'.
What wrong with this code?
The issue is your regular expression matching for id, you're putting \d+ outside of the matching group when it's actually what you want to match:
url(r'^(?P<id>\d+)/$', views.TestPageDetail.as_view())
By the way, to be good REST citizen, you shouldn't add the / at the end of a URL for a specific object.
Note: As mentioned by JPG, adding a name for the resource you're fetching (plural) would be proper RESTful:
url(r'^pages/(?P<id>\d+)$', views.TestPageDetail.as_view())
This way, you fetch page nr. 1 at /api/pages/1
The original problem was the closing parathesis (the regex expression), you were misplaced that.
urlpatterns = [
url(r'^$', views.TestPageList.as_view()),
url(r'^(?P<id>\d+)/$', views.TestPageDetail.as_view()),
^^^ here
]
Apart from that, You should change the urls patterns to a sensible form, as
#testpages/urls.py
urlpatterns = [
url(r'^test/$', views.TestPageList.as_view()),
url(r'^test/(?P<id>\d+)/$', views.TestPageDetail.as_view()),
]
then the list-api will be available on /api/test/ endpoint and the detail-api will be available on /api/test/{id}/

How to upload image to custom location using models.ImageField and attribute?

I am an absolute beginner with Django so here is my question:
I created a model and I have image = models.ImageField(). When I use the admin interface, every uploaded image is placed in the root directory.
I read through this https://docs.djangoproject.com/en/dev/topics/files/ and if I use the below example it still doesn't work.
from django.core.files.storage import FileSystemStorage
fs = FileSystemStorage(location='/static/images/gallery')
class Car(models.Model):
...
photo = models.ImageField(storage=fs)
The new entry is correctly added but when I click the image name, the following error is displayed, and the image is not placed in /static/images/gallery
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/admin/Library/book/12/change/002_user_experience_remastered.jpg/change/
Raised by: django.contrib.admin.options.change_view
book object with primary key '12/change/002_user_experience_remastered.jpg' does not exist.
You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.
My code as I wrote it:
from django.core.files.storage import FileSystemStorage
fs = FileSystemStorage(location='/static/images/gallery')
class book(models.Model):
name = models.CharField(max_length=128, unique=True)
authors = models.CharField(max_length=128)
language = models.CharField(max_length=128)
otherDetails = models.URLField()
availableCopies = models.IntegerField()
borrowUntilDate = models.DateField()
image = models.ImageField(storage=fs)
commentName = models.CharField(max_length=128)
commentText = models.CharField(max_length=2048)
slug = models.SlugField(unique=True)
My project has the following configuration:
..\Services
Services
Library (my app)
static
templates
venvs
From the admin interface I load pics from C:\pics and I want them to be stored in ..\Services\Library\static\images\gallery folder.
What am I doing wrong? What am I missing?
Thank you!
From the documentations:
During development, you can serve user-uploaded media files from MEDIA_ROOT using the django.contrib.staticfiles.views.serve() view.
This is not suitable for production use! For some common deployment strategies, see Deploying static files.
For example, if your MEDIA_URL is defined as /media/, you can do this by adding the following snippet to your urls.py:
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# ... the rest of your URLconf goes here ...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
You need to specify the absolute path of your folder in the FileSystemStorage location and also provide a base_url if you have not set MEDIA_URL in settings.
fs = FileSystemStorage(
location='C:/.../Services/Library/static/images/gallery',
base_url='/gallery/'
)
References:
FileSystemStorage