"'Request' object has no attribute 'learner'": Django Restframework - python-3.x

There is an error in my code "'Request' object has no attribute 'learner'". Here, My requirement is "request.learner" is empty then call "CDetailsSerializer" otherwise call "CourseDetailsSerializer".
def list(self, request, **kwargs):
try:
queryset = self.get_queryset()
queryset = self.filter_queryset(queryset)
if not request.learner:
serializer = CDetailsSerializer(queryset, many=True)
else:
serializer = CourseDetailsSerializer(queryset, many=True)
print('s', serializer.data)
response_data = {'course': serializer.data}
return self.jp_response(s_code='HTTP_200_OK', data=response_data)
except Exception as e:
print(e)
return self.jp_error_response('HTTP_500_INTERNAL_SERVER_ERROR', 'EXCEPTION', [str(e), ])
Here always calling (else part) CourseDetailsSerializer, but in some situations, I also want to call (if part) CDetailsSerializer.Give me a solution to fix this.

Related

How could I create a docstring decorator in the presence of properties?

I have a collection of ever more specialized classes which correspond to collections of the same kind of data (temperature, density, etc) but for different drifts, for example, one subclass has dimensions (nx, ny) and a different suclass has dimensions (ncv), and I want to reflect that in the docstrings, for having a better documentation using Sphinx.
After reading many very useful threads here in Stack Overflow, I have arrived to this model:
import numpy as np
from functools import wraps
def class_decorator(cls):
import ipdb; ipdb.set_trace()
clsdict = {}
mro = cls.mro()
mro.reverse()
for tmp in mro[1:]: ##Ignore object class parent.
clsdict.update(tmp.__dict__)
for name, method in clsdict.items():
if hasattr(method, '__og_doc__'):
try:
method.__doc__ = method.__og_doc__.format(**clsdict)
except:
pass
else:
try:
method.__og_doc__ = method.__doc__
method.__doc__ = method.__doc__.format(**clsdict)
except:
pass
return cls
def mark_documentation(fn):
if not hasattr(fn, '__og_doc__'):
try:
fn.__og_doc__ = fn.__doc__
except:
pass
#wraps(fn)
def wrapped(*args, **kwargs):
return fn(*args, **kwargs)
return wrapped
def documented_property(fn):
if not hasattr(fn, '__og_doc__'):
try:
fn.__og_doc__ = fn.__doc__
except:
pass
#wraps(fn)
def wrapped(*args, **kwargs):
return fn(*args, **kwargs)
prp= property(wrapped)
prp.__og_doc__ = fn.__og_doc__
return prp
#class_decorator
class Base(object):
_GRID_DIM = 'nx, ny'
_TYPE = 'BaseData'
def __init__(self, name):
self.name = name
def shape(self):
""" This docstring contains the type '{_TYPE}' of class."""
print('Simple')
def operation(self, a, b, oper=np.sum, **kwargs):
""" Test for functions with args and kwargs in {_TYPE}"""
return oper([a,b])
#classmethod
def help(cls, var):
try:
print(get(cls, var).__doc__)
except:
print("No docstring yet.")
#class_decorator
class Advanced(Base):
_GRID_DIM = 'ncv'
_TYPE = 'AdvancedData'
def __init__(self,name):
super().__init__(name)
#property
#mark_documentation
# #documented_property
def arkansas(self):
"""({_GRID_DIM}, ns): Size of Arkansaw."""
return 'Yeah'
I am aiming to get the correctly formatted docstring when I call the help method or I use Sphinx, so that:
> adv = Advanced('ADV')
> adv.help("arkansas")
(ncv, ns): Size of Arkansaw.
> adv.help("operation")
Test for functions with args and kwargs in AdvancedData
I have managed to make it work so far, except for properties, because I assigned __og_doc__ to the function, but the property does not have that attribute. My last attempt at monkeypatching this, documented_property, fails because property is inmutable (as expected), and I cannot come up with any way to avoid this roadblock.
Is there any way around this problem?

request.data.get getting None in patch method

I am trying to get the id of user but request.get.data is not getting when i tried to print staff_user its showing None.but when use json.loads its working fine but reguest.data.get is showing None.
class MyDetailsAPIView(RetrieveUpdateDestroyAPIView):
permission_classes = [IsAuthenticated]
parser_classes = [MyMultiPartParser]
serializer_class = Myserializer
model = Document
lookup_url_kwarg = 'file_id'
def patch(self, request, *args, **kwargs):
staff_user_pk = request.data.get('staff_user_pk')
if staff_user_pk:
try:
staffuser = Staffuser.objects.get(id=staff_user_pk)
except Staffuser.DoesNotExist as exc:
raise ValidationError({'detail': exc})
file = self.get_object()
file.staffusers.add(staffuser)
return super().patch(request, *args, **kwargs)

Django Rest Framework - to_internal_value Error Inconsistency

