Tastypie Adding Custom Values (conditionally) - django

I have a Complex Django model with (1) alot of fields and (2) dynamically generated data for this model that is not stored on the model.
Comlex Resource:
class ComplexResource(resource):
class Meta:
allowed_methods = ('get','put','post','delete','patch')
queryset = Complex.objects.all()
serializer = CustomSerializer()
authorization = Authorization()
authentication = Authentication()
always_return_data = True
filtering = { "field_1" : ALL, "field_2" : ALL, "field_N" : ALL }
ordering = ["field_1", "field_2", "field_n"]
Currently, my Complex endpoint /m/api/v1/complex/ successfully returns STORED data on the model.
Complex Response:
{ "meta": {
"limit": 20,
"next": null,
"offset": 0,
"previous": null,
"total_count": 1
},
"objects": [
{"field_1": "foo", "field_2": "bar", ... , "field_n": "foobar"}
]
}
Problem:
What I would like to do is to use prepend_urls to add a custom endpoint which will return all of the data. This way I wouldn't have to use dehydrate wastefully adding data every time I called my current endpoint which can be seen here:
http://django-tastypie.readthedocs.org/en/latest/cookbook.html#adding-custom-values
Question
How do I go about creating a prepend_url which injects additional data into a resource? or is there a better design pattern for solving this altogether?
Complex Response w/all data: /m/api/v1/complex/all/
{ "meta": {
"limit": 20,
"next": null,
"offset": 0,
"previous": null,
"total_count": 1
},
"objects": [
{"field_1": "foo",
"field_2": "bar",
.
.
.
"field_n": "foobar",
"advanced_field_1 : "a1",
"advanced_field_2 : "a2",
.
.
.
"advanced_field_n : "an",
}
]
}

I think dehydrate was made for cases like yours. Add query set argument to determine that dehydrate should compute addition fields or not.
def dehydrate(self, bundle):
if bundle.request.GET.get('attach_dynamic_fields'):
bundle.data['my_dynamic_field_1'] = make_dynamic_field(1)
bundle.data['my_dynamic_field_2'] = make_dynamic_field(2)
return bundle
Then just use when needed:
/api/v1/complex/ # Gives all, no dynamic fields attached
/api/v1/complex/1/ # Gives one, no dynamic fields attached
/api/v1/complex/?attach_dynamic_fields=1 # Gives all, with dynamic fields
/api/v1/complex/1/?attach_dynamic_fields=1 # Gives one, with dynamic fields
Creating prepend_url doesn't make sense for me. Because it means rewriting Tastypie again. Which is sign that something here is not RESTful.
If you want to do it anyway you should take a look on dispatch method and its flow:
Flow through request / response cycle
You will have to rewrite this: dispatch method in your prepend_url somehow.

Related

django-rest-framework-datatables and Django Parler's translation field

