Django Rest Framework - Envelope a Paginated Response - django

I want to wrap an paginated response in an envelope. The Result should look like this.
{
"data": ["datum 1", "datum 2", "datum 3"],
"meta": {
"some": "meta",
"data": "foo",
},
"page": {
"total": 12345,
"count": 3,
"from": 3,
"to": 6,
"next": "http://example.com?page=2",
"prev": "http://example.com?page=0",
}
}
The custom page format can be achieved by inheriting from PageNumberPagination.
My question is about passing the Metadata. I do not see any way to pass it to the Pagination except some form of in band signaling. Is there a clean(er) way to do this?

class CustomPagination(pagination.PageNumberPagination):
view = None
def paginate_queryset(self, queryset, request, view=None):
self.view = view
return super().paginate_queryset(queryset, request, view)
def get_meta(self, data=None, **meta):
return {
'data_from_view': self.view.__class__.__name__,
'static_data': settings.ROOT_URLCONF,
'len_per_page': len(data),
'dynamic_data_on_thy_fly': meta
}
def get_paginated_response(self, data, **meta):
return Response({
'links': {
'next': self.get_next_link(),
'previous': self.get_previous_link()
},
'meta': self.get_meta(data, **meta),
'count': self.page.paginator.count,
'results': data
})

Related

django LOGGING - How to change filter attribute name by format

I have the following settings:
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
},
'some_id': {
'()': 'my.special.filter'
},
},
'formatters': {
'json': {
'()': 'my.special.formatter',
'format': '%(thread)d\t%(message)s'
},
...
the filter add "some_id" to the log so the output looks like this:
{"thread": 140155333515008, "message": "some log msg", "some_id": "123456"}
I want to modify the additional attribute "some_id", so the output would look like this:
{"thread": 140155333515008, "message": "some log msg", "some-id": "123456"}
I saw that it can be done with CustomAdapter but I have a lot of "logger = logging.getLogger(...)" so I cant use this.
How can i change the output attribute name?
for now, the solution is as following:
class my.special.formatter(JsonFormatter):
def __init__(self, *args, **kwargs):
super(my.special.formatter, self).__init__(*args, **kwargs)
def format(self, record):
if hasattr(record, 'some_id'):
record.__setattr__('some-id', record.some_id)
record.__delattr__('some_id')
return super(my.special.formatter, self).format(record)
but its not ideal...

how print the function by the location in the list?

data = [
{
'name': 'Instagram',
'follower_count': 346,
'description': 'Social media platform',
'country': 'United States'
},
{
'name': 'Cristiano Ronaldo',
'follower_count': 215,
'description': 'Footballer',
'country': 'Portugal'
},
{
'name': 'Ariana Grande',
'follower_count': 183,
'description': 'Musician and actress',
'country': 'United States'
}]
def dictionary_value():
for value in data:
return value["name"], value["follower_count"],value["description"], value["country"]
Hi, I'm newbie in python and i have a question about dictionary and lists:
i would like that my function dictionary value() will return only the values and print the function by the location in the list, for example: if i want to choose data[2] the outcome should be: 'Ariana Grande', 183,'Musician and actress','United States'. i could not find a way to do it.
Use dict.values method:
def dictionary_value(i):
return list(data[i].values())
Output:
print(dictionary_value(2))
# 'Ariana Grande', 183,'Musician and actress','United States'

Render data passed from Django to Vue

I get my data through axios with this:
get_questions: function (){
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = 'X-CSRFToken'
axios.post('{% url 'sw_app:api_get_questions' %}', this.test)
.then(response=>{
this.questions = response.data.questions
console.log(response.data.questions)
})
}
Here's the view function:
def do_get_questions(request):
data = json.loads(request.body.decode('utf-8'))
test_code = data['code']
is_owner = check_test_owner(request, test_code)
response = {}
if is_owner:
# Get Questions
questions = models.Question.objects.filter(test__code=test_code)
ser_questions = serializers.serialize('json', questions)
response['result'] = 'ok'
response['message'] = 'Questions fetched!'
response['questions'] = ser_questions
return JsonResponse(response)
else:
response['result'] = 'failed'
response['message'] = 'You are not the owner of this test!'
return JsonResponse(response)
It returns this:
[{"model": "sw_app.question", "pk": 2, "fields": {"test": 40, "content": "What is the phrase that beginner coders commonly use to display a string on the screen?"}}]
models.py for reference:
class Question(models.Model):
test = models.ForeignKey(Test, on_delete=models.CASCADE)
content = models.CharField(max_length=900)
def __str__(self):
return "Question: {} - Test: {}".format(self.id, self.test.id)
Back in my vue (template), I store the questions here:
data: {
test: {
code: '',
},
questions: {}
},
Now when I do this:
<li class="list-group-item" v-for="question in questions" :key="question.pk">
[[ question.content ]]
</li>
It just display a lot of empty list objects. When I try doing this:
<li class="list-group-item" v-for="question in questions" :key="question.pk">
[[ question]]
</li>
It displays this:
Any ideas? Thanks a lot!
Suppose you have 2 questions so we can show them using v-for.
const app = new Vue({
data() {
return {
test: {
code: '',
},
questions: [{"model": "sw_app.question1",
"pk": 1,
"fields": {
"test": 40, "content": "Content for question 1"
}
},
{"model": "sw_app.question2",
"pk": 2,
"fields": {
"test": 40, "content": "Content for question 2"
}
}
],
}
},
})
app.$mount("#app")
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<li class="list-group-item" v-for="question in questions" :key="question.pk">
{{ question.pk}} - {{ question.fields.content }}
</li>
</div>

How to post a data with an array field in react request?

So I'm using request from https://github.com/request/request#forms. In tsx file, I'm passing
id: id, text: string, array: number[].
post(
{json: true, url: '...', form: {id: id, text: text, array: array}},
(error, response, body) => {
if (response.statusCode === 400) {
dispatch(errStep(body['text']));
} else {
dispatch(addStep(body));
}
}
)
This is a post method with the body {id: id, text: text, array: array}. However, from Django, when I print the request.data, I receive <QueryDict: {'text': ['hello'], 'id': ['12'], 'array[0]': ['51'], 'array[1]': ['52']}>.
This way, I can't retrieve the array ['51', '52] by calling request.data.getlist('array').
I would like my request.data to be in this format: <QueryDict: {'text': ['hello'], 'id': ['12'], 'array': ['51', '52']}> because [51, 52] is returned by calling request.data.getlist('array').
Thanks!
qsStringifyOptions: {arrayFormat: 'repeat'} as one of the options in post call will transform 'array[0]': ['51'] , 'array[1]': ['53'] to 'array': ['51', '52']