I have a model, User, in which the primary unique field is email. I have a separate Organization model which allows users to map to organizations through a many-to-many mapping.
I want the serializer to allow users to be created if they have an existing email but no organization association (organization is taken from the user making the request so is not in the payload).
The standard ModelSerializer includes a check against the field in to_internal_value(). I am consequently trying to override it like so:
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
fields = self._writable_fields
for field in fields:
validate_method = getattr(self, 'validate_' + field.field_name, None)
primitive_value = field.get_value(data)
try:
if validate_method == self.validate_email:
if User.objects.filter(email=primitive_value).exists():
if not self.active_organization.members.filter(email=primitive_value).exists():
continue
else:
validated_value = field.run_validation(primitive_value)
if validate_method is not None:
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
except DjangoValidationError as exc:
errors[field.field_name] = get_error_detail(exc)
except SkipField:
pass
else:
set_value(ret, field.source_attrs, validated_value)
return super().to_internal_value(data)
This works, but the error that is returned if the object already has a record in User and Organization does not correctly map as a dictionary. For example, the validation error shows this:
[ErrorDetail(string='User with this Email already exists.', code='unique')]
Instead of what it should show, this:
{'email': [ErrorDetail(string='User with this Email already exists.', code='unique')]}
I tested by overriding the method and trying both my custom called code vs. the original, and it replicates the above findings:
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
try:
print('trying custom')
for field in self._writable_fields:
if field.field_name == 'email':
print(field.run_validation)
validated_value = field.run_validation(field.get_value(data))
except Exception as e:
print('error custom')
print(str(e))
try:
print('Trying original')
value = super().to_internal_value(data)
except Exception as e:
print('Exception - original')
print(str(e))
Output:
trying custom
<bound method CharField.run_validation of EmailField(max_length=254, validators=[<UniqueValidator(queryset=User.objects.all())>])>
error custom
[ErrorDetail(string='User with this Email already exists.', code='unique')]
Trying original
Exception - original
{'email': [ErrorDetail(string='User with this Email already exists.', code='unique')]}
Can anyone help me understand why this is happening please? I'm really stuck as to how this is happening.
I was not able to figure out why exactly the errors generated by to_internal_value(self, data) change when I copy the code from the underlying ModelSerializer vs calling super(). However, I did find a kind-of hackish workaround.
Because I strip out all the other related info (nested serializers, kind of) before hand, I'm really just worried about the email. Therefore, I traverse the _writable_fields twice: the first time I look for an existing email where it isn't in the organization. If those conditions are true, I return a dictionary and proceed to the create() method. If they fail, I call super. So far this seems to work. Here is my simplified class.
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
try:
for field in self._writable_fields:
if field.field_name == 'email':
primitive_value = field.get_value(data)
validator = EmailValidator()
validator(primitive_value)
if User.objects.filter(email=primitive_value).exists():
if not self.active_organization.members.filter(email=primitive_value).exists():
self.email_already_exists = True
return {'email': primitive_value}
except:
pass
return super().to_internal_value(data)
For reference, this is the complete ViewSet and Serializer I'm using:
class AdminUsersSerializer(serializers.ModelSerializer):
"""User serializer for the admin user view"""
groups = GenericGroupSerializer(source='group_set', many=True, required=False)
permission_sets = GenericPermissionSetSerializer(source='permissionset_set', many=True, required=False)
active_organization = None
email_already_exists = False
class Meta:
model = User
fields = ['pk', 'email', 'groups', 'permission_sets'] # , 'permissions']
def set_active_organization(self, organization):
self.active_organization = organization
def create(self, validated_data):
if not self.email_already_exists:
user = User.objects.create(
email=validated_data['email']
)
user.set_password(None)
user.save()
else:
user = User.objects.get(email=validated_data['email'])
return user
def to_internal_value(self, data):
"""
Dict of native values <- Dict of primitive datatypes.
"""
try:
for field in self._writable_fields:
if field.field_name == 'email':
primitive_value = field.get_value(data)
validator = EmailValidator()
validator(primitive_value)
if User.objects.filter(email=primitive_value).exists():
if not self.active_organization.members.filter(email=primitive_value).exists():
self.email_already_exists = True
return {'email': primitive_value}
except:
pass
return super().to_internal_value(data)
class AdminUsersViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = AdminUsersSerializer
permission_classes = [account_permissions.IsAdminRequired]
http_method_names = ['get', 'post']
active_organization = None
def create(self, request, *args, **kwargs):
self.active_organization = self.request.user.activeorganization.organization
groups = None
permission_sets = None
serializer = self.get_serializer(data=request.data)
serializer.set_active_organization(self.active_organization)
if 'groups' in serializer.initial_data:
if serializer.initial_data.get('groups'):
groups = serializer.initial_data.pop('groups')
else:
serializer.initial_data.pop('groups')
if 'permission_sets' in serializer.initial_data:
if serializer.initial_data.get('permission_sets'):
permission_sets = serializer.initial_data.pop('permission_sets')
else:
serializer.initial_data.pop('permission_sets')
# Normal method functions
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
# Created user
user = User.objects.get(email=serializer.data['email'])
# Add user to organization
self.active_organization.members.add(user)
# Make sure to format the ajax groups data properly
if groups:
try:
group = Group.objects.get(
id=groups,
organization=self.active_organization
)
group.members.add(user)
except:
pass
if permission_sets:
try:
permission_set = PermissionSet.objects.get(
id=permission_sets,
organization=self.active_organization
)
permission_set.members.add(user)
except:
pass
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def get_queryset(self):
return self.queryset.filter(
userorganizationmembership__organization=self.request.user.activeorganization.organization
).all()
It does feel hackish, but it seems to be getting the job done.

