I am kind of new to API.
I am working on a project where I can send POST and GET requests to different APIs. I just want to know how sort of the class in the view file should look like.
For example, I have a class that inherits generics.GenericAPIView. How do I send a get request to a specific URL or how do I save the data using the serializer to the database with post request?
class ArticelViewSet(generics.GenericAPIView, mixins.ListModelMixin, mixins.CreateModelMixin):
serializer_class = ArticleSerializer_Modelserializers
queryset = Article.objects.all()
lookup_field = 'id'
def get(self, request, id=None):
if id:
return self.retrieve(request)
else:
return self.list(request)
def post(self, request):
return self.create(request) #return the created object
Related
I am sending django 2 forms in a post request 1 which works as intended and the other which fails to validate and as such is not saved.
the code for the form is here :
class Pick_Vulns(ModelForm):
class Meta:
model = ReportVuln
fields = "__all__"
widgets = {
'Vuln' : Select(attrs={'class':'form-control'}),
'Report' : HiddenInput(attrs={'Value': reportcount}),
}
This form loads correctly on the page with no issues but when the post request is sent it seems to be not be accepted and fails to validate.
an example of the post request :
a post request to the server the first param being a csrf token the next for being the working form the last two being part of the form that does not function.
The code for the post request within my django view is as follows :
def post(self, request):
forminput = Reportform(request.POST or None)
returnedvulns = Pick_Vulns(request.POST or None)
if request.user.is_staff == True:
if forminput.is_valid():
forminput.save()
if returnedvulns.is_valid():
returnedvulns.save()
forminput = Reportform
inoutform = {
'Reportform': forminput,
'reportvulns': pickvulns,
'ReportCount': Reportcount
}
return render(request, self.template_name, inoutform, )
the model to which the form is saved is here :
class ReportVuln(models.Model):
Vuln = models.ForeignKey(Vulnerability, on_delete=models.SET_NULL, null=True, related_name='Vulnerability')
Report = models.ForeignKey(Report, on_delete=models.SET_NULL, null=True) # allows for the referencing of reports
To my memory this has been working in the past and after some minor changes it seems to have broken.
error i recieve is :
ValueError at /reporting/Create
The ReportVuln could not be created because the data didn't validate.
Request Method: POST Request URL:
http://127.0.0.1:8000/reporting/Create Django Version: 3.0.2
Exception Type: ValueError Exception Value:
The ReportVuln could not be created because the data didn't validate.
if you need any more information please ask this is a key component and needs fixing. Thank you.
Im working on django rest framework and using a function based views. Im using 2 functions, one to render html and another for json response. How can I combine both the function to have more effecient code
My code
def register(request):
return render(request, 'register.html')
#api_view(['POST'])
#permission_classes((AllowAny,))
def create_user(request):
if request.method == 'POST':
serializer = SignupSerializer(data=request.data)
print 'ser'
print serializer
if not serializer.is_valid():
return Response(serializer.errors,\
status=status.HTTP_400_BAD_REQUEST)
else:
serializer.save()
return Response({
'status': 'Created',
'message': 'Verification email has been sent to your email. Please verify your account.'
}, status=status.HTTP_201_CREATED)
This can be handled by your serializer, as described in part2 of the drf tutorial.
It works like this:
urls.py
from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from your_app import views
urlpatterns = [
url(r'^blahblah/$', views.create_user),
]
urlpatterns = format_suffix_patterns(urlpatterns)
views.py
def create_user(request, format=None): # add this format argument
...
Based on the format argument, you can decide you want to the request to be rendered.
What I want is, if a user goes to this URL:
/user/22
then the front-end should render an HTML page for the user who's pk value is 22. This is my URLs.py:
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
urlpatterns = [
url(r'^user/(?P<pk>[0-9]+)$', views.UserPageView.as_view()),
url(r'^', include(router.urls)),
]
And this is UserPageView:
class UserPageView(generics.RetrieveAPIView):
queryset = User.objects.all()
renderer_classes = (TemplateHTMLRenderer,)
def get(self, request, *args, **kwargs):
self.user = self.get_object()
return Response({'user': self.user}, template_name='user.html')
And this is my UserViewSet:
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (IsCreationOrAuthenticated, IsWatchOrOwnerOrReadOnly,)
Assuming 'user' is a JS object, I plan on using my DRF API by sending a get request using AngularJS to the following URL:
("/users/" + user.pk) // which leads to UserViewSet (which serializes the user object)
to get the information for that specific user. However, user is not a JSON object, it is a Django variable which I can use in the template using the Django template tags, like so: {{ user }}.
How do I get my DRF view to return JSON to the HTML template as well? What's the best way for me to do this? Thanks in advance!
I'm not exactly sure if there's any chance that it will work the way you're currently doing at, as the first met URL will always direct you to the UserPageView.
However, perhaps you should take a look at DRF's format_suffixes.
With an additional format you can specify if you want to get the JSON or HTML representation of the user object.
i want to have custom json response after data post sendind to my Tastypie API models django.
class MyModelResource(ModelResource):
my_field=""
class Meta:
queryset = MyModel.objects.all()
resource_name = 'nick_name'
authentication = ApiKeyAuthentication()
authorization = DjangoAuthorization()
def hydrate(self, bundle):
#on recupere les donnée injectée par bundle.data['title']
#et on inject les donnée via bundle.obj.title
#bundle.data['my_field'] ="1234"
bundle.obj.my_field=bundle.data['my_field']
self.my_field = bundle.data['my_field']
return bundle
def wrap_view(self, view):
"""
Wraps views to return custom error codes instead of generic 500's
"""
#csrf_exempt
def wrapper(request, *args, **kwargs):
try:
callback = getattr(self, view)
response = callback(request, *args, **kwargs)
if request.is_ajax():
patch_cache_control(response, no_cache=True)
lst_dic=[]
mon_dic = dict(success=True, my_field=self.my_field
)
# response is a HttpResponse object, so follow Django's instructions
# to change it to your needs before you return it.
# https://docs.djangoproject.com/en/dev/ref/request-response/
lst_dic.append(mon_dic)
response = HttpResponse(simplejson.dumps(lst_dic), content_type='application/json')
return response
except (BadRequest, fields.ApiFieldError), e:
return HttpBadRequest({'success':False,'code': 666, 'message':e.args[0]})
except ValidationError, e:
# Or do some JSON wrapping around the standard 500
return HttpBadRequest({'success':False,'code': 777, 'message':', '.join(e.messages)})
except Exception, e:
# Rather than re-raising, we're going to things similar to
# what Django does. The difference is returning a serialized
# error message.
return self._handle_500(request, e)
return wrapper
My problem here, i can't grab the self.my_field value to put in mon_dic, i always have data object, not value...
thx for help
EDIT : Add my_field global variable, and then grab value from bundle that's it ;)
Maybe I am not understanding what you want to do here. But wrap_view is for handling customer error responses. If all you want to do is return the data that was posted, you can set always_return_data to true in your Meta:
class Meta:
always_return_data = True
Or if you want to control what data gets sent back, you can use the dehydrate method:
def dehydrate(self, bundle):
bundle.data['custom_field'] = "Whatever you want"
return bundle
Does anyone know how can I successfully retrieve the object count of a model, in JSON format, and how I need to configure my routing? I'm trying to achieve this using a APIView and returning a Response formatted by JSONRenderer.
UPDATE:
#api_view(['GET'])
#renderer_classes((JSONRenderer, JSONPRenderer))
def InfluenciasCountView(request, format=None):
influencia_count = Influencia.objects.count()
content = {'influencia_count': influencia_count}
return Response(content)
Here's the route I'm using:
url(r'^influencias/count/$', views.InfluenciasCountView, name='influencias-count')
Check out this snippet of code (the second one). If this does not suit your need, please add some of your code (for better understanding).
UPDATE
For routing, DRF offers a default router for each view. This means that you can have the following configuration in your urls.py: (using the example from the previous link)
url(r'^users/count/$', views. UserCountView.as_view(), name='users-count')
Then, when you access the URL your_base_url/users/count/ you will see something like {'user_count': 10}.
UPDATE 2
The entire code should look like this:
class UserCountView(APIView):
"""
A view that returns the count of active users.
"""
renderer_classes = (JSONRenderer, )
def get(self, request, format=None):
user_count = User.objects.count()
content = {'user_count': user_count}
return Response(content)
I am using routers from REST Framework to build my URLs. I tried above code but doesn't get it working. One of the problems is I cannot get /count/ into the router endpoints.
I checked DRF document (3.8.2) and found that there is a (new?) #action decorator (I was using 3.7.7 and it doesn't have it). So, here is my full solutions:
Upgrade DRF to 3.8.2 (or above) in requirements.txt (or PipFile if you using that).
Add a new action count method to the ModelViewSet
Update get_permissions to include the newly added action count
Here is my views.py:
from rest_framework.decorators import action
from rest_framework.response import Response
class PostViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows recommend to be viewed or edited.
"""
model = Post
queryset = Post.objects.filter(is_active=True)
serializer_class = serializers.PostSerializer
filter_backends = (filters.SearchFilter, DjangoFilterBackend,)
search_fields = ('title', 'body',)
filter_fields = ('status', 'type')
def get_permissions(self):
if self.action in ('list', 'retrieve', 'create', 'count'):
return (AllowAny()),
if self.action in ('update', 'partial_update'):
return (IsAdminUser()),
return (IsAdminUser()),
#action(detail=False)
def count(self, request):
queryset = self.filter_queryset(self.get_queryset())
count = queryset.count()
content = {'count': count}
return Response(content)
To query count of posts: /api/posts/count/?format=json
To query count of published: /api/posts/count/?format=json&status=published
One of the important thing here is to use the queryset from filter_queryset(...), rather than Post.objects.all().
UPDATE
Since count is common, I created a mixin for that.
from rest_framework.decorators import action
from rest_framework.response import Response
class CountModelMixin(object):
"""
Count a queryset.
"""
#action(detail=False)
def count(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
content = {'count': queryset.count()}
return Response(content)
To use it, just add CountModelMixin to your ModelViewSet (also support nested ModelViewSet).
class PostViewSet(viewsets.ModelViewSet, CountModelMixin):
If you use permissions, also add 'count' to the list of granted action.