I'm looking for a way/function/method to make it impossible to save two identical names on my JSON, for example, I got this JSON with repeated names:
[
[
{
"id": "59a5c80dc75969297837c51e",
"name": "uza",
"password": "3648726"
},
{}
],
[
{
"id": "59a5c811c75969297837c51f",
"name": "kuza",
"password": "3648726"
},
{}
],
[
{
"id": "59a5c83ec75969297837c520",
"name": "kuza",
"password": "3648726"
},
{}
]
]
My code that creates an user is this one:
#api.route('/', methods=['POST'])
def create():
# Grabs the data from the requisition
user_json = request.get_json(silent=True)
if not user_json:
return "FAIL"
# creates an entity JSON
user, errors = schema.load(user_json)
if bool(errors):
return jsonify(errors)
user.save()
return "SUCCESS"
Again, I'm using mongoengine, anybody knows how to do it?
Edited to add my model.py
rom mongoengine import Document
from mongoengine import StringField, ReferenceField
import marshmallow_mongoengine as ma
from marshmallow import Schema, fields
from .service import ImageService
class User(Document):
name = StringField(unique=True)
password = StringField(unique=True)
class Face(Document):
user = ReferenceField(User)
image = StringField()
embedding = StringField()
def get_embedding(self):
return ImageService().from_base64_flat(self.embedding.encode())
def get_image(self):
return ImageService().from_base64(self.image.encode())
class UserSchema(ma.ModelSchema):
class Meta:
model = User
class FaceSchema(ma.ModelSchema):
class Meta:
model = Face
image = ma.fields.Method(deserialize="img_to_base64", serialize="img_to_base64")
embedding = ma.fields.Method(deserialize="to_base64", serialize="to_base64")
def img_to_base64(self, data):
return ImageService().to_base64(data)
def to_base64(self, data):
return ImageService().np_to_base64(data)
In the class User i changed it from required to unique, now i can't add one with the same name but in exchange it returns an INTERNAL SERVER ERROR on Insomnia, and as you can see i put another unique on the password for test and it didn't worked it saves even if there is another user with the same password.
Try this
class User(Document):
name = StringField(unique=True)
password = StringField(unique=True)
meta = {
'indexes': [{'fields': ['name'], 'unique': True}]
}
Related
I'm using Django for my work project. What I need to get is all likes put by some user. Likes are put to transactions, so I am getting the list of all transactions in 'items' field, where the user put his like/dislike. There are some optional parameters that can be in the request:
{
"user_id": (usually is taken from session but can be used to get likes of specific user by admins),
"like_kind_id": (1 for like/2 for dislike),
"include_code_and_name": (True/False),
"page_size": (integer number) for pagination
}
With the last parameter, I am facing the issues. The result should look like this:
{
"user_id":id,
"likes":[
{
"like_kind":{
"id":id,
"code":like_code,
"name":like_name,
},
"items":[
{
"transaction_id":transaction_id,
"time_of":date_created,
},...
]
}
]
}
"Likes" is just array of 2 elements (like and dislike).
So, my problem is that I cannot set pagination for "items" array as there can be a lot of transactions. I am getting the page_size from request.data.get("page_size") but cannot apply it so that the results will be paginated. I know that for GET-requests I need simply set pagination_class in views.py. Anyone knows how can I do the similar procedure for POST-request and set the page_size of pagination class to 'page_size' from data.request? =)
This is my views.py:
class LikesUserPaginationAPIView(PageNumberPagination):
page_size = 1
page_size_query_param = 'page_size'
max_page_size = 1
class LikesUserListAPIView(APIView):
"""
All likes of the user
"""
permission_classes = [IsAuthenticated]
authentication_classes = [authentication.SessionAuthentication,
authentication.TokenAuthentication]
pagination_class = LikesUserPaginationAPIView
#classmethod
def post(cls, request, *args, **kwargs):
like_kind = request.data.get('like_kind')
include_code = request.data.get('include_code')
page_size = request.data.get('page_size')
pagination.PageNumberPagination.page_size = page_size
if include_code is None:
include_code = False
else:
if include_code == "False":
include_code = False
elif include_code == "True":
include_code = True
else:
return Response("Should be True или False for include_code",
status=status.HTTP_400_BAD_REQUEST)
if like_kind is None:
like_kind = "all"
else:
try:
likekind = LikeKind.objects.get(id=like_kind)
except LikeKind.DoesNotExist:
return Response("ID doesn't exists ",
status=status.HTTP_404_NOT_FOUND)
context = {"include_code": include_code, "like_kind": like_kind}
user_id = request.user.id # get the user_id from session
# TODO
# optionally other users with higher privilege can get access to other users' likes
# need to check for the privilege (admin, coordinator, ..)
# user_id = request.data.get('user_id')
if user_id is not None:
try:
user = User.objects.get(id=user_id)
users = [user, user, user, user, user]
serializer = LikeUserSerializer(users, many=True, context=context)
return Response(serializer.data)
except User.DoesNotExist:
return Response("ID doesn't exists ",
status=status.HTTP_404_NOT_FOUND)
return Response("user_id is not given",
status=status.HTTP_400_BAD_REQUEST)
My serializer.py:
class LikeUserSerializer(serializers.ModelSerializer):
likes = serializers.SerializerMethodField()
user_id = serializers.SerializerMethodField()
def get_user_id(self, obj):
return obj.id
def get_likes(self, obj):
include_code = self.context.get('include_code')
like_kind_id = self.context.get('like_kind')
likes = []
if like_kind_id == "all":
like_kinds = [(like_kind.id, like_kind.name, like_kind.get_icon_url()) for like_kind in LikeKind.objects.all()]
else:
like_kinds = [(like_kind.id, like_kind.name, like_kind.get_icon_url()) for like_kind in
[LikeKind.objects.get(id=like_kind_id)]]
# {"user_id": 1}
if include_code:
for like_kind in like_kinds:
items = []
transactions_liked = [(like.transaction_id, like.date_created)
for like in Like.objects.filter_by_user_and_like_kind(obj.id, like_kind[0])]
for transaction1 in transactions_liked:
items.append(
{
"transaction_id": transaction1[0],
"time_of": transaction1[1],
}
)
likes.append(
{
"like_kind": {
'id': like_kind[0],
'name': like_kind[1],
'icon': like_kind[2],
},
"items": items
}
)
return likes
else:
for like_kind in like_kinds:
items = []
transactions_liked = [(like.transaction_id, like.date_created)
for like in Like.objects.filter_by_user_and_like_kind(obj.id, like_kind[0])]
for transaction1 in transactions_liked:
items.append(
{
"transaction_id": transaction1[0],
"time_of": transaction1[1],
}
)
likes.append(
{
"like_kind": {
'id': like_kind[0],
},
"items": items
}
)
return likes
class Meta:
model = Like
fields = ['user_id', 'likes']
In urls.py I have the following path:
path('get-likes-by-user/', likes_views.LikesUserListAPIView.as_view()),
If you have any questions, please ask. Thanks, all!! I will appreciate your help!
I am trying to perform the unit test for a feature in my website, whereby the user uploads a JSON file and I test if the JSON file is valid using serialization and JSON schema. When running the following test code I keep getting assertion error.
serializer.py
class Serializer(serializers.Serializer):
file = serializers.FileField(required=True)
format = serializers.CharField(required=True)
def validate(self, data):
is_valid, message = Validation().is_valid(
json.loads(data.read()))
if (not (is_valid)):
raise serializers.ValidationError(message)
tests.py
class Validation(TestCase):
def test_valid_serializer(self):
file_mock = mock.MagicMock(spec=File)
file_mock.name = 'mock.json'
file_mock.content = {
'mockData': [{
"id": 1,
"name": "blue",
}]
}
serializer_class = Serializer(data=file_mock.content)
assert serializer_class.is_valid()
assert serializer_class.errors == {}
Maybe you need to SimpleUploadedFile to wrap the file_mock?
from django.core.files.uploadedfile import SimpleUploadedFile
I'm pretty new to Django restframework, what i'm trying now is to return object with foreignkey.
class User(models.Model):
name = models.CharField(max_length=255,blank=True)
date_created = models.DateTimeField(auto_now_add=True)
date_modiefied = models.DateTimeField(auto_now=True)
area = models.CharField(max_length=255,blank=True)
uuid = models.CharField(max_length=255)
home = models.CharField(max_length=255,blank=True)
work = models.CharField(max_length=255,blank=True)
mobileNo = models.CharField(max_length=255,blank=True)
email = models.CharField(max_length=255,blank=True)
appVersionCode = models.CharField(max_length=255,blank=True)
photoUrl = models.CharField(max_length=255,blank=True)
serverTime = models.CharField(max_length=255,blank=True)
fcmTokenId = models.CharField(max_length=255,blank=True)
def __str__(self):
return self.name
class LocationData(models.Model):
user = models.ForeignKey(
User, related_name='user', on_delete=models.DO_NOTHING)
source_id = models.CharField(max_length=255)
latitude = models.CharField(max_length=255)
longitude = models.CharField(max_length=255)
speed = models.CharField(max_length=255)
kms = models.CharField(max_length=255)
date_created = models.DateTimeField(auto_now=True)
date_modiefied = models.DateTimeField(auto
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
class LocationDataSerializer(serializers.ModelSerializer):
class Meta:
model = LocationData
fields = '__all__'
depth = 1
I'm using def get_queryset(self):
class SyncIndexLastDataViewSet(viewsets.ModelViewSet):
serializer_class = LocationDataSerializer
def get_queryset(self):
userid = self.request.query_params.get('user_id', None)
userExist = User.objects.filter(id=userid)
if userExist.exists():
# call the original 'list' to get the original response
queryset = LocationData.objects.values('source_id').filter(user__id=userid).order_by('-source_id')[:1]
lastSourceId = queryset[0]['source_id']
response = {"collection": {"data": lastSourceId,"statusCode": status.HTTP_200_OK,"version":"1.0"}}
json = JSONRenderer().render(response)
# customize the response data
if response is not None:
return json
else:
# return response with this custom representation
response = {"collection": {"data": "","statusCode":status.HTTP_404_NOT_FOUND,"version":"1.0","error":"Not found"}}
return response
Right now the result is inside the response is below and immediately it throws this error
But i want that queryset to return as below one, Hence i can read those key-pair values in android
{ "collection": {
"data": {
"id": 31,
"source_id": "55",
"latitude": "24654",
"longitude": "454654",
"date_created": "2019-02-08T17:10:09.318644Z",
"date_modiefied": "2019-02-08T17:10:09.318714Z",
"area": "54546",
"user": {
"id": 1,
"name": "Dormy",
"date_created": "1992-01-18T03:29:53.388000Z",
"date_modiefied": "2018-02-19T05:17:00.164000Z",
"serverTime": "",
"fcmTokenId": ""
}
},
"statusCode": 200,
"version": "1.0"
}
Now the error throws
AttributeError: Got AttributeError when attempting to get a value for field source_id on serializer LocationDataSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the int instance.
Original exception text was: 'int' object has no attribute 'source_id'.
Thanks!
The answer to this depends on what type of view you are using but the bottom line is you don't do this in get_queryset you do this in the method for the type of reguest.
For example if you are using a RetrieveAPIView you should override the retrieve method from the RetrieveModelMixin like so:
class MyAPIView(RetrieveAPIView):
queryset = MyModel.objects.all()
serializer_class = MySerializer
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
data = {
"collection": {
"data": serializer.data
},
"statusCode": 200,
"version": "1.0"
}
return Response(data)
If you are using something else like a ListAPIView then you want to see what is used by that in the relevant method and override that to wrap your data.
The main thing to realise here is that it has nothing to do with getting the queryset - which is just about getting data from the database. This is about transforming the data into the correct format when sending back a response. As a result the work should be done at the point the response is made.
There are couple of solution possible for this problem. NDevox already mention how we can overwrite our retrive function and get our expected response. But If we want this will be done with every response for every api end-point and if we go this way we need to overwrite every function then its quite burden and its DRY we should avoid this as possible. One of the possible way to introduce a middleware or overwrite Response so that we can get our generic response for every-api end-point without explicitly overwrite every functionality.
Possible Solution One
As we are using DRF here we can add our own return responses with various media types, say for application/json.
First We need to add in our settings.py
REST_FRAMEWORK = {
...
'DEFAULT_RENDERER_CLASSES': (
'app_name.renderers.ApiRenderer', # our own render middleware
),
...
}
And in our custom render middleware
from rest_framework.renderers import BaseRenderer
from rest_framework.utils import json
class ApiRenderer(BaseRenderer):
def render(self, data, accepted_media_type=None, renderer_context=None):
our_response_dict = {
'version': '1.0'
'data': {},
'message': '',
}
if data.get('data'):
our_response_dict['data'] = data.get('data')
if data.get('status'):
our_response_dict['statusCode'] = data.get('status')
if data.get('message'):
our_response_dict['message'] = data.get('message')
data = our_response_dict
return json.dumps(data)
Reference Link
Possible Solution Two
If we are using ModelViewset then there is another way we can achievement that. Say Our Views.py are like following
class A(serializer.ModelSerializer):
........
class B(serializer.ModelSerializer):
........
class C(serializer.ModelSerializer):
........
Our goal is to overwrite ModelViewset's to_representation function and return our custom result. This will like as following
from collections import OrderedDict
class OurParentViewset(serializer.ModelSerializer):
......
def to_representation(self, instance):
data = super(serializers.ModelSerializer, self).to_representation(instance)
result = OrderedDict()
result['data'] = data
result['version'] = '1.0'
result['statusCode'] = '2xx' # i am not fully sure how to customize this
return result
class A(OurParentViewset):
........
class B(OurParentViewset):
........
class C(OurParentViewset):
........
Implementing a custom renderer here seems to be a ways to go.
You can have requests from your android client include in the Accept header a way to identify the client to the renderer. 1 e.g.
Accept: application/json; android=true
Then compose a renderer using the JSONRenderer class to provide the format for your Android client.
# ./formatters/android_format.py
from rest_framework.renderers import JSONRenderer, BaseRenderer
from django.http.multipartparser import parse_header
class AndroidV1FormatRenderer(BaseRenderer):
media_type = 'application/json'
format = 'json'
json_renderer = JSONRenderer()
def android(self, accepted_media_type):
base_media_type, params = parse_header(accepted_media_type.encode('ascii'))
return 'android' in params
def render(self, data, accepted_media_type=None, renderer_context=None):
response = renderer_context['response']
android = self.android(accepted_media_type)
if android:
data = {
"collection": {"data": data},
"statusCode": response.status_code,
"version": "1.0"
}
return json_renderer.render(
wrapped_data, accepted_media_type, renderer_context)
This can then be used where you require response formatted that way using renderer_classes attribute of your APIView. 2
Since get_queryset won't allow you to customize the response data. I decide to take the query value that's important to me.
http://localhost/api/users/?user_id=1 --> changed into ...api/users/1
def retrieve(self, request, *args, **kwargs):
""" userid = self.request.query_params.get('user_id', None) """
userid = kwargs.get('pk')
userExist = User.objects.filter(id=userid)
if userExist.exists():
# call the original 'list' to get the original response
queryset = LocationData.objects.values('source_id').filter(user__id=userid).order_by('-source_id')[:1]
lastSourceId = queryset[0]['source_id']
response = {"collection": {"data": lastSourceId,"statusCode": status.HTTP_200_OK,"version":"1.0"}}
# customize the response data
if response is not None:
return Response(response)
else:
# return response with this custom representation
response = {"collection": {"data": "","statusCode":status.HTTP_404_NOT_FOUND,"version":"1.0","error":"Not found"}}
return response
I am following this tutorial for using Graphene with Django, and everything was going smooth, until I reached the Integration with Django Rest Framework section.
This section says that you can reuse DRF serializers with Graphene, by creating serializers clones, but it doesn't say what to do with such clones in order to reuse DRF serializers with Graphene.
These are my serializers and clones:
from rest_framework import serializers
from graphene_django.rest_framework.mutation import SerializerMutation
from GeneralApp.models import Airport
from ReservationsManagerApp.serializers import ReservationSerializer
from ReservationsManagerApp.models import ReservationComponent, ReservationHotel, ReservationRoundtrip, ReservationTransfer, ReservationTour, ReservationService, Hotel
class ReservationMutation(SerializerMutation):
class Meta:
serializer_class = ReservationSerializer
class ReservationComponentGraphSerializer(serializers.ModelSerializer):
component = serializers.SerializerMethodField()
class Meta:
model = ReservationComponent
fields = ('id', 'reservation', 'dertour_bk', 'day', 'content_type', 'object_id', 'comment', 'is_invoiced', 'component')
def get_component(self, instance):
components_models = {
'reservationhotel': ReservationHotel,
'reservationroundtrip': ReservationRoundtrip,
'reservationtransfer': ReservationTransfer,
'reservationtour': ReservationTour,
'reservationservice': ReservationService,
}
component = components_models[instance.content_type.model].objects.get(id=instance.object_id)
return self.get_component_string(instance.content_type.model, component)
def get_component_string(self, component_model, component):
components_get_string = {
'reservationhotel': self.get_hotel_string,
'reservationroundtrip': self.get_roundtrip_string,
'reservationtransfer': self.get_transfer_string,
'reservationtour': self.get_tour_string,
'reservationservice': self.get_service_string,
}
return components_get_string[component_model](component):
def get_hotel_string(self, component):
return component.hotel.name
def get_roundtrip_string(self, component):
return component.roundtrip.name
def get_transfer_string(self, component):
origin_str = self.get_place_str('origin', component)
destination_str = self.get_place_str('destination', component)
return "{} => {}".format(origin_str, destination_str)
def get_place_str(self, case, component):
places_models = {
'airport': Airport,
'hotel': Hotel,
}
if case == 'origin':
return places_models[component.origin_content_type.model].objects.get(id=component.origin_object_id).name
else:
return places_models[component.destination_content_type.model].objects.get(id=component.destination_object_id).name
def get_tour_string(self, component):
return component.tour.name
def get_service_string(self, component):
return component.service.name
class ReservationComponentMutation(SerializerMutation):
class Meta:
serializer_class = ReservationComponentGraphSerializer
And this is my schemas.py:
import graphene
from graphene_django.types import DjangoObjectType
from ReservationsManagerApp.models import Reservation, ReservationComponent
from InvoicesManagerApp.models import Invoice, InvoiceEntry, InvoiceEntryComponent
from PaymentsManagerApp.models import Payment, PaymentReservationComponent
class ReservationType(DjangoObjectType):
class Meta:
model = Reservation
class ReservationComponentType(DjangoObjectType):
class Meta:
model = ReservationComponent
class InvoiceType(DjangoObjectType):
class Meta:
model = Invoice
class InvoiceEntryType(DjangoObjectType):
class Meta:
model = InvoiceEntry
class InvoiceEntryComponentType(DjangoObjectType):
class Meta:
model = InvoiceEntryComponent
class PaymentType(DjangoObjectType):
class Meta:
model = Payment
class PaymentReservationComponentType(DjangoObjectType):
class Meta:
model = PaymentReservationComponent
class Query(object):
all_reservations = graphene.List(ReservationType)
all_reservation_components = graphene.List(ReservationComponentType)
all_invoices = graphene.List(InvoiceType)
all_invoice_components = graphene.List(InvoiceEntryType)
all_invoice_entries_components = graphene.List(InvoiceEntryComponentType)
all_payment = graphene.List(PaymentType)
all_payment_reservation_components = graphene.List(PaymentReservationComponentType)
def resolve_all_reservations(self, info, **kwargs):
return Reservation.objects.all()
def resolve_all_reservation_components(self, info, **kwargs):
return ReservationComponent.objects.select_related('reservation').all()
def resolve_all_invoice_entries_components(self, info, **kwargs):
return InvoiceEntryComponent.objects.select_related('reservation_component').all()
def resolve_all_payment_reservation_components(self, info, **kwargs):
return PaymentReservationComponent.objects.select_related('reservation_component').all()
I don't know if I am missing something obvious, but I can't understand how am I suppose to use those serializers mutations with graphene. I guess it must be by configuring the Query class in some way, but I can't find a reference in the documentation.
I don't see any reason why we have to do as shown in that tutorial. It is much easier to connect drf and graphql in following way. Doing this way,you do not need to worry about any vague classes and just rely on main aspects of drf and graphene.
Construct drf serializers normally, and connect it to graphql as shown below.
Consider we have model Subject. Let's create CRUD api for it.
from graphene.types.scalars import Scalar
class ObjectField(Scalar): # to serialize error message from serializer
#staticmethod
def serialize(dt):
return dt
class SubjectType(DjangoObjectType):
class Meta:
model=Subject
# For mutation, use serializers
#creating subject
class CreateSubject(graphene.Mutation):
subject=graphene.Field(SubjectType)
message=ObjectField()
status=graphene.Int()
class Arguments:
name=graphene.String(required=True)
description=graphene.String(required=True)
#classmethod
def mutate(cls,root,info,**kwargs):
serializer=SubjectSerializer(data=kwargs)
if serializer.is_valid():
obj=serializer.save()
msg='success'
else:
msg=serializer.errors
obj=None
print(msg)
return cls(subject=obj,message=msg,status=200)
'''Updating subject'''
class UpdateSubject(graphene.Mutation):
subject=graphene.Field(SubjectType)
status=graphene.Int()
message=ObjectField()
class Arguments:
id=graphene.ID(required=True)
name=graphene.String()
description=graphene.String()
#classmethod
def mutate(cls,root,info,id,**kwargs):
sub=Subject.objects.get(id=id)
serializer=SubjectSerializer(sub,data=kwargs,partial=True)
if serializer.is_valid():
obj=serializer.save()
msg='success'
else:
msg=serializer.errors
obj=None
print(msg)
return cls(subject=obj,message=msg,status=200)
'''Delete Subject'''
class DeleteSubject(graphene.Mutation):
message=ObjectField()
status=graphene.Int()
class Arguments:
id=graphene.ID(required=True)
#classmethod
def mutate(cls,root,info,id,**kwargs):
c=Subject.objects.get(id=id)
c.delete()
return cls(message='success',status=200)
class Mutation(graphene.ObjectType):
create_subject=CreateSubject.Field()
update_subject=UpdateSubject.Field()
delete_subject=DeleteSubject.Field()
# Query is normal.
class Query(graphene.ObjectType):
subject=graphene.Field(SubjectType,id=graphene.Int(), slug=graphene.String())
subjects=graphene.List(SubjectType)
def resolve_subject(self, info, id=None, slug=None):
if id:
return Subject.objects.get(id=id)
if slug:
return Subject.objects.get(slug=slug)
def resolve_subjects(self,info,**kwargs):
return Subject.objects.all()
You can try making little framework-like thing for yourself to avoid redundant code as seen.
From your example:
import graphene
from your.schemas import Query as YourQuery
from your.serializers import ReservationComponentMutation
# notice its an objecttype, and i've also added some debug
class Mutation(graphene.ObjectType):
debug = graphene.Field(DjangoDebug, name="_debug")
create_reservation = ReservationComponentMutation.Field()
class Query(YourQuery, graphene.ObjectType):
pass
class Mutation(Mutation, graphene.ObjectType):
pass
root_schema = graphene.Schema(query=Query, mutation=Mutation)
And the url:
urlpatterns = (
url(r"^graphql", GraphQLView.as_view(schema=root_schema graphiql=True), name="graphql"),
)
# you can wrap csrf_exempt(GraphQLView.as_view(...)) for testing
# or you can setup the frontend `apollo-client` to use csrf_tokens
# also see the related links below
For example for apollo-client and not apollo-boost the window.csrf_token is {% csrf_token %} in the template rendering:
import { ApolloProvider } from "react-apollo";
import ApolloClient from "apollo-client";
import { HttpLink } from "apollo-link-http";
import { InMemoryCache as Cache } from "apollo-cache-inmemory";
import { ApolloLink } from "apollo-link";
import fetch from "unfetch";
const uri = UrlUtils.makeUrl(Urls.graphQl);
const AuthLink = (operation, next) => {
const token = window.csrf_token;
operation.setContext(context => ({
...context,
headers: {
...context.headers,
"X-CSRFToken": token
}
}));
return next(operation);
};
const link = ApolloLink.from([
AuthLink,
new HttpLink({
uri,
credentials: "same-origin",
fetch // override fetch implementation for polyfills
})
]);
const apollo = new ApolloClient({
link,
cache: new Cache().restore({})
});
You should then be able to:
query TestQuery() {
resolveAllReservations () {
id
}
}
or:
mutate TestMutate($input: ReservationComponentMutationInput!) {
createReservation(input: $input) {
id
errors {
field
messages
}
}
_debug {
sql {
rawSql
}
}
}
related:
https://stackoverflow.com/a/39026832/2026508
URL: / client /[client_id]/ log / operator
Method: POST
Data:
{
"access_token": "TOKEN",
"limit": 100,
"sort": "asc",
"start_date": "2018-01-01T00: 00: 00Z"
}
OR
{
"access_token": "TOKEN",
"limit": 100,
"sort": "asc",
"offset": "500"
}
Success Response:
{
"result": "ok",
"logs": [
{
"date": "2018-01-01T00: 00: 00Z",
"text": "Log entry"
},
...
]
}
Log entry in the format: "message. User: name the name of the operator."
I need to create a request to receive logs of operator activity. Which returns a formatted log of all user actions.
I have an activity application in which there is an OperatorLog model.
from django.db import models
from users.models import User
from .constants import ACTIVITY_ACTIONS
class OperatorLogManager(models.Manager):
"""Manager for operator logs"""
def active(self):
"""Mark object as active"""
return self.filter(is_delete=False)
def get_by_user_id(self, id):
return self.active().filter(pk=id)
def get_by_client_id(self, client_uid):
return self.active().filter(client_uid=client_uid)
class OperatorLog(models.Model):
"""Model for logs"""
user = models.ForeignKey(User, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
is_deleted = models.BooleanField(default=False)
action_type = models.CharField(max_length=32,
сhoices=ACTIVITY_ACTIONS)
message = models.TextField(max_length=2048)
client_uid = models.CharField(max_length=50)
bitrix_id = models.PositiveIntegerField()
# Operator Manager
objects = OperatorLogManager()
def delete(self, **kwargs):
self.is_deleted = True
self.save()
You need a public api (activity / api.py) to register events in other applications,
There is also a file with a list of activity types (constants.py), it should be available in other applications via the import of api.py, you need to output the logs using the serializer (DRF).
constants.py (Sample version)
from model_utils import Choices
ACTIVITY_ACTIONS = Choices (
('ACTION_REQ_PHONE_VERIFY', 'Request phone verification'),
('VALIDATE_PHONE', 'Request phone validation'),
('VALIDATE_EMAIL', 'Email validation'),
('SET_INTERNAL_VERIFY', 'Set result of Internal verification'),
('SET_BANK_VERIFY', 'Set result of Bank verification'),
('GET_CLIENT_DATA', 'Request client data'),
('GET_SENSITIVE_INFO', 'Request sensitive info'),
)
Try the logging library, where you can access various type of log messages
like-
Error, Debug, Warning or just Information.
You can read more about here:
https://docs.python.org/3/library/logging.html