Mocking a method's return value does not work

While testing the create_response method, I cannot seem to mock the return value of the get_external_response method.
/foo/response
from abc import ABCMeta, abstractmethod
def create_response(url, type):
query = create_query(url, type)
external_response = get_external_response(query) <-- what I want to mock
return external_response
def create_query(url, type):
cc = MyFactory
return cc.get_concrete_class(url, type)
def get_external_response(cc):
return cc.make_query()
class MyAbstractClass(metaclass=ABCMeta):
def __init__(self, url, type):
self.url = url
self.type = type
self.query = self.make_query()
#abstractmethod
def make_query(self):
pass
class MyFactory:
#staticmethod
def get_concrete_class(url, type):
if type == 'A':
return MyClass(url, type)
else:
print("not valid type")
class MyClass(MyAbstractClass):
def __init__(self, url, type):
super().__init__(url, type)
def make_query(self):
return self.url + self.type
if __name__ == '__main__':
result = create_response('www.stackoverflow.com', 'A')
print(result)
If I run the above, I get the expected www.stackoverflow.comA.
But if try to mock the return value of get_external_response, it does not seem to do anything: it still returns www.stackoverflow.comA and the assertion below fails.
/foo/test_response
from foo.response import create_response
import pytest
from unittest import mock
def test_create_response():
mock_external_response = mock.Mock()
mock_external_response.create_flask_response.return_value = 'www'
result = create_response('www.stackoverflow.com', 'A')
assert result == 'www'
I do not understand why the return value is not set since when the create_response is called, it will eventually reach the point of calling the create_flask_response which, if I am not mistaken, should return www given that I have mocked it.
Can someone explain what I am doing wrong?
I noticed that you are creating a Mock object inside of a function, but are not actually using the Mock.
It looks like you need to patch the function where it is used to use the Mock.
/foo/test_response
#mock.patch('foo.response.get_external_response')
def test_create_response(mock_get_external_reponse):
mock_get_external_response.return_value = 'www' # This is a Mock object, but will be used as a patch over the actual function where it is used
result = create_response('www.stackoverflow.com', 'A')
assert result == 'www'
Quick links to relevant documentation sections for convenience:
Intro to mocking and patching: https://docs.python.org/3/library/unittest.mock.html#quick-guide
Patch specifically here: https://docs.python.org/3/library/unittest.mock.html#unittest.mock.patch

assigning textvariable to entry causes validation to be disabled on DoubleVar

I am modifying tk.Entry() to validate a numeric input and notify a user if there was an error in applying it.
Beginning with the code below:
import tkinter as tk
class FloatEntry(tk.Entry):
def __init__(self, parent, *args, **kwargs):
tk.Entry.__init__(self, parent, validate="focusout", validatecommand=self.validate, *args, **kwargs)
def validate(self):
try:
print(float(self.get()))
return True
except ValueError as e:
print(e)
return False
if __name__ == "__main__":
root = tk.Tk()
root.bind_all("<1>", lambda event:event.widget.focus_set()) # make all widgets focusable
var = tk.DoubleVar()
frame = tk.Frame()
frame.pack(fill="both", expand=True)
FloatEntry(frame, textvariable=var).pack()
tk.Label(frame, textvariable=var).pack()
root.mainloop()
This results in the exception being triggered and printing, "could not convert string to float:". After this, neither the try nor the except in validate() are triggered again, so I assume it somehow returned None and disabled validation (I could be wrong here).
If I change the variable var = DoubleVar() to var =tk.StringVar(), then the validation works as expected, printing the float if the string can be parsed as a float, and printing the exception otherwise.
Finally, if I add a check to the value returned by get() before the try/except block, validation works as expected as well.
def validate(self):
try:
val = self.get()
if(val is not ''):
print(float(self.get()))
return True
except ValueError as e:
print(e)
return False
What is causing validation to be disabled on creation of a FloatEntry object?(or if that isn't happening, what is?)
I'll be honest and say I don't fully understand why this is happening. However, a simple workaround seems to be to configure the validatecommand after you've called the __init__ of the superclass:
class FloatEntry(tk.Entry):
def __init__(self, parent, *args, **kwargs):
tk.Entry.__init__(self, parent, validate="focusout", *args, **kwargs)
self.configure(validatecommand=self.validate)
When I make the above changes, I see the validate being called every time the widget loses focus.

Resources