Show ISO date values in string form - django

So I was trying to get what months that an insurer filed a claim. However, the values were in ISO Form. I was trying to show it in string form. Instead of showing 2021-01-01, show January; 2021-01-02, show February
Here's the sample get data
Data in image form
{
"Month": [
"2021-04-01T00:00:00+08:00",
"2021-02-01T00:00:00+08:00",
"2021-03-01T00:00:00+08:00"
],
"Claim(s)": {
"": 18,
"Bank Transfer": 5,
"CAR": 1,
"home": 5,
"Credit": 7,
"Energy": 1,
"health": 38,
"\"health\"": 5
}
}
I'd like to change the ISO date form into string form instead.
Here is my code in Views
class GetClaimsCompare_year(APIView):
def get_claim_count(self, claims_data, claim_type):
claims_count = claims_data.filter(claim_type = claim_type).count()
return claims_count
def get_claims_type(self, claim_per_month):
return claim_per_month.claim_type
def get(self, request):
today = datetime.now()
claims_data = Claims.objects.filter(modified_at__year =today.year)
claim_per_month = claims_data.annotate(month = TruncMonth('modified_at')).values('month').annotate(claim_type=Count('id'))
labels = []
claims_type = list(set(map(self.get_claims_type, claims_data)))
final = {}
for claims in claim_per_month:
labels.append(claims['month'])
for claim_type in claims_type:
final[claim_type] = self.get_claim_count(claims_data, claim_type)
context = {
'Month':labels,
'Claim(s)':final
}
return Response(context)

Simple call strftime on the datetime that you get
...
for claims in claim_per_month:
month_label = claims['month'].strftime('%B')
labels.append(month_label)
...

Related

How to display all dates for multiple model annotations in django

So I'm working on a website, and I want to have some kind of a summary page to display the data that I have. Let's say I have these models:
class IceCream(TimeStampedModel):
name = models.CharField()
color = models.CharField()
class Cupcake(TimeStampedModel):
name = models.CharField()
icing = models.CharField()
So on this page, users will be able to input a date range for the summary. I'm using DRF to serialize the data and to display them on the view actions. After I receive the filter dates, I will filter out the IceCream objects and Cupcake objects using the created field from TimeStampedModel.
#action(detail=False, methods=['get'])
def dessert_summary(self, request, **kwargs):
start_date = self.request.query_params.get('start_date')
end_date = self.request.query_params.get('end_date')
cupcakes = Cupcake.objects.filter(created__date__range=[start_date, end_date])
ice_creams = IceCream.objects.filter(created__date__range=[start_date, end_date])
After filtering, I want to count the total cupcakes and the total ice creams that is created within that period of time. But I also want to group them by the dates, and display the total count for both ice creams and cupcakes based on that date. So I tried to annotate the querysets like this:
cupcakes = cupcakes.annotate(date=TruncDate('created'))
cupcakes = cupcakes.values('date')
cupcakes = cupcakes.annotate(total_cupcakes=Count('id'))
ice_creams = ice_creams.annotate(date=TruncDate('created'))
ice_creams = ice_creams.values('date')
ice_creams = ice_creams.annotate(total_ice_creams=Count('id'))
So I want the result to be something like this:
{
'summary': [{
'date': "2020-09-24",
'total_ice_creams': 10,
'total_cupcakes': 7,
'total_dessert': 17
}, {
'date': "2020-09-25',
'total_ice_creams': 6,
'total_cupcakes': 5,
'total_dessert': 11
}]
}
But right now this is what I am getting:
{
'summary': [{
'cupcakes': [{
'date': "2020-09-24",
'total_cupcakes': 10,
}, {
'date': "2020-09-25",
'total_cupcakes': 5,
}],
'ice_creams': [{
'date': "2020-09-24",
'total_ice_creams': 7,
}, {
'date': "2020-09-27",
'total_ice_creams': 6,
}]
}]
}
What I want to ask is how do I get all the dates of both querysets, sum the ice creams and cupcakes, and return the data like the expected result? Thanks in advance for your help!
So here's what you can do:
gather all icecream/cupcakes count data into a dictionary
icecream_dict = {obj['date']: obj['count'] for obj in ice_creams}
cupcakes_dict = {obj['date']: obj['count'] for obj in cupcakes}
create a sorted list with all the dates
all_dates = sorted(set(list(icecream_dict.keys()) + list(cupcakes_dict.keys())))
create a list with items for each date and their count
result = []
for each_date in all_dates:
total_ice_creams = icecream_dict.get(each_date, 0)
total_cupcakes = cupcakes_dict.get(each_date, 0)
res = {
'date': each_date,
'total_ice_creams': total_ice_creams,
'total_cupcakes': total_cupcakes,
'total_dessert': total_ice_creams + total_cupcakes
}
result.append(res)
# check the result
print(result)
Hint: If you plan to add more desert-like models, consider have a base model Desert that you could query directly instead of querying each desert type model.

