Flask RestPlus/RestX: how do I share API models between Namespaces? - python

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.

Related

Django REST can't write custom Throttle and getting ImportError:

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

Django, drf-yasg - how to add description to tags?

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 want to add costume field after django social app login

Hi I am php developer new to python/django
I'm creating a social login with django using 'social-auth-app-django' library and i followed following tutorial to implement it.
https://simpleisbetterthancomplex.com/tutorial/2016/10/24/how-to-add-social-login-to-django.html
Its working fine but i also need to add costume files in database which will be in different table but it will be get added when new user is created.
I have extended the user table as following
from django.contrib.auth.models import User
class NewsCreator(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
CreatorLastLogs= models.CharField(max_length=100)
CreatorLogs= models.CharField(max_length=100)
and i want to add data to these fields when a new user is created or when existing user logins. I tried going through documentation but could not found any thing that is related to code extension/customisation etc. Thanks in advance
Hi i have found answer to this so i'm posting for people who will stumble upon this post later.
django social provides pipeline to extend their code, and we just have to extend this pipeline
for this in your setting.py file post following list(all in this list are default pipeline methods which gets called except for last one).
SOCIAL_AUTH_PIPELINE = (
'social_core.pipeline.social_auth.social_details',
'social_core.pipeline.social_auth.social_uid',
'social_core.pipeline.social_auth.auth_allowed',
'social_core.pipeline.social_auth.social_user',
'social_core.pipeline.user.get_username',
'social_core.pipeline.user.create_user',
'social_core.pipeline.social_auth.associate_user',
'social_core.pipeline.social_auth.load_extra_data',
'social_core.pipeline.user.user_details',
'newsapp.pipeline.save_profile'<-- this is your method
)
create a file in your app with name pipeline.py and name of method is to be provided in list above like last string in list (newsapp is name of my app provide your appname)
in your pipeline.py file
def save_profile(backend, user, response, *args, **kwargs):
if NewsCreator.objects.filter(user_id=user.id).count() == 0 :
newsCreator = NewsCreator.objects.create(user=user)
//your logic for new fields
newsCreator.save()
if you have any other query regarding django-social you can refer
https://github.com/python-social-auth/social-docs
its detail documentation

create_or_get with data from user input

Trying to implement a user registration form on a website I can't make user input to be added as a new user to the database. I'm using Flask with Peewee, and have:
nUser ={
'email': request.form['e_mail'],
'uname': request.form['username'],
'pword': request.form['password'],
'time': strftime('%Y-%m-%d %H:%M:%S')
}
nUser = User.create_or_get()
where nUser is temporary dict for new user. I should mention, that with the official peewee docs I tried nUser, created = User.create_or_get(nUser) what returned an error of too many arguments.
A code about User class is below (stored in separate .py, but there is from models import * up there):
class User(Model):
email=TextField()
uname=TextField(unique=True)
pword=TextField()
time=TextField()
class Meta:
database = db
Although it looks like it "works" from a webuser side, no record is added to the database. Previously I did it with User.select().where(User.uname...... and it worked, but now I would like to switch to create_or_get() method since it would shorten my code and looks more efficient. Logging in for old users works, so the connection and access to the DB is fine. I would appreciate any hints.
The official documentation that you link to show that create_or_get takes keyword arguments only. To pass a dict, you need to use the ** syntax:
User.create_or_get(**nuser)

Where shall I put 'initialization code' in a Django application?

I want some code in my Django app to be executed only once when server is started, not per request.
Specifically, I want to load some database tables into memory. These tables contain some 'metadata' that doesn't change per request. Like this:
ProductTypesData = None;
def loadProductTypesData():
productTypes = ProductType.objects.all();
for ptype in productTypes:
ptype_data = {
"id":ptype.id,
"name": ptype.name,
"description":ptype.desc
};
ProductTypesData.append(ptype_data);
loadProductTypesData();
Where should I put this code?
Other Q/A about django initialization suggest to put it in urls.py. But importing the models in urls.py doesn't seem logical to me.
Can I just put the code in models.py? Does it get executed only once (if it is acceptable to be executed not on django start)?

Categories

Resources