Angular NgRessource with paginated results from django rest framework

My api basically returns something like this:
GET /api/projects/
{
"count": 26,
"next": "http://127.0.0.1:8000/api/projects/?page=2",
"previous": null,
"results": [
{
"id": 21,
"name": "Project A",
...
},
{
"id": 19,
"name": "Project B",
...
},
...
]
}
Using NgResource, I am able to query the api and get the data like this:
var PROJECT = $resource('/api/projects/:id/', {id:'#id'},{
query : {
method : 'GET',
isArray : false
}
});
factory.project_list = function(callback) {
PROJECT.query({},function(project_list){
factory.project_list = project_list.results;
callback();
});
};
My different projects are now available in factory.project_list. The issue here is that each item in factory.project_list are not ngResource items. So I can't call methods such as .$save(), .$update()...
I saw a transformResponse() function but I'm not able to get it working easily...
Do you have any idea what could be the best approach here ?
This is what worked for me:
app.config(['$resourceProvider', function($resourceProvider) {
$resourceProvider.defaults.stripTrailingSlashes = false;
}]);
services.factory('Project', ['$resource',
function($resource) {
return $resource('api/project/:id/', {}, {
query: {
method: 'GET',
url: 'api/projects/',
isArray: true,
transformResponse: function(data, headers) {
return angular.fromJson(data).results;
},
},
});
}
]);