folder structure api/api_views.py
api_views.py
class BurstRateThrottle(UserRateThrottle):
scope = 'burst'
class SustainedRateThrottle(UserRateThrottle):
scope = 'sustained'
settings.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'api.api_views.BurstRateThrottle',
'api.api_views.SustainedRateThrottle'
],
'DEFAULT_THROTTLE_RATES': {
'burst': '60/min',
'sustained': '1000/day'
}
}
Getting this error : Could not import 'api.api_views.BurstRateThrottle' for API setting 'DEFAULT_THROTTLE_CLASSES'. ImportError: Module "api.api_views" does not define a "BurstRateThrottle" attribute/class.
I would suggest checking the official documentation which is very straightforward.
https://www.django-rest-framework.org/api-guide/throttling/#custom-throttles
Moreover, There are certain models that need to be overridden in order to be able to implement a fully working custom throttling solution. However, You can use the built-in functionality that throttling modules offer and customize it based on your needs.
Simple Example:
from rest_framework.throttling import UserRateThrottle
class ThrottleCheck(APIView):
throttle_class = UserRateThrottle
throttle_scope = "THIS SHOULD BE THE NAME YOU DEFINE IN YOUR SETTING FILE"
def get(self,request:Request)-> Response:
"""
SOME CODE GOES HERE.
The throttle would be triggered here
"""
The last words, Ideally if you can handle throttling from your Nginx side would make more sense Since on production this might be challenging using the Throttle class of Django-rest-framework.
Hope this helps. Happy Hacking
Related
I want to get a model in django using the current url
for example
a = resolve(request.path_info).url_name
context = { 'example' : a.objects.all }
here the retrieved url name is available in models
This obivously won't work but this is what I want to accomplish
You can access the request's resolver via request.resolver_match. See the docs here for more info. That can give you better access to the resolver than looking it up again.
Once you have that you can look up the model using the AppConfig.get_model method.
from django.apps import apps
ModelClass = apps.get_model(app_name, model_name)
Or
ModelClass = apps.get_model(f'{app_name}:{model_name}')
Swagger documentation says you can do that:
https://swagger.io/docs/specification/grouping-operations-with-tags/
But unfortunately drf-yasg not implementing this feature:
https://github.com/axnsan12/drf-yasg/issues/454
It is said, that I can add custom generator class, but it is a very general answer. Now I see that drf_yasg.openapi.Swagger gets info block and I have thoughts, that this might be right place to put global tags section as an additional init argument, but it deeper, than customizing generator class and I have lack of knowledge of this module
Does anybody have solution to this particular problem, or at least maybe a link to some sort of tutorial, how to properly customize generator class?
Not sure if this is exactly what your are looking for, but I think it might help.
To set tags I use #swagger_auto_schema decorator, which can be applied in a few different ways depending mostly on the type of Views used on your project. Complete details can be found on docs here.
When using Views derived from APIView, you could do something like this:
class ClientView(APIView):
#swagger_auto_schema(tags=['my custom tag'])
def get(self, request, client_id=None):
pass
According to the docs, the limitation is that tags only takes a list of strs as value. So from here on, I believe there is no support for extra attributes over tags as stated at Swagger docs, here.
Anyway, if you only need to define a summary or a description to obtain something like the image below, you could define them using the decorator or a class-level docstring. Here is an example:
class ClientView(APIView):
'''
get:
Client List serialized as JSON.
This is a description from a class level docstring.
'''
def get(self, request, client_id=None):
pass
#swagger_auto_schema(
operation_description="POST description override using
decorator",
operation_summary="this is the summary from decorator",
# request_body is used to specify parameters
request_body=openapi.Schema(
type=openapi.TYPE_OBJECT,
required=['name'],
properties={
'name': openapi.Schema(type=openapi.TYPE_STRING),
},
),
tags=['my custom tag']
)
def post(self, request):
pass
Good luck!
Unfortunately, this is a current issue with drf-yasg.
To actually achieve this, you need to create your own schema generator class:
from drf_yasg.generators import OpenAPISchemaGenerator
class CustomOpenAPISchemaGenerator(OpenAPISchemaGenerator):
def get_schema(self, request=None, public=False):
"""Generate a :class:`.Swagger` object with custom tags"""
swagger = super().get_schema(request, public)
swagger.tags = [
{
"name": "api",
"description": "everything about your API"
},
{
"name": "users",
"description": "everything about your users"
},
]
return swagger
Make sure to also include it in your Schema View
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
schema_view = get_schema_view(
openapi.Info(
title="My API",
default_version='v1',
),
generator_class=CustomOpenAPISchemaGenerator,
)
Hope this works for you!
I've got the following structure in my Flask-RestX application:
api_models
users
permissions
namespaces
users
permissions
I've got a permission_model in api_models/permissions which I want to use in user_model in api_models/users. Usecase:
Permission model: (in api_models/permissions.py)
permission_model = permission_api.model('Permission', {
"id": fields.String(description="Permission ID", required=True)
})
User model: (in api_models/users.py)
from .permissions import permission_model
user_model = users_api.model('User', {
"id": fields.String(description="User ID", required=True),
"permissions": fields.List(fields.Nested(permission_model))
})
I thought it's just as easy as importing models from one file to the other but the whole API breaks down when doing that ("No API definition provided."). I assume this is because they are attached to different Namespaces?
Is there a workaround?
How do people use models cross Namespaces?
Thanks.
This actually works as expected. After spending a lot of time trying to understand why models are not shared, I've started from scratch, reviewing every line of code and when I got to the Namespace registration block....I felt incredibly stupid: I forgot to register the actual "Permissions" Namespace into the app. Did that and now works fine and models are shared as expected.
I have a Django 1.11 project using Viewflow - https://github.com/viewflow/viewflow - that I've incorporated. It's been very helpful, but a lot of stuff is kind of "magic", and being my first serious Django project, I'm running into an issue I'm not sure of how to solve, or the best way.
I have a generic template that expects a lot of context. I have a function that adds this context to all of my views:
def add_general_context(context, MOC, MOC_enabled_fields = (), MOC_status = None):
context['MOC'] = MOC
context['current_date'] = timezone.now().strftime("%D")
context['MOC_form'] = forms.MOCForm(prefix="MOC_form", MOC_enabled_fields=MOC_enabled_fields, instance=MOC)
context['MOCAttachments'] = models.MOCAttachment.objects.filter(MOC=MOC)
context['MOCAttachment_form'] = forms.MOCAttachmentForm(prefix="MOCAttachment_form")
context['MOCApprovals'] = models.MOCApproval.objects.filter(MOC=MOC)
context['MOCTasks'] = models.MOCTask.objects.filter(MOC=MOC)
context['MOC_status'] = MOC_status
context['MOCConversation'] = models.MOCConversation.objects.filter(MOC=MOC)
# Add comments to the conversation
for conversation in context['MOCConversation']:
conversation.comments = models.MOCComment.objects.filter(conversation=conversation)
context['MOCComment_form'] = forms.MOCCommentForm(MOC=MOC)
context['MOCCommentReply_form'] = forms.MOCCommentReplyForm()
I basically need to add this context to a view that is inside viewflow - namely, AssignTaskView - https://github.com/viewflow/viewflow/blob/f50accb3cde5d53f1d4db0debf5936867712c3bd/viewflow/flow/views/task.py#L109
I've tried a few things to overwrite/add to the context, but none seem to work.
Attempt 1: Overwrite the URL and use extra_context (SO suggested this)
- The issue is that the urls are "magic", my urlpatterns is very simply:
from material.frontend import urls as frontend_urls
urlpatterns = [
url(r'^MOC/', include('MOC.urls')),
url(r'', include(frontend_urls)),
]
Overwriting the urls themselves was WAY over my head, I dug into it for a while, but it uses really generic functions to pull in modules, etc. I didn't have a clue how to really even attempt it.
Attempt 2: Overwrite the view itself and the get_context_data function
I think this would be possible, but it just doesn't seem to work. My attempts looked similar to this (the lastest one):
from viewflow.flow.views.task import AssignTaskView as CoreAssignTaskView
class AssignTaskView(CoreAssignTaskView):
def get_context_data(self, **kwargs):
context = super(AssignTaskView, self).get_context_data(**kwargs)
print("Did it work?")
return context
This is in my views.py - however, it simply doesn't run. I'm probably missing something, but I can't figure out how to actually force it to use my view instead of the one built in to viewflow.
I've successfully overwritten Viewflow's templates without issue, but overwriting anything else is beyond me. Any suggestions?
Yes you can actually override a view url by putting it on top of url_patterns
urlpatterns = [
url(
r'^/workflow/appname/flowname/(?P<process_pk>\d+)/taskname/(?P<task_pk>\d+)/assign/$',
YouCustomView.as_view(),
{'flow_task': FlowClass.taskname},
name="{}__assign".format(self.name)))
),
url(r'', include(frontend_urls)),
]
But it's simpler just to create a custom flow.View subclass and set you own Assign View
https://github.com/viewflow/viewflow/blob/master/viewflow/flow/nodes.py#L306
from viewflow import flow
class MyView(flow.View):
assign_view_class = MyAssignTaskView
flows.py:
class MyFlow(Flow):
...
taskname = MyView(UpdateProcessView).next(this.end)
That's how you can override any of the built-in views.
Viewflow designed to provide all knobs within your codebase. You can customize any behavior by subclassing Flow or flow Node classes.
The custom node example could be helpful
https://github.com/viewflow/viewflow/blob/master/demo/customnode/nodes.py
I have a web2py application where I have written various modules which hold business logic and database related stuff. In one of the files I am trying to access auth.settings.table_user_name but it doesn't work and throws and error as global name 'auth' is not defined. If I write the same line in controller, it works. But I want it to be accessed in module file. Please suggest how do I do that.
In your model file, where you define auth:
from gluon import current
auth = Auth(db)
current.auth = auth
Then in a module:
from gluon import current
def some_function():
auth = current.auth
....
For more details, see http://web2py.com/books/default/chapter/29/04/the-core#Accessing-the-API-from-Python-modules.
I was getting a very similar error ("name 'auth' is not defined"). Had to add from django.contrib import auth at the top of views.py and it worked.