Django Rest API from Database - python

I have 2 APIs from my existing project. Where One provides the latest blog posts and another one provides sorting details. The 2nd API (sorting) gives blog posts ID and an ordering number, which should be in the 1st,2nd,3rd...n position. If I filter in the first API with that given ID I can get the blog post details.
How can I create a Django REST API from Database? or an API merging from that 2 APIs? Any tutorial or reference which might help me?
Frist API Response:
{
"count": 74,
"next": "https://cms.example.com/api/v2/stories/?page=2",
"previous": null,
"results": [
{
"id": 111,
"meta": {
"type": "blog.CreateStory",
"seo_title": "",
"search_description": "",
"first_published_at": "2022-10-09T07:29:17.029746Z"
},
"title": "A Test Blog Post"
},
{
"id": 105,
"meta": {
"type": "blog.CreateStory",
"seo_title": "",
"search_description": "",
"first_published_at": "2022-10-08T04:45:32.165072Z"
},
"title": "Blog Story 2"
},
2nd API Response
[
{
"featured_item": 1,
"sort_order": 0,
"featured_page": 105
},
{
"featured_item": 1,
"sort_order": 1,
"featured_page": 90
},
Here I want to create another API that will provide more details about sorting for example it will sort like this https://cms.example.com/api/v2/stories/105 and catch Title, Image & Excerpt and If there is no data from Sorting details it will show the first API's response by default.

After searching, I found that you can make API from Database. In setting you need to set the database credentials and then need to create a class inside your models.py and inside class's meta you need to set meta name to db_table and then create serializers.py and views.py as you create REST API.
class SortAPI(models.Model):
featured_item_id = models.IntegerField()
sort_order = models.IntegerField()
title=models.TextField()
first_published_at=models.DateTimeField()
alternative_title= models.TextField()
excerpt=models.TextField()
sub_heading=models.TextField()
news_slug=models.TextField()
img_title=models.TextField()
img_url=models.TextField()
img_width=models.IntegerField()
img_height=models.IntegerField()
class Meta:
db_table = 'view_featured'

Related

Unable to get individual mongo document

I am fairly new to python and mongodb and I'm facing an issue already.
I am trying to "translate" a nodejs backend restapi into flask, using mongodb as a data source.
Using the flask documentation, I was able to configure my app in order to connect to my local mongod.
And I am able to obtain values from the users collection like this
def getUser():
usr = Users.objects(email="mail#mail.com")
return {
"user": usr,
}
Which returns the following JSON when I'm calling the API through Postman
{
"user": [
{
"__v": 0,
"_id": {
"$oid": "5da86dc651eac87d2a82e2e2"
},
"createdAt": {
"$date": 1571319238918
},
"email": "mail#mail.com",
"password": "$2b$10$hoH57R5GL1MrwqpuW4yEJ.wwLlyNgyfxQm2Mxb19wioYTPPsU9z7y",
"profil": {
"_id": {
"$oid": "5da86dc651eac87d2a82e2e3"
},
"checked": false,
"clapList": [],
"followerList": [],
"followingList": [],
"playpoint": 0
},
"updatedAt": {
"$date": 1571319477959
}
}
]
}
As you can see, I have an array with one user in it. When I try to get only one object, like this:
def getUser():
usr = Users.objects(email="mail#mail.com").first()
return {
"user": usr,
}
I have a 500 status returned in Postman and the following error in my debug console: mongoengine.errors.FieldDoesNotExist: The fields "{'__v'}" do not exist on the document "Users"
This is my Users model
import mongoengine as me
class Users(me.Document):
phone = me.StringField()
email = me.StringField()
password = me.StringField()
accountType = me.StringField()
createdAt = me.DateTimeField()
updatedAt = me.DateTimeField()
profil = me.EmbeddedDocumentField(Profil)
I have already tried adding __v as an InfField(), but I still have the same error.
What is that __v anyway and should I retry making a new database from scratch?
Additional info:
The mongodb database and collection was generated using the nodejs API
The users in the database were generated using the nodejs API
So I added a meta property to it and I'm now able to use the class
meta = {
'strict': False,
}
I don't really know yet what transpired in there but I'm not touching anything if it works

Finding most popular tag Taggit Tastypie Django

Context
I have been having conflict. Currenly, I am creating a question answer application. Each question has a tag, and I want to show the most popular tags (e.g. tags that have the most questions associated with it).
Specifics
I am using django-taggit's TaggableManager to do so. Here is the model definition of the Question:
class Question(models.Model):
tags = TaggableManager()
date = models.DateTimeField(default=timezone.now)
text = models.TextField(null=True)
So now I have the several tags attached to questions.
Question
How do I make a tastypie resource to display the tags and sort them by which tag has the most questions associated with it?
My attempts
I have really only had one decently successful attempt at making this work. Here is the tastypie resource:
class TagResource_min(ModelResource):
def dehydrate(self, bundle):
bundle.data['total_questions'] len(Question.objects.filter(tags__slug=bundle.obj.slug))
return bundle
class Meta:
queryset=Tag.objects.all()
Returns a nice JSON with a variable called total_questions with the number of questions associated with it. Although, dehydrate is after the sort_by part of the request cycle specified here, so I cannot sort the resource by total_questions. Here is the JSON:
{
"meta": {
"limit": 20,
"next": null,
"offset": 0,
"previous": null,
"total_count": 13
},
"objects": [
{
"id": 1,
"name": "testing tag",
"resource_uri": "/full/tag/1/",
"slug": "testing-tag",
"total_questions": 2
},
...]
}
Another attempt I had went a different way trying to make the queryset be formed from the Question model:
queryset=Question.objects.filter(~Q(tags__slug=None)).values('tags', 'tags__slug').annotate(total_questions=Count(Tag))
The problem with this was that the filter function turns the result to dict type instead of models.Model type. The key difference was that models.Model has the attribute pk which is a type of identification, and the dict does not have that.
Any contribution is much appriciated! Thank you!

Many to many PATCH not immediately showing up in response Django REST Framework 2.4.3

It seems that performing a PATCH on an endpoint with a many-to-many relation updates the object but doesn't return back the updated data until the next response vs returning it back in the PATCH response.
Example with original object:
{
"id": 35,
"interests": [
1,
2
],
"personal_statement": "Hello World",
"photo": "",
"resume": "",
"user": 2
}
PATCH request setting interests=[1,2,3,4,5] ... Example response:
{
"id": 35,
"interests": [
1,
2
],
"personal_statement": "Hello World",
"photo": "",
"resume": "",
"user": 2
}
Example of next GET Response:
{
"id": 35,
"interests": [
1,
2,
3,
4,
5
],
"personal_statement": "Hello World",
"photo": "",
"resume": "",
"user": 2
}
This is using Django v1.7.4 and Django REST Framework v2.4.3
My first assumption is that since it's a many to many relation it is saving the parent object first and returning back that data before saving the many to many relation data, but I'm not entirely sure. Any help would be appreciated. Thanks.
EDIT
The issue is actually an open issue on Django REST Framework with some possible solutions. It was being caused by prefetch_related in my ViewSet queryset:
https://github.com/tomchristie/django-rest-framework/issues/1556
https://github.com/tomchristie/django-rest-framework/issues/2442
According to REST API patterns, PATCH request performs a partial update, so Django-Rest-Framework just returns updated data.
May be you want to override PATCH view to return complete serializer data or change your PATCH request to PUT one.
I encountered the same while adding prefetch_related to a many to many field I had. I solved it by simply adding a custom update to my serializer:
def update(self, instance, validated_data):
super(SimpleClientModelResource, self).update(instance, validated_data)
return self.Meta.model.objects.get(id=instance.id)

DJango: formatting json serialization

I have the following DJango view
def company(request):
company_list = Company.objects.all()
output = serializers.serialize('json', company_list, fields=('name','phonenumber','email','companylogo'))
return HttpResponse(output, content_type="application/json")
it result as follows:
[{"pk": 1, "model": "test.company", "fields": {"companylogo": null, "phonenumber": "741.999.5554", "name": "Remax", "email": "home#remax.co.il"}}, {"pk": 4, "model": "test.company", "fields": {"companylogo": null, "phonenumber": "641-7778889", "name": "remixa", "email": "a#aa.com"}}, {"pk": 2, "model": "test.company", "fields": {"companylogo": null, "phonenumber": "658-2233444", "name": "remix", "email": "b#bbb.com"}}, {"pk": 7, "model": "test.company", "fields": {"companylogo": null, "phonenumber": "996-7778880", "name": "remix", "email": "a#aba.com"}}]
my questions:
1. can i control the order of the fields
2. can i change the name of the fields
3. I was expecting to see the result with indentation in the browser i.e. instead of one long line to see something like this:
[
{
"pk": 1,
"model": "test.company",
"fields":
{
"companylogo": null,
"phonenumber": "741.999.5554",
"name": "Remax",
"email": "home#remax.co.il"
}
},
{
"pk": 4,
"model": "test.company",
"fields":
{
"companylogo": null,
"phonenumber": "641-7778889",
"name": "remixa",
"email": "a#aa.com"
}
},
....
}
]
you can get pretty format in this way:
return JsonResponse(your_json_dict, json_dumps_params={'indent': 2})
django doc as the first comment say
Python (unrelated to Django and starting with 2.6) has a built in json library that can accomplish the indentation you require. If you are looking for something quick and dirty for debug purposes you could do something like this:
from django.http import HttpResponse
from django.core import serializers
import json
def company(request, pretty=False):
company_list = Company.objects.all()
output = serializers.serialize('json', company_list, fields=('name','phonenumber','email','companylogo'))
if pretty:
output = json.dumps(json.loads(output), indent=4))
return HttpResponse(output, content_type="application/json")
But this is a performance issue if the Company model is large. I recommend taking Dan R's advice and use a browser plugin to parse and render the json or come up with some other client side solution. I have a script that takes in a json file and does exactly the same thing as the code above, reads in the json and prints it out with indent=4.
As for sorting your output, you can just use the order_by method on your query set:
def company(request):
company_list = Company.objects.order_by("sorting_field")
...
And if you always want that model sorted that way, you can use the ordering meta-class option:
class Company(models.Model):
class Meta:
ordering = ["sorting_field"]
...
As a final note, If your intent is to expose your models with a web service, I highly recommend taking a look at tastypie. It may help you in the long run as it provides many other convenient features that help towards that end.
With Django 1.7 I can get nicely indented JSON by using the indent parameter of the serializer. For instance, in a command that dumps data from my database:
self.stdout.write(serializers.serialize("json",
records,
indent=2))
The indent parameter has been in Django since version 1.5. The output I get looks like this:
[
{
"fields": {
"type": "something",
"word": "something else",
},
"model": "whatever",
"pk": 887060
},
{
"fields": {
"type": "something more",
"word": "and another thing",
},
"model": "whatever",
"pk": 887061
},
...
To order your records then you'd have to do what Kevin suggested and use order_by, or whatever method you want to order the records you pass to the serializer. For instance, I use itertools.chain to order different querysets that return instances of different models.
The serializer does not support ordering fields according to your preferences, or renaming them. You have to write your own code to do this or use an external tool.
JSON doesn't have indentation, it's simply structured data. Browsers or other tools may format the JSON so that it looks nice but by default it's not there. It's also not part of the JSON as the formatting is just how it looks on the screen. JSON is often processed by other code or services so they don't care about indentation, as long as the data is structured correctly.

tastypie PUT error unauthorized 401 when edit related fields

so I just try to use tastypie put method to edit objects.
let's say my object have this structure:
{
"id": 38,
"media": [],
"name": "tesdr",
"resource_uri": "/api/v2/group/38/",
"status": 7,
"user_name": null,
"users": []
}
witch media and users are related many to many field. when I edit group and use put without any change in m2m fields every thing works fine.
but when I try to put something like this:
{
"id": 38,
"media": [
"/api/v2/media/70/"
],
"name": "testgpat",
"resource_uri": "/api/v2/group/40/",
"status": 6,
"user_name": null,
"users": []
}
tastypie return an 401 http error. so what is the solution? any idea?
ok! I just solved the problem. have to define a many to many field in both resources which wants to set relation.
thanks all! :D

Categories

Resources