How to use Django's APIRequestFactory with an array of objects? - django

I have the following test
def test_bulk_post(my_faker,factory):
snippets = [{'code':'print(True)'},{'code':'print(True)'},{'code':'print(True)'}]
assert factory.post('/snippets/',snippets) == True
I am trying to extend the snippets app in the tutorial to accept multiple code objects in a single post request.
Right now this gives me:
/venv/lib/python3.8/site-packages/django/test/client.py(244)encode_multipart()
*** AttributeError: 'list' object has no attribute 'items'
so its not expecting a list.. But I want to give it one. How do I do that?

factory.post by default expects a key, value pairs that goes with multipart/form-data and not list hence error
You should probably set content_type='application/json' to pass data as JSON body
factory.post('/snippets/',snippets, content_type='application/json )

Related

Django Rest Framework - Object of type <> is not Json seralizable

I'm new to django rest framework and need some help.
I have ApiView:
class SomeApiView(APIView):
def get_url(self, some_id):
return generate_url(Choices.BOOK, some_id)
def get(self,request):
id = request.query_params.get("some_id")
result_url = self.get_url(id)
return Response({'result_url': result_url})
here when sending request I get next error:
Object of type Choices is not Json serializable.
Choices looks like this:
class Choices(Enum):
BOOK="book"
MOVIE="movie"
GAME="game"
how can I fix this error? Thank you in advance
The error is saying that Choice is not able to be converted to json. Your ideal outcome is {'result_url': 'book'} for example (I assume), but right now it's {'result_url': Choice} which cannot be converted to json.
My point is that instead of Choice you need to return something json serializable (like a string). My best guess is that you need {'result_url': result_url.value}, but I do not know if this will work as I do not know the rest of your code.

what's the value type of the value of request.POST in django?

This is from print(request.POST)
<QueryDict: {'csrfmiddlewaretoken': ['2Tg4HgJ07qksb3hPUDWSQYueYOjYOkQcmzll9fnjbJ0GZHkWHdM8DtYqZB4uv3Fv'], 'username': ['boycececil'], 'password': ['password']}>
This is from print(request.POST.get('username'))
boycececil
So as you can see, list (from one of the values of QueryDict)-> string(from the get function), that's magic! Isn't it?
So, somebody know what's going on?
What the value type of the value of request.POST in django?
The type is django.http.request.QueryDict
So as you can see, list -> string, that's magic! Isn't it?
No, it isn't magic. This is just the documented behavior of QueryDict:
"QueryDict.__getitem__(key)
Returns the value for the given key. If the key has more than one value, it returns the last value. ..."
Note: if you want all values for a key, you can call getlist(key) on the QueryDict.
So, the request.POST is a subclass of the dictionary but not a raw dictionary.
It is a subclass of the django MultiValueDict class which is a subclass of dict.
When I call get(key) to the Querydict it return the last value of the list. Sounds like the get method in Querydict overwrite the get method in the raw dictionary.
Yes ... that is what the __getitem__ method does.
By the way, I wonder why we need multiple value for one key.
It is because HTTP allows multiple values for a given parameter in a request. So if multiple values can be provided, django need to be able to make them available via the HttpRequest.POST object.
But since this is an unusual case, they decided to just give your code one value for each parameter ... unless it specifically asks for them all. Django is being helpful.

How to call a function from views.py to tasks.py?

I'm trying this: but its throwing an TypeError: auto_sms() missing 1 required positional argument: 'request' error.
Now I'm thinking of getting the function from views.py instead and calling it on tasks.py if requests is not working on tasks.py, how can I do it? Thanks!
#shared_task
def auto_sms(request):
responses = Rainfall.objects.filter(
level='Torrential' or 'Intense',
timestamp__gt=now() - timedelta(days=1),
)
count = responses.count()
if not (count % 10) and count > 0:
send_sms(request)
return
Passing the entire request is probably not a good idea since it can include Django model objects such as a user object. Now the problem that you will face is that if there is an object that is not serializable, then you'll get an error while calling the function. So instead of passing the whole request, just send the data that you actually need.
For example, I'm guessing you need the user here to send an SMS to. So instead of passing the whole request with the user object included, then just send the user_id and then get the user there. basically, you have to make sure that the data you're passing is serializable.
It's generally a good idea to pass ids of the Django models since the data might change while your function is being processed and you might get the old data if you pass the whole data.

Django request.body always printing nonsense result (b'')

I am new to django , I started working on an existing Vuejs/Django project to easily understand how things are working .
I wrote a new specific view in views.js
def hello(request):
print(req.body)
return HttpResponse('hello')
Then in urls.py I added the following:
path('hello/',views.hello,name='hello')
At first I tried sending a plain/text , but the print function shows the following
b''
I tried printing request.data but it says
WSGIRequest' object has no attribute 'data'
I tried sending a JSON and using the following :
body_string = request.body.decode("utf-8", "ignore")
data = json.loads(body_string)
Result :
Expecting value: line 1 column 1 (char 0)Expecting value:
or:
data = json.loads(request.data.get('_content'))
Result:
'WSGIRequest' object has no attribute 'data'
none of that seems to be working .
The app I am working on seems to be working fine but it has no specific URL that's way I am stuck as I have no example , even here I couldn't find anything that helps.

TypeError: expected string or bytes-like object User.id

I'm trying to register an new Transaction object on the DB using Django, but I'm having TypeError: expected string or bytes-like object when I try to do user_id = user.id I can't really understand why this is happening, since I do the same steps when registering a new Bank object (as shown on prints below). I've tried to debug and the local variables have the correct value, I've also tried to cast user.id with string or int, but none of them worked.
traceback console error create Transaction method create Bank method
models.py
Firstly, please don't post code or errors as images; they are text, they should be posted as text in the question.
However I don't see anything in any of those snippets that suggest the error is with the user - that line is probably highlighted because it's the last in that multi-line call.
Rather, the error looks to be in the reference to date.today - if that's the datetime.date class, then today is a method, which you would need to call:
Transaction.objects.create(date=date.today(), ... )
Or, since that field has a default anyway, you could leave out the date attribute from the create call altogether.