I am using django-oscar for my development.
I have created a new app as per my requirement
views.py
class MediaImportView(TemplateView):
template_name = 'lookup/import_media_file.html'
def get(self, request):
ctx = {}
return render(self.template_name, ctx, request, using=request)
getting the error as below.
InvalidTemplateEngineError at /import_media_file
Could not find config for '<WSGIRequest: GET '/import_media_file'>' in settings.TEMPLATES
From the documentation, the using argument takes:
The NAME of a template engine to use for loading the template.
Instead of passing the name of a template engine, you are passing a request object, hence the error. In addition, all your other arguments are wrong as well - the signature of this function is:
render(request, template_name, context=None, content_type=None, status=None, using=None)
So the first argument needs to be a request, the second a template name, and the third the context. Something like this:
return render(request, self.template_name, ctx)
Related
Summary of the problem:
I'm running a requests call on an API endpoint, whose request params are hidden in a config file and I decided to try out hydra to retrieve those params [Reason being the request params do change as I'm working on collecting custom dataset using RapidAPI]
I have created a class called QueryParamsLocations which implements the getter methods to fetch the parameters to be later used by run_query method.
class QueryParamsLocations(QueryParams):
#hydra.main(config_path='configs', config_name='location_query')
def get_params_query_string(self, cfg: DictConfig) -> dict():
return {
'query': cfg.location_params.query,
'locale': cfg.location_params.locale,
'currency': cfg.location_params.currency
}
#hydra.main(config_path='configs', config_name='location_query')
def get_url(self, cfg: DictConfig) -> str():
return cfg.urls.location_url
#hydra.main(config_path='configs', config_name='location_query')
def get_headers(self, cfg: DictConfig) -> dict():
return {
'X-RapidAPI-Host': cfg.headers.x_rapidapi_host,
'X-RapidAPI-Key': cfg.headers.x_rapidapi_key
}
class QueryParams is an abstract class which has these 3 getter templates. run_query method is an external call to run the request.
#hydra.main(config_path='configs', config_name='location_query')
def run_query(cfg: DictConfig) -> None:
try:
LoggerFactory.get_logger('logs/logger.log', 'INFO').info('Running query for location')
qpl = QueryParamsLocations()
response = requests.request("GET", qpl.get_url(cfg), headers=qpl.get_headers(cfg), params=qpl.get_params_query_string(cfg))
print(response.json())
except Exception as e:
LoggerFactory.get_logger('logs/logger.log',
'ERROR').error(f'Error in running query: {e}')
run_query()
While running run_query without if name == 'main': and with it as well , the following error is encountered :
[2022-05-16 13:43:32,614][logs/logger.log][ERROR] - Error in running query: **decorated_main()** takes from 0 to 1 positional arguments but 2 were given
Although newer version of hydra (I'm using hydra-core==1.1.2) uses two arguments while creating cfg object however , I'm not sure as to whether there's other way of handling this as such.
Also, by searching through other threads, following was also tried - Compose API
however, from the docs, it requires an override parameter , which is not needed atm.
Would like to know if any other approach can be tried out. Happy to provide more details if needed.
Definitely use the Compose API and not hydra.main() for this use case.
You can just pass an empty array for your override list if you have nothing to override.
I am trying to validate a DRF get request using django form as follows,
The view of django rest api
#csrf_exempt
#api_view(['GET', 'POST'])
def pkg_list(request):
if request.method == 'GET':
frm=ThisForm(request.GET)
if frm.is_valid:
print("form ok")
print(frm.cleaned_data)
else:
print("invalid")
mydata=[{"email": request.GET['reseller']}]
results=ResellerListPackages(mydata,many=True).data
return Response(results)
The view class is form is as follows,
class ThisForm(forms.Form):
reseller=forms.EmailField(max_length=255)
def clean(self):
self.cleaned_data = super().clean()
print(self.cleaned_data)
return self.cleaned_data
The form validation seems working fine , but the frm.cleaned_data is not found with the following error,
print(frm.cleaned_data)
AttributeError: 'ThisForm' object has no attribute 'cleaned_data'
Can some one point to me the correct direction. It is the first time using the DRF
Change
frm.is_valid
to
frm.is_valid()
Forms only get a cleaned_data attribute when is_valid() has been called, and you haven't called it on this new, second instance.
but in your case, you are not calling the is_valid() method.
I started testing views, but I found an error in the test, tell me where I went wrong, I'm just starting to learn, so don't judge strictly
my views:
`class MovieDetailView(Genre, DetailView):
model = Movie
slug_field = "url"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["star_form"] = RatingForm()
return context
`
my test looks like this:
`def test_starform_set_in_context(self):
request = RequestFactory().get('some-slug')
view = MovieDetailView()
view.setup(request)
context = view.get_context_data()
self.assertIn('star_form', context))`
url:
`path("<slug:slug>/", views.MovieDetailView.as_view(), name="movie_detail"),`
I think this is because Django's get_context_data() function uses the 'object' to pass it into the context.So, I suggest you to use get_object() method.
See this for more details: https://ccbv.co.uk/projects/Django/3.0/django.views.generic.detail/DetailView/
basically you need to return an object e.g.
def get_object(self,queryset=None):
obj = Movie.object.get(slug=self.kwargs.get('slug'))
return obj #also handle 404
or try one more thing :
slug_fields = slug
path should be
path("<str:slug>/", views.MovieDetailView.as_view(), name="movie_detail"),
I have a rather contrived code here :
backend_data = {
"admins": ["Leo", "Martin", "Thomas", "Katrin"],
"members": [
"Leo",
"Martin",
"Thomas",
"Katrin",
"Subhayan",
"Clemens",
"Thoralf"
],
"juniors": ["Orianne", "Antonia", "Sarah"]
}
class Backend:
def __init__(self, data):
self.backend_data = data
def get_all_admins(self):
return self.backend_data.get("admins")
def get_all_members(self):
return self.backend_data.get("members")
def get_all_juniors(self):
return self.backend_data.get("juniors")
class BackendAdaptor:
# Does some conversion and validation
def __init__(self, backend):
self.backend = backend
def get_all_admins(self):
return (admin for admin in self.backend.get_all_admins())
def get_all_members(self):
return (member for member in self.backend.get_all_members() if member not in self.backend.get_all_admins())
def get_all_juniors(self):
return (junior for junior in self.backend.get_all_juniors())
if __name__ == "__main__":
backend = Backend(data=backend_data)
adaptor = BackendAdaptor(backend=backend)
print(f"All admins are : {list(adaptor.get_all_admins())}")
print(f"All members are : {list(adaptor.get_all_members())}")
print(f"All juniors are : {list(adaptor.get_all_juniors())}")
So the BackendAdaptor class basically would be used to do some validation and conversion of the data that we get from the Backend .
The client should only be asked to interact with the API of the BackendAdaptor which is exactly similar to that of Backend . The adaptor class sits in middle and gets data from Backend does some validation if required and the gives back the data to client.
The issue is that the validation on the data that is getting returned from the Backend is not done for every method(For ex: there is validation done on get_all_members but not on get_all_admins and also not on get_all_juniors). The method just gives back a generator on whatever data it gets from Backend.
As is the case now i still have to implement a one liner methods for them .
Is there a way in Python to avoid this ? I am thinking in lines of magic methods like __getattribute__ ? But i have no idea on how to do this for methods.
So the best case scenario is this:
I implement the methods for which i know that i have to do some validation on Backend data
For the rest of the methods it is automatically delegated to Backend and then i just return a generator from what i get back
Any help would be greatly appreciated.
You can implement __getattr__. It is only called if a non-existing attribute is accessed. This will return some generic function with the desired functionality.
class BackendAdaptor:
def __init__(self, backend):
self.backend = backend
def __getattr__(self, name):
if not hasattr(self.backend, name):
raise AttributeError(f"'{name}' not in backend.")
return lambda: (i for i in getattr(self.backend, name)())
def get_all_members(self):
return (member for member in self.backend.get_all_members() if member not in self.backend.get_all_admins())
Im working on a gRPC microservice.
Because every method has to load a JSON string from the request argument first – and then in the end dump it again, I want to use a decorator on the methods of the class, so that the method itself besides the return only contains the ... more stuff to do ... below:
class VPPSetupService(SetupService_pb2_grpc.VPPSetupServiceServicer):
...
def method(self, request, context):
request = json.loads(request.context)
request = request["request"]
header = request["headers"]
... more stuff to do ...
response = json.dumps(response)
return SetupService_pb2.JsonContextResponse(context=response)
So I wrote a decorator function.
However, I could not find a solution for this error:
request = json.loads(request.context)
UnboundLocalError: local variable 'request' referenced before assignment
The error is produced by this: (Just as an example, the real thing is a bit more complex)
from functools import wraps
def json_and_error(func):
#wraps(func)
def args_wrapper(*args, **kwargs): # Problem: This
request = json.loads(request.context) <<# variable is referenced
request = request["request"] # before assignment
header = request["headers"]
func(*args, **kwargs)
return func(*args, **kwargs)
return args_wrapper
class VPPSetupService(SetupService_pb2_grpc.VPPSetupServiceServicer):
...
#json_and_error
def method(self, request, context):
... more stuff to do ...
return SetupService_pb2.JsonContextResponse(context=response)
I tried using request = json.loads(args[1].context) instead. But then I get this error:
if request["source_machine"] and request["dest_machine"]: TypeError:
'JsonContextRequest' object is not subscriptable
The input given as request argument is an object of type <class 'SetupService_pb2.JsonContextRequest'> The JSON String in the request would be accessible through the request.context attribute.
I'm thinking the problem is related to how the decorator function is being called. I suppose if it was called at runtime of the class method the variable request should already have been assigned the request object.
But maybe I'm completely wrong here. So how would you solve this?
There are few errors in your code:
def args_wrapper(*args, **kwargs):
request = json.loads(request.context)
You're using request.context while request variable is undefined (it will be defined only after json.loads(request.context) will be executed). You tried to fix it using request = json.loads(args[1].context), but got JsonContextRequest object is not subscriptable in wrapped function. Look at this line closer:
return func(*args, **kwargs)
You decorator returns wrapped function called with the same params, so this code result isn't used, you don't pass request and header to wrapped function:
request = json.loads(request.context)
request = request["request"]
header = request["headers"]
Also you shouldn't call wrapped function:
func(*args, **kwargs)
I guess you want to do something like this:
def json_and_error(func):
def args_wrapper(this, request):
context = request.context
request = json.loads(context)
request = request["request"]
return func(this, request, context)
return args_wrapper