DRF formatting XLSX content

I am trying to set a different color on every second row in XLSX file. From the documentation I see that I can pass some conditions using body property or get_body() method, but this only allows me to set somewhat "static" conditions. Here is the ViewSet config responsible for rendering the XLSX file:
class MyViewSet(XLSXFileMixin, ModelViewSet):
def get_renderers(self) -> List[BaseRenderer]:
if self.action == "export":
return [XLSXRenderer()]
else:
return super().get_renderers()
#action(methods=["GET"], detail=False)
def export(self, request: Request) -> Response:
serializer = self.get_serializer(self.get_queryset(), many=True)
return Response(serializer.data)
# Properties for XLSX
column_header = {
"titles": [
"Hostname", "Operating System", "OS name", "OS family", "OS version", "Domain", "Serial number",
"Available patches",
],
"tab_title": "Endpoints",
"style": {
"font": {
"size": 14,
"color": "FFFFFF",
},
"fill": {
"start_color": "3F803F",
"fill_type": "solid",
}
}
}
body = {
"style": {
"font": {
"size": 12,
"color": "FFFFFF"
},
"fill": {
"fill_type": "solid",
"start_color": "2B2B2B"
},
}
}
OK. I got the answer after some digging through the source code. The render method of XLSXRenderer has this piece of code:
for row in results:
column_count = 0
row_count += 1
flatten_row = self._flatten(row)
for column_name, value in flatten_row.items():
if column_name == "row_color":
continue
column_count += 1
cell = ws.cell(
row=row_count, column=column_count, value=value,
)
cell.style = body_style
ws.row_dimensions[row_count].height = body.get("height", 40)
if "row_color" in row:
last_letter = get_column_letter(column_count)
cell_range = ws[
"A{}".format(row_count): "{}{}".format(last_letter, row_count)
]
fill = PatternFill(fill_type="solid", start_color=row["row_color"])
for r in cell_range:
for c in r:
c.fill = fill
So when I added a field row_color in my serializer as SerializerMethodField I was able to define a function that colors rows:
def get_row_color(self, obj: Endpoint) -> str:
"""
This method returns color value for row in XLSX sheet.
(*self.instance,) extends queryset to a list (it must be a queryset, not a single Endpoint).
.index(obj) gets index of currently serialized object in that list.
As the last step one out of two values from the list is chosen using modulo 2 operation on the index.
"""
return ["353535", "2B2B2B"][(*self.instance,).index(obj) % 2]

How to format json response in django?

