queryset filtering via a list of query values - django

A beginner django question...
Here's a JSON response...
"data": [
{
"type": "Subject",
"id": "0",
"attributes": {
"created": "2019-01-01T00:00:00Z",
"modified": "2019-01-01T00:00:00Z",
"subject_code": "A&H",
"subject_name": "AH",
"subject_short_name": "A & HUM"
},
"relationships": {
"organization": {
"data": {
"type": "Organization",
"id": "61"
}
},
"created_user": {
"data": null
},
"last_updated_user": {
"data": null
}
},
"links": {
"self": "http://localhost:8001/v1/subject_owner/0"
}
},
The above response is coming from a serializer
queryset = Subject.objects.all()
I have a query which is
http://localhost:8001/v1/subject_owner?owner_ids=62,63
So, how do we write a filtering condition for the owner_ids as a list? The response should have only the results where the owner_ids match organization_id. I have tried few:
queryset.filter(organization__in=[owner_id_list])
and
queryset.filter(organization=owner_id_list)
and obviously they don't work. Any help will be appreciated.
FYI, here's the model class...
class SubjectManager(models.Manager):
def get_by_natural_key(self, subject_code):
return self.get(subject_code=subject_code)
class Subject(get_subject_base_class(Organization)):
objects = SubjectManager()
def __str__(self):
return self.subject_code
def natural_key(self):
return (self.subject_code,)

You have to make something like that:
owner_id_list = [62, 63]
Subject.objects.filter(organization_id__in=owner_id_list)

Related

How to register Swagger endpoints in Flasgger

Currently using Swagger/Flasgger/Flask to document APIs/routes in an app.
# app.py
from flask import Flask
from flasgger import Swagger
from myapp.blueprints.main import main
app = Flask(__name__)
app.register_blueprint(main)
swag = Swagger(app)
# myapp.blueprints.main.views.py
main = Blueprint('main', __name__)
#main.route('/user/<path:user_id>', methods=['GET', 'PUT', 'DELETE'])
#main.route('/user', methods=['GET', 'POST'])
def user(user_id=None):
pass
To get documentation on two routes used for the same function, I need to do two things per the Flasgger documentation:
Add a #swag_from declaration pointing to the file that contains the spec.
Give the #main.route and #swag_from the same endpoint kwarg.
When I do step 1, I start seeing the spec information in the Swagger output:
# myapp.blueprints.main.views.py
#main.route('/user/<path:user_id>', methods=['GET', 'PUT', 'DELETE'])
#main.route('/user', methods=['GET', 'POST'])
#swag_from('user_without_id.yml')
def user(user_id=None):
pass
// > curl localhost:8000/apispec_1.json
{
"definitions": {
"User": {
"properties": {
"age": {
"default": "180",
"description": "The user age (should be integer)",
"type": "integer"
},
"tags": {
"default": [
"wizard",
"hogwarts",
"dead"
],
"description": "optional list of tags",
"items": {
"type": "string"
},
"type": "array"
},
"username": {
"default": "Sirius Black",
"description": "The user name.",
"type": "string"
}
},
"required": [
"username",
"age"
]
}
},
"info": {
"description": "The test-swagger-api spec",
"termsOfService": "/tos",
"title": "test-swagger-api",
"version": "1.0"
},
"paths": {
"/user": {
"get": {
"description": "The default payload is invalid, try it, then change the age to a valid integer and try again<br/>",
"parameters": [
{
"in": "body",
"name": "body",
"required": true,
"schema": {
"$ref": "#/definitions/User"
}
}
],
"responses": {
"200": {
"description": "A single user item",
"schema": {
"$ref": "#/definitions/User"
}
}
},
"summary": "Test validation using JsonSchema"
},
"post": {
"description": "The default payload is invalid, try it, then change the age to a valid integer and try again<br/>",
"parameters": [
{
"in": "body",
"name": "body",
"required": true,
"schema": {
"$ref": "#/definitions/User"
}
}
],
"responses": {
"200": {
"description": "A single user item",
"schema": {
"$ref": "#/definitions/User"
}
}
},
"summary": "Test validation using JsonSchema"
}
},
"/user/{user_id}": {
"get": {
"description": "The default payload is invalid, try it, then change the age to a valid integer and try again<br/>",
"parameters": [
{
"in": "body",
"name": "body",
"required": true,
"schema": {
"$ref": "#/definitions/User"
}
}
],
"responses": {
"200": {
"description": "A single user item",
"schema": {
"$ref": "#/definitions/User"
}
}
},
"summary": "Test validation using JsonSchema"
}
}
},
"swagger": "2.0"
}
However, as soon as I add the endpoint and methods kwargs, my output loses the spec:
# myapp.blueprints.main.views.py
#main.route('/user/<path:user_id>', methods=['GET', 'PUT', 'DELETE'])
#main.route('/user', endpoint='my-new-endpoint', methods=['GET', 'POST'])
#swag_from('user_without_id.yml', endpoint='my-new-endpoint', methods=['GET', 'POST'])
def user(user_id=None):
pass
// > curl localhost:8000/apispec_1.json
{
"definitions": {},
"info": {
"description": "The test-swagger-api spec",
"termsOfService": "/tos",
"title": "test-swagger-api",
"version": "1.0"
},
"paths": {},
"swagger": "2.0"
}
Not sure where the documentation is going. Flasgger's blueprint example doesn't show how to make this work with multiple routes on a single function.
https://stackoverflow.com/a/55109061/3316036
#swag_from needs to contain the blueprint name in its endpoint field which is unfortunately not clear from the flasgger docs.
# myapp.blueprints.main.views.py
#main.route('/user/<path:user_id>', methods=['GET', 'PUT', 'DELETE'])
#main.route('/user', endpoint='my-new-endpoint', methods=['GET', 'POST'])
#swag_from('user_without_id.yml', endpoint='main.my-new-endpoint', methods=['GET', 'POST'])
def user(user_id=None):
pass

How to nest a serializer?

So I'm trying to create an /api/info url that return various data on my application. It pulls data from various models and puts it together in one response. I got the following:
class SessionInfo(generics.GenericAPIView):
def get(self, request, format=None):
token = Token.objects.get(user=self.request.user)
userprofile = UserProfile.objects.get(user=self.request.user)
is_admin = self.request.user.is_staff
is_primary_owner = userprofile.primary_owner
managers = userprofile.reports_to.all()
man = ["test manager 1", "test manager 2"]
pages = Page.objects.filter(published=True, show_in_menu=True)
pages_output = JSONRenderer().render(PageSerializer(pages).data)
content = {
'user': {
"username": str(self.request.user.username),
"first_name": str(self.request.user.first_name),
"last_name": str(self.request.user.last_name),
"is_admin": is_admin,
"is_primary_owner": is_primary_owner,
"api_token": token.key,
"timezone": 'blalala',
"managers": man,
},
'license': {
"plan" : "gold",
"expiry_date" : "lol",
},
'feature_flags': {
'billing_test': False,
},
'pages': { pages_output },
}
return Response(content)
However it doesn't properly serialize and render pages, making it an escaped string instead:
{
"feature_flags": {
"billing_test": false
},
"user": {
"username": "test#user.com",
"first_name": "Test",
"last_name": "User",
"is_admin": true,
"managers": [
"test manager 1",
"test manager 2"
],
"api_token": "08d1a5827da9a90e7746949ffd2e69e87c51b272",
"timezone": "blalala",
"is_primary_owner": false
},
"license": {
"expiry_date": "lol",
"plan": "gold"
},
"pages": [
"[{\"id\": 1, \"title\": \"Trololol\"}, {\"id\": 2, \"title\": \"NEW pages\"}]"
]
}
if I use directuly use pages_output = PageSerializer(pages) I get:
<webapp_api_v1.serializers.PageSerializer object at 0x10a0d8f90> is not JSON serializable
How can I make a serializer properly nest within my constructed response? Thanks!
Solved it with pages_output = PageSerializer(pages).data and changing 'pages': pages_output,

What is the "likes" field from an FB Open Graph GET og.likes request?

I've implemented functionality to Like a non-FB URL in a cross-platform mobile app (Phonegap) I'm developing, and part of functionality is that I need to find out if a user has liked a URL before, hence a GET on the og.likes object. In the result of this request there's a field in the og.likes data that I'm unsure about.
My request:
GET me/og.likes?access_token={AccessToken}&object={EncodedExternalURL}
The response:
{
"data": [
{
"id": "_____",
"from": {
"id": "______",
"name": "______"
},
"start_time": "2015-01-12T06:17:24+0000",
"end_time": "2015-01-12T06:17:24+0000",
"publish_time": "2015-01-12T06:17:24+0000",
"application": {
"name": "______",
"namespace": "______",
"id": "______"
},
"data": {
"object": {
"id": "____",
"url": "____",
"type": "website",
"title": "____"
}
},
"type": "og.likes",
"no_feed_story": false,
"likes": { // <-- this guy here and its properties
"count": 0,
"can_like": true,
"user_likes": false
},
"comments": {
"count": 0,
"can_comment": true,
"comment_order": "chronological"
}
}
],
"paging": {
"next": "____"
}
}
What is the likes field? And the sub properties of count, can_like, user_likes? Is it that other users can like this Like?
likes field is for manage the likes that this like has. Users can like or comment a like.

Django AJAX looping data

In my view I'm trying to loop all pages and extract the name for each using the code below. But it does not appear to work.
How can I achieve this?
view.py
json_dict = json.loads(request.POST['site'])
for item in json_dict['pages']:
item.json_dict['name']
the JSON data
{
"someitem": "xaAX",
"pages": [
{
"id": "1364484811734",
"name": "Page Name",
"type": "basic",
"components": {
"img": "",
"text": ""
}
},
{
"id": "1364484812918",
"name": "Contact",
"type": "contact",
"components": {
"text": "Send us an email using the form below.",
"contact-form": {
"contact-name": "zzz",
"contact-email": "zz"
}
}
},
]
}
This should work:
json_dict = json.loads(request.POST['site'])
for item in json_dict['pages']:
print item['name']

Django Tastypie - How to get related Resources with a single request

Suppose following Resources are given:
class RecipeResource(ModelResource):
ingredients = fields.ToManyField(IngredientResource, 'ingredients')
class Meta:
queryset = Recipe.objects.all()
resource_name = "recipe"
fields = ['id', 'title', 'description',]
class IngredientResource(ModelResource):
recipe = fields.ToOneField(RecipeResource, 'recipe')
class Meta:
queryset = Ingredient.objects.all()
resource_name = "ingredient"
fields = ['id', 'ingredient',]
A HTTP Request to myhost.com/api/v1/recipe/?format=json gives following response:
{
"meta":
{
...
},
"objects":
[
{
"description": "Some Description",
"id": "1",
"ingredients":
[
"/api/v1/ingredient/1/"
],
"resource_uri": "/api/v1/recipe/11/",
"title": "MyRecipe",
}
]
}
So far so good.
But now, I would like to exchange the ingredients resource_uri ("/api/v1/ingredient/1/") with something like that:
{
"id": "1",
"ingredient": "Garlic",
"recipe": "/api/v1/recipe/1/",
"resource_uri": "/api/v1/ingredient/1/",
}
To get following response:
{
"meta":
{
...
},
"objects":
[
{
"description": "Some Description",
"id": "1",
"ingredients":
[
{
"id": "1",
"ingredient": "Garlic",
"recipe": "/api/v1/recipe/1/",
"resource_uri": "/api/v1/ingredient/1/",
}
],
"resource_uri": "/api/v1/recipe/11/",
"title": "MyRecipe",
}
]
}
The answer is the attribute full=True:
ingredients = fields.ToManyField('mezzanine_recipes.api.IngredientResource', 'ingredients', full=True)