I've got model with translated fields.
class Device(TranslatableModel):
translations = TranslatedFields(name=models.CharField(max_length=100))
I made a serializer like:
class DeviceSerializer(TranslatableModelSerializer):
translations = TranslatedFieldsField(shared_model=Device)
class Meta:
model = Device
fields = ('translations',)
It gives me nice JSON like it should.
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"device": {
"translations": {
"en": {
"name": "Sample Device"
}
}
}
}
]
}
Now i want to use it with django-rest-framework. In my template I've written script like:
$('#devices').DataTable({
'serverSide': true,
'ajax': 'api/devices/?format=datatables',
'columns': [
{'data':'device.translations.en'}
It refuses to work with me. I am getting django.core.exceptions.FieldError: Unsupported lookup 'en' for AutoField or join on the field not permitted.
If I am not appending .en to {'data'} it gives Object.object of course.
Issue is in template file.
Pass name & data field separately to columns in data-table configuration
please replace field_name with your model field name
$('#devices').DataTable({
'ajax': 'api/devices/?format=datatables',
'columns': [
{"data": "translations.en.field_name" , "name": "translations.field_name"},
]
});
for more details refer django-rest-framework-datatables
& Django-parler-rest
The actual problem is that while making get request to server
data-table will add name value in column parameter so
instead of writing
"name": "translations.en.field_name"
write down:
"name": "translations.field_name"
remove language code

How to change DRF to use a Response from a schema?

Is it possible to change the Django Rest Framework to use a Response from a schema?
For example, a GET using the standard DRF will output:
{
"count": 0,
"next": null,
"previous": null,
"results": []
}
Where I would like it to output
{
"meta_stuff": {
"License": "MIT"
},
"data": []
}
Where results=data and an extra ). Would I need to customise DRF or can a swagger.JSON schema be used to achieve this?
I suppose you're talking about pagination style. If so you should look at this link: http://www.django-rest-framework.org/api-guide/pagination/#custom-pagination-styles.
Basically you're going to write your own custom Pagination class, customizing DRF's behavior. Documentation's example is exactly what you've described.

Django: outputting JSON, not OrderedDict

I have a strange problem.
I have an API built with the Django REST framework.
I'm making a call and getting the following JSON back:
{
"success": true,
"result": {
"user_type": "ta",
"email": "myemail#gmail.com",
"first_name": "John",
"last_name": "Smith",
"mobile_phone": "555-555-5555",
"id": "0f165a85-2da6-4dcb-97cb-bf04900a942b"
}
}
I've tried to add a logging middleware when I'm trying to get the same output from response.data and writing int into a text field in my database.
For the very same request response.data is this: (and this gets written into my db, instead of the desired JSON string from above):
{'success': True, 'result': OrderedDict([('user_type', 'ta'), ('email', 'myemail#gmail.com'), ('first_name', 'John'), ('last_name', 'Smith'), ('mobile_phone', '555-555-5555'), ('id', UUID('0f165a85-2da6-4dcb-97cb-bf04900a942b'))])}
Why is that? How can I get get rid of that OrderedDict and get a perfect JSON string from response.data?
Please note: json.dumps doesn't work. I'm getting TypeError: Object of type 'UUID' is not JSON serializable. My entire ID system in the models is based on UUIDs. However, my Django REST framework is capable of serializing it just fine in the above example... how is that done?
You are hitting this problem because you're trying to dump the internal representation using json.dumps, which doesn't know how to handle UUID objects.
I can see two options - one, teach dumps how to serialize a UUID. This can be done by subclassing JSONDecoder, e.g. this SO answer.
However, DRF already knows how to serialize these fields. Poking around in the debugger, it looks like the response text is stashed in response.rendered_content. I'd check if that's populated by the time your middleware is run.
json.dumps(log_data, indent=2)
this can format your dict to the str you want.
eg:
# save log_data in some way
log_data = {
"success": True,
"result": {
"user_type": "ta",
"email": "myemail#gmail.com",
"first_name": "John",
"last_name": "Smith",
"mobile_phone": "555-555-5555",
"id": "0f165a85-2da6-4dcb-97cb-bf04900a942b"
}
}
logger.info(json.dumps(log_data, indent=2))
print(json.dumps(log_data, indent=2), type(json.dumps(log_data, indent=2)))
logger save to django.log like:
I managed to find this posted solution.
https://arthurpemberton.com/2015/04/fixing-uuid-is-not-json-serializable
I added the code to my models and now I do not get TypeError: Object of type 'UUID' is not JSON serializable when I serialize my UUID fields. This allowed me to call json.dumps on my response.data and serialize it to text perfectly.

Passing JSON data from response to request in Django

I have a Django (1.8.3) view that:
Makes a GET request to Server A (jetty), which returns JSON data in the body of the response. Then,
Makes a POST to Server B (node.js), passing the JSON data recieved from Server A in the body of the request.
The JSON data is structured like:
{
name: "foo",
details: {
"date": "today",
"isCool": "no",
},
stuff: [
{
"id": "1234",
"rating": "5",
}, {
"id": "5678",
"rating": "1",
},
]
}
But I can't figure out how to get the JSON from Server A's response into the request to Server B in my Django view. If I do this:
jetty_response = requests.request(method='GET', url=jetty_url)
node_response = requests.request(method="POST", url=node_url,
data=jetty_response.json())
I get the JSON object in Server B, but it looks like this:
{
name: "foo",
details: [ "date", "isCool"],
stuff: [ "id", "rating", "id", "rating"]
i.e. the name property is correct, but the details dict is instead received as the keyset of the original dict, and the stuff list is received as a flat array of the keysets in all objects in the original dict.
If I instead do this in django:
node_response = requests.request(method="POST", url=node_url,
data=json.dumps(jetty_response.json()))
I get an empty object in node, and same goes if I do simply:
data=jetty_response.content
How do I make this request??
Figured it out myself.
As is usually the case, the simplest answer:
node_response = requests.request(method="POST", url=node_url,
data=jetty_response.content)
worked fine once I took a closer look at my log and realized my POSTs were bouncing back 413, and then adjusted the size limit on my bodyParser in express.

Django - serialize to JSON, how to serialize a FK User object

I'm on a page which sends a request to server side for a list of comments of current topic.
like this
localhost:8000/getComments/567 , while 567 is the topic id.
then, in my django view, like this:
def getProjectComments(request, pId):
format = 'json'
mimetype = 'application/javascript' #'application/xml' for 'xml' format
comments = PrjComment.objects.filter(prj=pId)
data = serializers.serialize(format, comments)
return HttpResponse(data,mimetype)
Now , the question is ,
when I try to use jQuery.parseJSON(data) at the browser side.
[
{
"pk": 10,
"model": "app.prjcomment",
"fields":
{
"status": 1,
"time_Commented": "2011-12-11 17:23:56",
"prj": 1,
"content": "my comment 1",
"user": 25
}
},
{
"pk": 9,
"model": "app.prjcomment",
"fields": {
"status": 1,
"time_Commented": "2011-12-11 17:23:51",
"prj": 1,
"content": "comment \u4e00\u4e2a",
"user": 33
}
} ..
I need to use some detail information of user object. (user is a Foreign Key in model PrjComment)
such as user.first_name to display on the comment list.
but here it is only an id for user.("user": 33)
How can I do that? Anyone who can kind help?
Thank you very much
the User is the Django auth_user.
The easy solution would be to specify the values you need:
comments = PrjComment.objects.filter(prj=pId) \
.values('status','time_commented','prj','content','user__id',
'user__username','user__first_name')
Update:
To access your userprofile information use the table name as defined in your AUTH_PROFILE_MODULE setting. In my case the table is called userprofile, and I'd access the data like this:
values('user__userprofile__moreinfo')
where moreinfo is the field you're interested in