Django: Send current logged in user as JSON - json

I would like to create a GET endpoint that returns the JSONResponse of the current logged-in user. Ideally, it would look like:
{
"username": "joe",
"email": "joe#plainviewhcp.com",
"first_name": "",
"last_name": "",
"last_login": "2021-09-17T17:11:00.039Z",
"is_superuser": true,
"is_active": true
}
(Note that I'm using Django 3.2, not Django REST API)
This requires serializing the current user object, but serializing a single object is... opaque in the documentation, and many similar questions have responses from 6 or more years/two major versions ago.

I've solved this problem by re-querying the user from the request.user object and singling out the first field. This has the added benefit of controlling the fields. Note that I've already tested to make sure the user is logged in at this point.
def api_current_user(request: HttpRequest):
user = (
User.objects.filter(pk=request.user.pk)
.values(
"username",
"email",
"first_name",
"last_name",
"last_login",
"is_superuser",
"is_active",
)
.first()
)
return JsonResponse(user)

Related

return model instance without tuple when case statement is used in SQLAlchemy + FastAPI

Let's say I have an API, by calling it we get a list of posts, for each post I want to send a value whether that post is editable or not by the logged-in user in the response. so for that I'm using Case statement from SQLAlchemy and based on the logged-in user ID I'm returning true or false
The code looks like below
is_editable_expr = case(
[
(Post.user_id == current_user.id, True),
],
else_=False,
).label("is_editable")
data = db_session.query(Post, is_editable_expr).order_by(Post.created_at.desc()).join(User).all()
I'm using FastAPI and when it tries to serialize the data it fails because the value returned by this is ORM looks like
[(<Post title=Todo title description=A short description about your todo>, False), ...]
here the post model instance is inside the tuple and is_editable is directly accessible. the Post pydantic model looks like this
class Post(BaseModel):
id: int
title: str,
description: str,
user: User
is_active: bool
is_editable: bool
class Config:
orm_mode = True
since the orm instance itself is inside tuple while serializing it's failing and cannot access title/descriptions etc. I want my response to be a list of Post and it should look like this
[
{
"title":"title name",
"description":"some long description",
"is_editable":true
},
...
]
Can anyone please advice or suggest how can I make it work. Thanks in advance.
That is happening because of your query definition: db_session.query(Post, is_editable_expr)
So basically the second item in the tuple is your is_editable expression
I would rather avoid doing it in the database and would do a simple loop to do it on the server:
data = (db_session.query(Post)
.order_by(Post.created_at.desc())
.join(User)
.all())
for post in data:
post.is_editable = post.user_id == current_user.id

Error when including a contact to group using People API

I need to add a single contact to all the below groups. I tried to add the contact to groups one by one, however when I tested with the first group the API gave an error
GoogleJsonResponseException: API call to people.contactGroups.members.modify failed with error: Cannot add contacts to deprecated system contact group resource name "contactGroups/chatBuddies".
I want to add the created contact to all these groups
contactGroups/chatBuddies
contactGroups/all
contactGroups/friends
contactGroups/coworkers
contactGroups/family
contactGroups/blocked
I dont see anywhere that these groups are depreciated
I have tried with
var b = {
"phoneNumbers": [{
"type": "mobile",
"value": "09876543210"
}],
"names": [{
"unstructuredName": "Test account"
}],
"urls": [],
"addresses": [{
"type": "work",
"formattedValue": "0"
}],
"organizations": [{
"name": "Organisation"
}],
"emailAddresses": [{
"type": "home",
"value": "abcd#gmail.com"
}]
}
function doGet(e) {
var resource = People.People.createContact(b);
var id = resource.metadata.sources[0].id;
var contactResourceName = resource["resourceName"];
var group = People.ContactGroups.get("contactGroups/friends");
var groupResourceName = group["resourceName"];
var membersResource = {
"resourceNamesToAdd": [
contactResourceName
]
}
People.ContactGroups.Members.modify(membersResource, groupResourceName);
return ContentService.createTextOutput(JSON.stringify(group));
}
Where was the deprecation notice?
It was on display in the bottom of a locked filing cabinet stuck in a disused lavatory with a sign on the door saying "Beware of the Leopard."
In all seriousness, advanced services are thin layers wrapping the corresponding REST APIs, in this case, People API, therefore each method of the service has a corresponding method exposed by the API, specifically contactGroups.members.modify.
The description of the method reads as follows, clearly outlining that system contact groups are, in fact, deprecated:
The only system contact groups that can have members added are contactGroups/myContacts and contactGroups/starred. Other system contact groups are deprecated and can only have contacts removed.
Can I update system groups via the API directly?
It does not seem to be possible, as adding system groups to contact when updating memberships field via the people.updateContact method is explicitly forbidden (you have to examine the ContactGroupMembership resource docs to find the info):
Any contact group membership can be removed, but only user group or "myContacts" or "starred" system group memberships can be added.

POST nested json in postman formdata

actually, I wanted to send nested JSON with an image to creating user profile image in Django, and the main issues addressed to I cant fill the nested objects
this is my json that successfully post in raw mode :
{
"id": 1,
"bio": "salam manam",
"user": {
"username": "amirlesani",
"first_name": "",
"password":"somepasword"
"last_name": "",
"email": ""
},
"user_type": {
"user_type": "br"
}
}
But when I want to fill up the form data same as that way its shown an error like this
user_type: this field is required!
user: this field is required!
serlializers:
class UserProfileSerializer(serializers.HyperlinkedModelSerializer):
user = UserSerializer()
user_type = UserTypeSerializer()
images = ProfileImageSerializer(source='profileimage_set', many=True, read_only=True)
class Meta:
model = UserProfile
fields = ('id', 'bio', 'user', 'images', 'user_type')
def create(self, validated_data):
usertype = validated_data.pop('user_type')
type = UserTypeSerializer.create(UserTypeSerializer(), validated_data=usertype)
user_data = validated_data.pop('user')
user = UserSerializer.create(UserSerializer(), validated_data=user_data)
userprofile = UserProfile.objects.create(user=user, bio=validated_data.pop('bio'), user_type=type)
images_data = self.context.get('view').request.FILES
for image_data in images_data.values():
ProfileImage.objects.create(userprofile=userprofile, image=image_data, user_type=type)
userprofile.save()
return userprofile
i found the solution , u must distinct the imageUploader from the nested json , and connect ur images to ur data with a foreign key

Jira API | Error: "Operation value must be a string" - trying to set value nested two levels deep

Trying to create a new jira ticket of specific requestType, but it is nested two levels deep. Tried few possible alterations, but no luck. Here's the code I have,
require 'jira-ruby' # https://github.com/sumoheavy/jira-ruby
options = {
:username => jira_username,
:password => jira_password,
:site => 'https://jiraurl/rest/api/2/',
:context_path => '',
:auth_type => :basic,
:read_timeout => 120
}
client = JIRA::Client.new(options)
issue = client.Issue.build
fields_options = {
"fields" =>
{
"summary" => "Test ticket creation",
"description" => "Ticket created from Ruby",
"project" => {"key" => "AwesomeProject"},
"issuetype" => {"name" => "Task"},
"priority" => {"name" => "P1"},
"customfield_23070" =>
{
"requestType" => {
"name" => "Awesome Request Type"
}
}
}
}
issue.save(fields_options)
"errors"=>{"customfield_23070"=>"Operation value must be a string"}
Also tried passing a JSON object to customfield_23070,
"customfield_23070": { "requestType": { "name": "Awesome Request Type" } }
still no luck, get the same error message.
If it helps, this is how customfield_23070 looks like in our Jira,
Does anyone know how to set requestType in this case, please? Any help is greatly appreciated!!
It seems that for custom fields with specific data types (string/number), you must pass the value as:
"customfield_1111": 1
or:
"customfield_1111": "string"
instead of:
"customfield_1111":{ "value": 1 }
or:
"customfield_1111":{ "value": "string" }
I'm not sure but you can try this possible examples:
eg.1:
"customfield_23070"=>{"name"=>"requestType","value"=>"Awesome Request Type"}
eg.2:
"customfield_23070"=>{"requestType"=>"Awesome Request Type"}
eg.3:
"customfield_23070"=>{"value"=>"Awesome Request Type"}
eg.4
"customfield_23070"=>{"name"=>"Awesome Request Type"}
for ref there are 2 methods depending upon the fields you are interacting with
have a look here '
updating-an-issue-via-the-jira-rest-apis-6848604
' for the applicable fields for update via verb operations, the other fields you can use examples as per above,
you can use both methods within the same call
{
"update": {"description": [{"set": "Description by API Update - lets do this thing"}]},
"fields": {"customfield_23310": "TESTING0909"}
}
Ok, I think I found how to do it.
You need to provide a string, and that string is the GUID of the RequestType.
In order to get that GUID. You need to run the following in a scriptrunner console:
import com.atlassian.jira.component.ComponentAccessor
def issue = ComponentAccessor.issueManager.getIssueByCurrentKey("ISSUE-400546") //Issue with the desired Request Type
def cf = ComponentAccessor.customFieldManager.getCustomFieldObjectByName("Tipo de solicitud del cliente") //Change it to the name of your request type field
issue.getCustomFieldValue(cf)
Source: https://community.atlassian.com/t5/Jira-Software-questions/how-to-set-request-type-value-in-while-create-jira-issue/qaq-p/1106696

Using REST design properly - Categories and Subcategories

I have two question on basic REST concepts.
QUESTION 1: Categories
So I have a list of Categories I want to show from a database.
SELECT * from categories
Currently, I use this REST desgin: /api/v1/categories/
Is that proper?
I have also seen /api/v1/categories/list/ -- or is this preferred? (If so, then what would a simple /categories call display then? (Or would the proper way then be /api/v1/category/list where category is singular and adding list will show you all categories -- this way a call to /category would allow veiwing info on just one?)
QUESTION 2: Subcategories. (Think "Seinfeld" as a subcategory of "Television".)
SELECT * FROM subcategories" WHERE category_id = {id}
The id above might be the Television Category where I want to get specific shows listed.
Would I do /api/v1/categories/{id}/ for the Subcategory with the subcat_id? Would I have to use parameters instead like /Categories?id={id}/
How would this relationship work?
My answers are based on "pragmatic REST".
QUESTION 1: Categories
If you go with plural or singular form then I would suggest sticking with it and not jump between singular and plural... this is subjective.
If you go with singular form, then the list path action sounds applicable. If you go with plural then I think it is more subjective... IMHO list removes ambiguity and I would prefer it.
QUESTION 2: Subcategories. (Think "Seinfeld" as a subcategory of "Television".)
IMHO sub-category sounds like a separate resource. I think it should have its own path element.
Would I do /api/v1/categories/{id}/ for the Subcategory with the subcat_id? Would I have to use parameters instead like /Categories?id={id}/
I think that /api/v1/subcategories/{id}/ is more popular. But one thing that is becoming more popular is searching criteria. ID might just be one of many search criteria. If you see yourself adding search criteria then /api/v1/subcategories/?id={id} or /api/v1/subcategories/?filter={some_search_string} where you decide how that search string is parsed.
The most important thing to consider is that you are able to grow (extend) your API without changing these initial decisions you are making now. Its easy to add to an API but harder to alter existing API design once it is being used.
The URI structure is an implementation detail, it does not matter by REST as long as your service fulfills the uniform interface constraint, which is about applying the relevant standards. In your case the URI structure must fulfill the URI standard and you have to use a hypermedia format, which contains hyperlinks. So in your case /api/v1/sdfh34gsv/123regf3 would be completely okay as long as it is in a hyperlink and there is sufficient metadata available to understand what that hyperlink does. E.g. with HAL+JSON:
{
"_links": {
"/api/v1/docs/rels/category": {
"href": "/api/v1/sdfh34gsv/123regf3",
"title": "Television"
}
}
}
By processing such a response the client will recognize the "/api/v1/docs/rels/category" link relation, so it will know that it is a hyperlink to a category, which title is "Television" and the details of the category can be retrieved by following the link. If the client does not know the /api/v1/docs/rels/category link relation, then it can dereference the URI and and probably it will get some description in RDF, which it can use to display the hyperlink in a more basic form. Ofc, if developers dereference the same URI, they can get a HTML description of the link relation.
By most of the REST services this does not happen, because they use vendor specific MIME types and probably plain JSON, which violates the HATEOAS constraint, but I guess it is more practical in some cases.
async getAllCategorySubCategoryAndGroupCategoryDetail(): Promise < CategoryDetails[] > {
try {
let categoryGroupQuery = `SELECT shrt_category_groups.id as categoryGroupId,
shrt_category_groups.category_group_name as categoryGroupName,
concat('${ENV.IMG_SERVER}',shrt_category_groups.category_group_image) AS categoryGroupImage,
shrt_category_groups.is_active as isActive,
shrt_category_groups.sort_order as sortOrder
FROM shrt_category_groups where shrt_category_groups.is_active = '1' `;
let categoryGroupList = await pool.query(categoryGroupQuery);
if (categoryGroupList.length > 0) {
let categoryListQuery = `SELECT shrt_categories.id as categoryId,
shrt_categories.category_name as categoryName,
shrt_categories.category_image as categoryImage,
shrt_categories.is_active as isActive,
shrt_categories.category_group_id as categoryGroupId
FROM shrt_categories where shrt_categories.is_active = '1'`;
let categoryList = await pool.query(categoryListQuery);
let subcategoryQuery = `SELECT shrt_sub_categories.id as subCategoryId,
shrt_sub_categories.is_active as isActive,
shrt_sub_categories.subcategory_commission as commission,
shrt_sub_categories.commission_type as commissionType,
shrt_sub_categories.sub_category_name as subCategoryName,
shrt_sub_categories.category_id as categoryId
FROM shrt_sub_categories where shrt_sub_categories.is_active = '1'`;
let subCategoryList = await pool.query(subcategoryQuery);
const getCategory = (categoryGroupId: any) => {
return categoryList.filter((cat: any) => cat.categoryGroupId == categoryGroupId)
}
const getSubCategory = (categoryId: any) => {
return subCategoryList.filter((subCategory: any) => subCategory.categoryId == categoryId)
}
let mergeData = categoryGroupList.map((catG: any) => {
return { ...catG,
category: getCategory(catG.categoryGroupId).map((cat) => {
return { ...cat,
subCategory: getSubCategory(cat.categoryId)
}
})
}
})
return mergeData;
} else {
return categoryGroupList;
}
} catch (error) {
throw error;
}
}
{
"data": [
{
"categoryGroupId": 1,
"categoryGroupName": "Cloud",
"categoryGroupImage": null,
"isActive": "1",
"sortOrder": null,
"category": [
{
"categoryId": 1,
"categoryName": "Kinder & Baby",
"categoryImage": null,
"isActive": "1",
"categoryGroupId": 1,
"subCategory": [
{
"subCategoryId": 17,
"isActive": "1",
"commission": null,
"commissionType": null,
"subCategoryName": "Shirts",
"categoryId": 1
},
{
"subCategoryId": 20,
"isActive": "1",
"commission": null,
"commissionType": null,
"subCategoryName": "Jacken",
"categoryId": 1
},
{
"subCategoryId": 21,
"isActive": "1",
"commission": null,
"commissionType": null,
"subCategoryName": "Organic Collection",
"categoryId": 1
},
{
"subCategoryId": 22,
"isActive": "1",
"commission": null,
"commissionType": null,
"subCategoryName": "Baby",
"categoryId": 1
},
{
"subCategoryId": 23,
"isActive": "1",
"commission": null,
"commissionType": null,
"subCategoryName": "Hoodies & Sweatshirts",
"categoryId": 1
}
]
}
]
}
]
}