I am retrieving data from multiple tables in Django.
my current response is :
{
"status": 0,
"message": "Client details retrived successfully...!!!",
"results": [
{
"id": 11,
"client_id": "CL15657917080578748000",
"client_name": "Pruthvi Katkar",
"client_pan_no": "RGBB004A11",
"client_adhar_no": "12312312313",
"legal_entity_name": "ABC",
"credit_period": "6 months",
"client_tin_no": 4564565,
"client_email_id": "abc#gmail.com",
"head_office_name": "ABC",
"office_name": "asd234",
"office_email_id": "zxc#gmail.com",
"office_contact": "022-27547119",
"gst_number": "CGST786876876",
"office_country": "India",
"office_state": "gujrat",
"office_district": "vadodara",
"office_taluka": "kachh",
"office_city": "vadodara",
"office_street": "New rode 21",
"office_pincode": 2344445,
"contact_person_name": "prasad",
"contact_person_designation": "DM",
"contact_person_number": "456754655",
"contact_person_email": "asd#gmail.com",
"contact_person_mobile": "5675545654",
"created_at": "2019-08-14T14:08:28.057Z",
"created_by": "Prathamseh",
"updated_at": "2019-08-14T14:08:28.057Z",
"updated_by": "prasad",
"is_deleted": false
},
{
"id": 11,
"user_id": "CL15657917080578748000",
"bank_details_id": "BL15657917080778611000",
"bank_name": "Pruthvi",
"branch": "vashi",
"ifsc_code": "BOI786988",
"account_number": 56756765765765,
"account_name": "Pruthvi",
"is_deleted": false
},
{
"id": 10,
"document_details_id": "DL15657917080808598000",
"user_id": "CL15657917080578748000",
"document_type": "Pruthvi ID",
"document": "www.sendgrid.com/pan",
"is_deleted": false
}
]
}
Expected Response :
I am getting the queryset form db in models.py and i am sending it to the views.py and i am iterating over the dict but not getting the expected response.
views.py
#csrf_exempt
def get_client_details(request):
try:
# Initialising lists for storing results
result = []
temp_array = []
# Getting data from request body
client_master_dict = json.loads(request.body)
# Response from get client data
records = ClientDetails.get_client_data(client_master_dict)
# Create response object
# Iterating over the records object for getting data
for i in range(len(records)):
# Converting the querysets objects to json array format
record_result_list = list(records[i].values())
# If multiple records are present
if(len(record_result_list) > 1):
for j in range(len(record_result_list)):
user_info = record_result_list[j]
temp_array.append(user_info)
result.append(temp_array)
temp_array=[]
# For single record
else:
result.append(record_result_list[0])
# Success
returnObject = {
"status" : messages.SUCCESS,
"message" : messages.CLIENT_RETRIVE_SUCCESS,
"results" : result
}
return JsonResponse(returnObject,safe=False)
I think the issue might be in my inner for loop, can anyone help me out with this, is there any way to iterate over the nested JSON object.
Models.py
#classmethod
def get_client_data(cls, client_master_dict):
try:
response_list = []
client_id = client_master_dict['client_id']
client_details = cls.objects.filter(client_id = client_id,is_deleted = False)
bank_details = BankDetails.objects.filter(user_id = client_id,is_deleted = False)
document_details = DocumentDetails.objects.filter(user_id = client_id,is_deleted = False)
response_list.append(client_details)
response_list.append(bank_details)
response_list.append(document_details)
return response_list
except(Exception) as error:
print("Error in get_client_data",error)
return False
Here i'm fetching data from 3 tables and adding it into list.
After printing the data on console i am getting :
[{'id': 11, 'client_id': 'CL15657917080578748000', 'client_name': 'Pruthvi Katkar', 'client_pan_no': 'RGBB004A11', 'client_adhar_no': '12312312313', 'legal_entity_name': 'ABC', 'credit_period': '6 months', 'client_tin_no': 4564565, 'client_email_id': 'abc#gmail.com', 'head_office_name': 'ABC', 'office_name': 'asd234', 'office_email_id': 'zxc#gmail.com', 'office_contact': '022-27547119', 'gst_number': 'CGST786876876', 'office_country': 'India', 'office_state': 'gujrat', 'office_district': 'vadodara', 'office_taluka': 'kachh', 'office_city': 'vadodara', 'office_street': 'New rode 21', 'office_pincode': 2344445, 'contact_person_name': 'prasad', 'contact_person_designation': 'DM', 'contact_person_number': '456754655', 'contact_person_email': 'asd#gmail.com', 'contact_person_mobile': '5675545654', 'created_at': datetime.datetime(2019, 8, 14, 14, 8, 28, 57874, tzinfo=<UTC>), 'created_by': 'Prathamseh', 'updated_at': datetime.datetime(2019, 8, 14, 14, 8, 28, 57874, tzinfo=<UTC>), 'updated_by': 'prasad', 'is_deleted': False}]
[{'id': 11, 'user_id': 'CL15657917080578748000', 'bank_details_id': 'BL15657917080778611000', 'bank_name': 'Pruthvi', 'branch': 'vashi', 'ifsc_code': 'BOI786988', 'account_number': 56756765765765, 'account_name': 'Pruthvi', 'is_deleted': False}]
[{'id': 10, 'document_details_id': 'DL15657917080808598000', 'user_id': 'CL15657917080578748000', 'document_type': 'Pruthvi ID', 'document': 'www.sendgrid.com/pan', 'is_deleted': False}]
Did you check the output of record_result_list? You can outright tell their if it's recovering the data in the format you requested. Try the printing to screen method to debug.
As far as I cam see, the expected output and the hierarchy of results for bank details are not matching. I don't know how you are handling the hierarchy. Are you directly taking it from JSON as the hierarchy? Or are you just taking the data and creating hierarchy in the expected output?

