Automation with Celery Periodic Tasks in Django 1.11 - django

I have implemented the following class based view below that creates a payslip and it's working perfectly. I was thinking further to automate this functionality by running it periodically i.e every month. How do I trigger the POST method with celery tasks.py to run periodically? I'm using celery==4.1.0,RabbitMQas my message broker,Python3andDjango 1.11anddjangorestframework==3.8.2`.
class PayslipPostAPIView(APIView):
"""
.. http:get:: /payslip_create/
**Request**:
.. sourcecode:: http
GET /payslip_create/web HTTP/1.1
Host: {{theDomain}}
Accept: application/json, text/javascript
**Response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: text/javascript
[
{
"id": 123,
"employee": 123,
"basic_salary": ["server", "web"],
"payment_mode": "I tried Nginx",
"currency": "Currency",
"payslip_no": "Payslip Number",
"month_ending": "Date",
"is_accounted": "True/False",
"created_at": "Date"
"modified_at": "Date",
"total_allowances": 123,
"total_deductions": 123,
"net_pay": 123,
"organization": 123
}
]
:reqheader Authorization: JWT token required to authenticate
.. http:post:: /payslip_create/
:param post_id: post's unique id
:type post_id: int
:reqheader Authorization: JWT token required to authenticate
:status 201: Payslip successfully Created
:status 400: Post parameters are invalid or missing
"""
permission_classes = (permissions.DjangoObjectPermissions,)
queryset = Payslip.objects.all()
model_list = [EmployeeProfile, Salary, Allowance, Deduction, PaymentMode]
def get(self, request, format=None):
payslip = Payslip.objects.filter(organization=get_auth(request)).all()
serializer = PayslipSerializer(payslip, many=True)
return Response(serializer.data)
def post(self, request, format=None):
try:
allowance_list = request.data.pop('allowance_list')
deduction_list = request.data.pop('deduction_list')
# employee = EmployeeProfile.objects.get(
# id=request.data.pop('employee'), organization=get_auth(request))
employee = EmployeeProfile.objects.get(id=request.data.pop('employee'),
organization=get_auth(request))
basic_salary = Salary.objects.get(
employee=employee)
# print(basic_salary)
payment_mode = PaymentMode.objects.get(
id=request.data.pop('payment_mode'), organization=get_auth(request))
data = request.data
data["organization"] = get_auth(request)
payslip = Payslip.objects.create(**data)
payslip.payslip_no = "PAYSLIP" + str(payslip.id) + "DT" + \
str(datetime.datetime.today())
payslip.basic_salary = basic_salary
payslip.employee = employee
payslip.payment_mode = payment_mode
payslip.save()
for item in allowance_list:
allowance = Allowance.objects.create(name=AllowanceType.objects.get(id=item['name']),
amount=item['amount'],
payslip=payslip,
organization=get_auth(
request)
)
for item in deduction_list:
ded = DeductionType.objects.get(id=item['name'])
deduction = Deduction.objects.create(name=ded,
amount=item['amount'],
payslip=payslip,
organization=get_auth(
request)
)
serializer = PayslipSerializer(payslip)
allow = Allowance.objects.filter(
payslip=payslip.id).aggregate(Sum('amount'))
deduct = Deduction.objects.filter(
payslip=payslip.id).aggregate(amount=Sum('amount'))
total_deductions = deduct['amount']
total_allowances = allow['amount__sum']
net_pay = (payslip.basic_salary.salary_value +
allow['amount__sum']) - deduct['amount']
payslip.total_deductions = total_deductions
payslip.total_allowances = total_allowances
payslip.basic_salary = basic_salary
payslip.organization = get_auth(request)
payslip.net_pay = net_pay
payslip.save()
serializer = PayslipSerializer(payslip)
payload = {
"allowances": list(Allowance.objects.filter(payslip=payslip.id, organization=get_auth(request)).values('name', 'amount', 'name__name')),
"deductions": list(Deduction.objects.filter(payslip=payslip.id, organization=get_auth(request)).values('name', 'amount', 'name__name')),
"app": "payroll",
"organization": get_auth(request),
"total_deductions": total_deductions,
"basic": payslip.basic_salary.salary_value,
"sal_grp": payslip.basic_salary.salary_group.name,
"total_allowances": total_allowances,
"net_pay": net_pay,
"paid": payslip.is_paid,
"data": json.dumps(serializer.data)
}
# print(payload)
###############################################
# Post the paslip entry updates to accounting #
###############################################
#
# ACC_IP = "http://0.0.0.0:8000"
accounting_url = ACC_IP + "/acc/incoming/transations/"
try:
if send_payslip_accounts(payload, accounting_url):
payslip.is_accounted = True
payslip.save()
return Response(data=json.dumps(serializer.data), status=status.HTTP_201_CREATED)
else:
payslip.is_accounted = False
payslip.save()
except Exception as e:
return Response(data=str(e), status=status.HTTP_400_BAD_REQUEST)
return Response(status=status.HTTP_201_CREATED)
except Exception as e:
raise e
return Response(serializer.data, status=status.HTTP_201_CREATED)

tasks.py
from celery import task
#task()
send_payslip_accounts(payload, accounting_url, payslip):
...
payslip.is_accounted = True
payslip.save()
views.py
from .tasks import send_payslip_accounts
class PayslipPostAPIView(APIView):
...
payslip.is_accounted = False
payslip.save()
send_payslip_accounts.apply_async((payload, accounting_url, payslip),)
...

Related

Is there a way I can get a list of all the items with balance variable in django

I have created an API that is being called by my react frontend. So the problem is this I have a viewset that shows a list of all customers in the database which works perfectly. I have also created a retrieve method that shows individual customer details and all the orders purchased. In this retrieve method, I have a variable that shows the balance for the customer. My question is, is there a way I can get a List of all customers with a balance that is greater than 0 and lower than 0
Here is my viewset
class CustomerViewSet(viewsets.ViewSet):
authentication_classes = [JWTAuthentication]
permission_classes = [IsAuthenticated]
def list(self, request):
customer = Customer.objects.all()
serializer = CustomerSerializer(customer, many=True, context={"request": request})
response_dict = {"error": False, "message": "All Customers List Data", "data": serializer.data}
return Response(response_dict)
def create(self, request):
try:
serializer = CustomerSerializer(data=request.data, context={"request": request})
serializer.is_valid(raise_exception=True)
serializer.save()
dict_response = {"error": False, "message": "Customer Data Stored Successfully"}
except:
dict_response = {"error": True, "message": "Phone Number Exists In Database, Fill All Fields"}
return Response(dict_response)
def retrieve(self, request, pk=None):
queryset = Customer.objects.all()
customer = get_object_or_404(queryset, pk=pk)
serializer = CustomerSerializer(customer, context={"request": request})
serializer_data = serializer.data
# Accessing All the Orders Details of Current Customer
orders_details = Orders.objects.filter(customer_id=serializer_data["id"]).order_by('-id')
orders_details_serializers = OrdersSerializer(orders_details, many=True)
serializer_data["orders"] = orders_details_serializers.data
# Accessing All Orders of Current Customer
orders_count = Orders.objects.filter(customer_id=serializer_data["id"])
orders_count_serializer = OrdersSerializer(orders_count, many=True, context={"request": request})
# Total orders amount of current customer
orders_total = Orders.objects.filter(customer_id=serializer_data["id"])
amount = 0
discount = 0
kgs = 0
for total in orders_total:
amount = amount + float(total.amount)
discount = discount + float(total.discount)
kgs = kgs + float(total.kgs)
serializer_data1 = serializer.data
# Accessing All the Payment Details of Current Customer
payments_details = Payments.objects.filter(customer_id=serializer_data1["id"]).order_by('-id')
payments_details_serializers = PaymentsSerializer(payments_details, many=True)
serializer_data["payments"] = payments_details_serializers.data
serializer_data2 = serializer_data
payment_count = Payments.objects.filter(customer_id=serializer_data2["id"])
payment_count_serializer = PaymentsSerializer(payment_count, many=True, context={"request": request})
# Total Payment of current customer
payment_total = Payments.objects.filter(customer_id=serializer_data2["id"])
t_amount = 0
for balance in payment_total:
t_amount = t_amount + float(balance.payment)
balance = amount - t_amount
dict_response = {"error": False, "message": "Single Data Fetch",
"data": serializer_data,
"payment": len(payment_count_serializer.data),
"buy_total": amount,
"payed_total": t_amount,
"balance": balance,
"kgs": kgs,
"discount": discount,
"orders_count": len(orders_count_serializer.data)}
return Response(dict_response)
def update(self, request, pk=None):
try:
queryset = Customer.objects.all()
customer = get_object_or_404(queryset, pk=pk)
serializer = CustomerSerializer(customer, data=request.data, context={"request": request})
serializer.is_valid(raise_exception=True)
serializer.save()
dict_response = {"error": False, "message": "Customer Data Updated Successfully"}
except:
dict_response = {"error": True, "message": "An Error Occurred"}
return Response(dict_response)
def destroy(self, request, pk=None):
queryset = Customer.objects.all()
customer = get_object_or_404(queryset, pk=pk)
# serializer = PaymentsSerializer(customer, context={"request": request})
customer.delete()
return Response({"error": False, "message": "Customer Deleted"})
Any idea or solution on how I can achieve that
Here is the solution you may like
from django.db.models import Sum
order = Orders.objects.filter(customer_id=serializer_data['id']).aggregate(Sum('amount'))
total_order_sum = order.get('amount__sum')
payment = Payments.objects.filter(customer_id=serializer_data2["id"])..aggregate(Sum('payment'))
total_payment_sum = payment.get('payment__sum')
balance = float(total_order_sum - total_payment_sum)

How to do pagination for a serializer field?

I have a task where I need to get stats and feedback by moderator ID. The 'stats' field is general, the 'feedback' field is a list of feedbacks. Can I make pagination for 'feedback' field? Of course I can make different endpoints for stats and feedback, but I'm not allowed to do this.
// GET /api/moderators/:id/feedback
{
"stats": [
{
"name": "123",
"value": -10
}
],
"feedback": [
{
"id": 1,
"createdBy": "FN LN",
"createdAt": "DT",
"comment": "",
"score": 5,
"categories": [
{
"name": "123",
"status": "POSITIVE/NEGETIVE/UNSET"
}
],
"webinarID": 123456
},
{
...
}
]
}
views.py
class TeacherFeedbackViewSet(ViewSet):
permission_classes = [IsAuthenticated, TeacherFeedbackPerm]
renderer_classes = [CamelCaseJSONRenderer]
#base_view
def list(self, request, pk):
moderator = get_object_or_404(Moderator, pk=pk)
serializer = ModeratorFeedback(moderator)
return Response(serializer.data)
serializers.py
class TeacherFeedbackSerializerDetail(ModelSerializer):
created_at = DateTimeField(source='datetime_filled')
created_by = SerializerMethodField(method_name='get_created_by')
categories = SerializerMethodField(method_name='get_categories')
webinar_id = IntegerField(source='webinar.id')
moderator_id = IntegerField(source='moderator.id')
class Meta:
model = TeacherFeedback
fields = ['id', 'created_by', 'created_at', 'categories', 'score', 'comment', 'moderator_id', 'webinar_id']
def get_categories(self, feedback: TeacherFeedback):
data = []
category_names = list(FeedbackCategory.objects.all().values_list('name', flat=True))
for category in feedback.category.all():
z = TeacherFeedbackCategory.objects.get(category=category, feedback=feedback)
data.append({"name": z.category.name, "status": z.status})
unset = list(map(lambda x: {"name": x, "status": "unset"},
list(set(category_names) - set([i["name"] for i in data]))))
return sorted(data + unset, key=lambda x: x["status"])
def get_created_by(self, feedback: TeacherFeedback):
return str(feedback.created_by.teacher)
class ModeratorFeedback(serializers.ModelSerializer):
stats = serializers.SerializerMethodField(method_name='get_stats_list')
feedback = TeacherFeedbackSerializerDetail(many=True, source='actual_feedbacks')
class Meta:
model = Moderator
fields = ['stats', 'feedback']
def get_stats_list(self, moderator: Moderator):
data = {}
for feedback in moderator.actual_feedbacks:
for category in feedback.category.all():
category_detail = TeacherFeedbackCategory.objects.get(feedback=feedback, category=category)
if category.name not in data:
data[category.name] = [category_detail.status]
else:
data[category.name].append(category_detail.status)
stats = []
for k, statuses in data.items():
weight = 100/len(statuses)
current_value = 0
for status in statuses:
if status == 'positive':
current_value += weight
else:
current_value -= weight
stats.append({"name": k, "value": float("{0:.2f}".format(current_value))})
return stats
In order to realize the pagination here, you need to make serializer for stats and feedback data respectively.
First you can define the ModeratorStats serializer.
class ModeratorStats(serializers.ModelSerializer):
stats = serializers.SerializerMethodField(method_name='get_stats_list')
class Meta:
model = Moderator
fields = ['stats']
def get_stats_list(self, moderator: Moderator):
...
And TeacherFeedbackSerializerDetail serializer is for the feedback.
Now in view,
from django.core.paginator import Paginator
from rest_framework.response import Response
class TeacherFeedbackViewSet(ViewSet):
...
#base_view
def list(self, request, pk):
moderator = get_object_or_404(Moderator, pk=pk)
# first get page and size param
page = int(request.GET.get('page', "1"))
size = int(request.GET.get('size', "10"))
# here I assumed the foreign key field name is `moderator`
query_set = TeacherFeedback.objects.filter(moderator__id = pk)
paginator = Paginator(query_set.order_by('id'), size)
feedbacks = paginator.page(page)
stats_data = ModeratorStats(moderator).data
feedbacks = TeacherFeedbackSerializerDetail(feedbacks, many=True).data
return Response({"stats": stats_data, "feedback": feedbacks})
And in frontend, you need to upload pagination params like ...?page=1&size=10.

TypeError: Field 'id' expected a number but got <django.contrib.auth.models.AnonymousUser object at 0x7f5e95756920>

first time I ask on the website.
I was testing a Django Restframework app.
The is to check an unauthenticated user that wants to create a review.
I got this error:
TypeError: Field 'id' expected a number but got <django.contrib.auth.models.AnonymousUser object at 0x7f5e95756920>.
this is the class test:
class ReviewTestCase(APITestCase):
def setUp(self):
self.user = User.objects.create_user(
username="example", password="Password#123")
self.token = Token.objects.get(user__username=self.user)
self.client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key)
self.stream = models.StreamPlatform.objects.create(
name="Netflix",
about="#1 Platform",
website="https://www.netflix.com"
)
self.watchlist = models.WatchList.objects.create(
platform=self.stream, title="Example Movie",
storyline="Example Movie",
active=True
)
self.watchlist2 = models.WatchList.objects.create(platform=self.stream, title="Example Movie",
storyline="Example Movie", active=True)
self.review = models.Review.objects.create(review_user=self.user, rating=5, description="Great Movie",
watchlist=self.watchlist2, active=True)
def test_review_create(self):
data = {
"review_user": self.user,
"rating": 5,
"description": "Great Movie!",
"watchlist": self.watchlist,
"active": True
}
response = self.client.post(
reverse('reviewcreate', args=(self.watchlist.id,)), data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(models.Review.objects.count(), 2)
response = self.client.post(
reverse('reviewcreate', args=(self.watchlist.id,)), data)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
**#The test who cause the error**
def test_review_create_unauth(self):
data = {
"review_user": self.user,
"rating": 5,
"description": "Great Movie!",
"watchlist": self.watchlist,
"active": True
}
self.client.force_authenticate(user=None, token=None)
response = self.client.post(
reverse('reviewcreate', args=(self.watchlist.id,)), data)
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
def test_review_update(self):
data = {
"review_user": self.user,
"rating": 4,
"description": "Great Movie! - Updated",
"watchlist": self.watchlist,
"active": False
}
response = self.client.put(
reverse('review-detail', args=(self.review.id,)), data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_review_list(self):
response = self.client.get(
reverse('movie-review', args=(self.watchlist.id,)))
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_review_ind(self):
response = self.client.get(
reverse('review-detail', args=(self.review.id,)))
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_review_ind_delete(self):
response = self.client.delete(
reverse('review-detail', args=(self.review.id,)))
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
def test_review_user(self):
response = self.client.get(
'/watch/review/?username' + self.user.username)
self.assertEqual(response.status_code, status.HTTP_200_OK)
In data items, you are passing an object, and you have to pasa an id. Change this:
review_user: self.user.id
Thanks to everyone,
I found the mistake.
In fact the problem was not in the func in the tests.py but in the view,
where I misspelled:
permission_classes = [IsAuthenticated]
with:
permission_clasees = [IsAuthenticated]
So everything is fine now.
Thanks again to all of you

How to render a json data into restapi?

I got a JSON response from some url. I have to show that into rest api but i got error. Here is my code
views
class StoreView(APIView):
serializer_class = PostcodeLookupSerializer
resp = requests.get('https://api.postcodes.io/postcodes/BN14 9GB')
resp_data = resp.json()['result']
result_dic = {
'longitude': resp_data['longitude'],
'latitude': resp_data['latitude']
}
result_data = JsonResponse(result_dic)
def result(self):
json_data = self.resp_data()
file_serializer = PostcodeLookupSerializer(json_data, many=True)
return Response(data=file_serializer.data, status=status.HTTP_200_OK)
serializer
class PostcodeLookupSerializer(serializers.Serializer):
postcode = serializers.CharField(required=True)
name = serializers.CharField(required=True)
and url
urlpatterns = [
path('views/', StoreView.as_view(), name='postcode_lookup'),]
how to display a json response into restapi?
I got this error
"detail": "Method \"GET\" not allowed."
You should return data inside response as below
return Response(data=file_serializer.data, status=status.HTTP_200_OK)

How to add extra attributes to queryset in django rest api using serialiser and listViewAPI?

How do I add additional fields like count, status_code to the queryset in the django rest api?
class SongList(generics.ListAPIView):
"""
API endpoint that allows users to be viewed or edited===1111.
"""
serializer_class = SongSerialier
def get_queryset(self):
queryset = Song.objects.all()
id = self.request.query_params.get('id', None)
test=QuerySet()
return queryset
Above code returns only the content in the SongSerialier in the form of list, for example
[
{
"song_title": "song1",
"file_type": "mp3",
"album": 1,
"test": "1",
"my_field": false
},
{
"song_title": "song1",
"file_type": "mp3",
"album": 2,
"test": "1",
"my_field": false
}
]
I want my output like below format
{
status_code:200,
count:2,
total_count:4,
data:[
{
"song_title": "song1",
"file_type": "mp3",
"album": 1,
"test": "1",
"my_field": false
},
{
"song_title": "song1",
"file_type": "mp3",
"album": 2,
"test": "1",
"my_field": false
}
]
}
GOT THE SOLUTION
*You need to override the list method in the ListAPIView *
class SongList(generics.ListAPIView):
i=0
"""
API endpoint that allows users to be viewed or edited===1111.
"""
serializer_class = SongSerialier
def list(self, request, *args, **kwargs):
response = super(SongList, self).list(request, args, kwargs)
# Add data to response.data Example for your object:
print("Data ::: ",type(response),response,response.data)#,dict(response.data))
print ("datat type: ",type(response.data))
d1 = collections.OrderedDict()
d1['a'] = 'A'
d1['b'] = 'B'
d1['c'] = 'C'
d1['d'] = 'D'
d1['e'] = 'E'
response.data=d1
self.no+=1
print ("no:2 ",self.no)
# response.data["a_status_code"]=200
# response.data["a_status_text"] = "Success"
#response['10_mi_count'] = 10
# a=response.render().content
# print ("a: ",a)
return response
def get_queryset(self):
self.no=1
print ("no:1 ",self.no)
queryset = Song.objects.all().annotate(count_test=Count('id'))
id = self.request.query_params.get('id', None)
test=QuerySet()
#print( "=========111" ,type(queryset),self.serializer_class.data)
# print ("j1: ",j)
# j+=1
return queryset
This will give the result as
Check link
following is my serializer code
class SongSerializer(serializers.ModelSerializer):
test=serializers.SerializerMethodField()
my_field = serializers.SerializerMethodField('is_named_bar')
def is_named_bar(self, foo):
return foo.id == "bar"
def get_test(self, obj):
print ("OBJ, ",obj,type(obj),obj.id)
return "1"
class Meta:
model=Song
fields=('song_title','file_type','album','test','my_field')