How to send multiple objects through HttpResponse or JsonResponse in django

I have two objects influencer_data and user_list in my views function.I want to send both influencer_data and user_list through the HttpResponse method and obtain the data in Json format.
My views function is:
def index(request):
influencers = Influencer.objects.all()
influencer_data = serializers.serialize("json",influencers)
user_list = UserList.objects.all()
user_list = serializers.serialize("json",user_list)
context = {
'influencer_data':influencer_data,
'user_list':user_list,
}
return HttpResponse(influencer_data,user_list, content_type='application/json')
When I pass both influencer_data and user_list I get the error
__init__() got multiple values for argument 'content_type'
When I change the return HttpResponse statement to
return HttpResponse(context, content_type='application/json')
I get
influencer_datauser_list
i.e just the key values from the dictionary
When I change the return statement to
return HttpResponse(json.dumps(context), content_type='application/json')
I get the output as:
"influencer_data": "[{\"model\": \"influencer_listings.influencer\", \"pk\": 8794, \"fields\": {\"full_name\": \"F A I Z S H A I K H \\ud83c\\udf08\", \"username\": \"mr_faizzz_07\", \"photo\": \"\", \"email_id\": \"\", \"external_url\": \"\", \"location_city\": \"Mumbai\", \"categories\": \"\", \"hashtags\": \"['#foryou', '#blessyou', '#all', '#faizanshaikh', '#keepsmiling', '#blessed', '#look',
(The Json object becomes a string)
When I pass only one object i.e either influencer_data or user_list. I get a Json object i.e it works correctly(I want data in the given format)
[
{
"model": "influencer_listings.influencer",
"pk": 8794,
"fields": {
"full_name": "F A I Z S H A I K H 🌈",
"username": "mr_faizzz_07",
"photo": "",
"email_id": "",
"external_url": "",
"location_city": "Mumbai",
"categories": "",
"hashtags": "['#foryou', '#blessyou', '#all', '#faizanshaikh', '#keepsmiling', '#blessed', '#look', '#ramzan', '#loveyou', '#lover', '#cuteboys', '#keepgoing', '#picoftheday', '#feathers', '#brothers', '#faizshaikhhhh', '#pictures', '#jummahmubarak', '#lovers']",
How should I deal with this?
def index(request):
influencers = Influencer.objects.all().values()
user_list = UserList.objects.all().values()
context = {
'influencer_data': influencer_data,
'user_list': user_list,
}
data = json.dumps(context, indent=4, sort_keys=True, default=str)
return HttpResponse(data, content_type='application/json')

Mock Stripe Methods in Python for testing

So I am trying to mock all the stripe web hooks in the method so that I can write the Unit test for it. I am using the mock library for mocking the stripe methods. Here is the method I am trying to mock:
class AddCardView(APIView):
"""
* Add card for the customer
"""
permission_classes = (
CustomerPermission,
)
def post(self, request, format=None):
name = request.DATA.get('name', None)
cvc = request.DATA.get('cvc', None)
number = request.DATA.get('number', None)
expiry = request.DATA.get('expiry', None)
expiry_month, expiry_year = expiry.split("/")
customer_obj = request.user.contact.business.customer
customer = stripe.Customer.retrieve(customer_obj.stripe_id)
try:
card = customer.sources.create(
source={
"object": "card",
"number": number,
"exp_month": expiry_month,
"exp_year": expiry_year,
"cvc": cvc,
"name": name
}
)
# making it the default card
customer.default_source = card.id
customer.save()
except CardError as ce:
logger.error("Got CardError for customer_id={0}, CardError={1}".format(customer_obj.pk, ce.json_body))
return Response({"success": False, "error": "Failed to add card"})
else:
customer_obj.card_last_4 = card.get('last4')
customer_obj.card_kind = card.get('type', '')
customer_obj.card_fingerprint = card.get('fingerprint')
customer_obj.save()
return Response({"success": True})
This is the method for unit testing:
#mock.patch('stripe.Customer.retrieve')
#mock.patch('stripe.Customer.create')
def test_add_card(self,create_mock,retrieve_mock):
response = {
'default_card': None,
'cards': {
"count": 0,
"data": []
}
}
# save_mock.return_value = response
create_mock.return_value = response
retrieve_mock.return_value = response
self.api_client.client.login(username = self.username, password = self.password)
res = self.api_client.post('/biz/api/auth/card/add')
print res
Now stripe.Customer.retrieve is being mocked properly. But I am not able to mock customer.sources.create. I am really stuck on this.
This is the right way of doing it:
#mock.patch('stripe.Customer.retrieve')
def test_add_card_failure(self, retrieve_mock):
data = {
'name': "shubham",
'cvc': 123,
'number': "4242424242424242",
'expiry': "12/23",
}
e = CardError("Card Error", "", "")
retrieve_mock.return_value.sources.create.return_value = e
self.api_client.client.login(username=self.username, password=self.password)
res = self.api_client.post('/biz/api/auth/card/add', data=data)
self.assertEqual(self.deserialize(res)['success'], False)
Even though the given answer is correct, there is a way more comfortable solution using vcrpy. That is creating a cassette (record) once a given record does not exist yet. When it does, the mocking is done transparently and the record will be replayed. Beautiful.
Having a vanilla pyramid application, using py.test, my test now looks like this:
import vcr
# here we have some FactoryBoy fixtures
from tests.fixtures import PaymentServiceProviderFactory, SSOUserFactory
def test_post_transaction(sqla_session, test_app):
# first we need a PSP and a User existent in the DB
psp = PaymentServiceProviderFactory() # type: PaymentServiceProvider
user = SSOUserFactory()
sqla_session.add(psp, user)
sqla_session.flush()
with vcr.use_cassette('tests/casettes/tests.checkout.services.transaction_test.test_post_transaction.yaml'):
# with that PSP we create a new PSPTransaction ...
res = test_app.post(url='/psps/%s/transaction' % psp.id,
params={
'token': '4711',
'amount': '12.44',
'currency': 'EUR',
})
assert 201 == res.status_code
assert 'id' in res.json_body
IMO, the following method is better than the rest of the answers
import unittest
import stripe
import json
from unittest.mock import patch
from stripe.http_client import RequestsClient # to mock the request session
stripe.api_key = "foo"
stripe.default_http_client = RequestsClient() # assigning the default HTTP client
null = None
false = False
true = True
charge_resp = {
"id": "ch_1FgmT3DotIke6IEFVkwh2N6Y",
"object": "charge",
"amount": 1000,
"amount_captured": 1000,
"amount_refunded": 0,
"billing_details": {
"address": {
"city": "Los Angeles",
"country": "USA",
},
"email": null,
"name": "Jerin",
"phone": null
},
"captured": true,
}
def get_customer_city_from_charge(stripe_charge_id):
# this is our function and we are writing unit-test for this function
charge_response = stripe.Charge.retrieve("foo-bar")
return charge_response.billing_details.address.city
class TestStringMethods(unittest.TestCase):
#patch("stripe.default_http_client._session")
def test_get_customer_city_from_charge(self, mock_session):
mock_response = mock_session.request.return_value
mock_response.content.decode.return_value = json.dumps(charge_resp)
mock_response.status_code = 200
city_name = get_customer_city_from_charge("some_id")
self.assertEqual(city_name, "Los Angeles")
if __name__ == '__main__':
unittest.main()
Advantages of this method
You can generate the corresponding class objects (here, the charge_response variable is a type of Charge--(source code))
You can use the dot (.) operator over the response (as we can do with real stripe SDK)
dot operator support for deep attributes