Set page of ViewSet in Django REST Framework - python

I have the following code:
class GeonamesCountryViewSet(viewsets.ReadOnlyModelViewSet):
permission_classes = (AllowAny,)
serializer_class = GeonamesCountrySerializer
ordering = ('country_name',)
offset_limit = 'required'
def get_queryset(self):
country_geoname_ids = self.request.QUERY_PARAMS.get('country_geoname_ids', None)
name_prefix = self.request.QUERY_PARAMS.get('name_prefix', None)
if (country_geoname_ids is None) and (name_prefix is None):
raise exceptions.ParseError("Either 'country_geoname_id' or 'name_prefix' must be defined.")
if country_geoname_ids is not None:
country_geoname_ids = [param.strip() for param in country_geoname_id.split(',')]
queryset = GeonamesCountry.objects.filter(country_geoname_id__in = country_geoname_ids)
if name_prefix is not None:
if len(name_prefix) < 2:
raise exceptions.ParseError("'name_prefix' must be at least 2 characters long")
queryset = GeonamesCountry.objects.filter(country_name__istartswith = name_prefix)
paginator = Paginator(queryset, self.request.QUERY_PARAMS.get('limit', 10))
selected_page = self.request.QUERY_PARAMS.get('page')
try:
countries = paginator.page(selected_page)
except EmptyPage:
raise exceptions.ParseError("'Page Empty")
return queryset
Is it possible to default to page one instead of raise exceptions.ParseError("'Page Empty") when the EmptyPage exception is thrown?
After reading the documentation I see it is easily done when not using a ViewSet, but how can I do it from within a ViewSet?

I think you will be quite safe by doing this:
try:
countries = paginator.page(selected_page)
except InvalidPage:
countries = paginator.page(1)
Notice the InvalidPage exception, so you can cover non numbers as well.
-- UPDATE --
It seems like the the cleanest way would be to override pagination class, it's the only way that gives you control over returned page number:
from django.core.paginator import Paginator, InvalidPage
class MyPaginator(Paginator):
def validate_number(self, number):
try:
number = super(MyPaginator, self).validate_number(number)
except InvalidPage:
number = 1
return number
class GeonamesCountryViewSet(viewsets.ReadOnlyModelViewSet):
paginator_class = MyPaginator
...

Related

How can i validate django field with either of two validators?

Here is the code,
I want ip_address to satisfy either of validate_fqdn or validate_ipv4_address.
import re
def validate_fqdn(value):
pattern = re.compile(r'^[a-zA-Z0-9-_]+\.?[a-zA-Z0-9-_]+\.[a-zA-Z0-9-_]+$')
if not pattern.match(value):
raise ValidationError('Provided fqdn is not valid')
return value
class KSerializer(serializers.HyperlinkedModelSerializer):
ip_address = serializers.CharField(max_length = 100, validators = [validate_fqdn, validate_ipv4_address])
How can I achieve this?
A new validator will do:
def validate_fqdn_or_ipv4_address(value):
try:
return validate_fqdn(value)
except:
return validate_ipv4_address(value)

django try block best use

I have a view that takes 2 arguments :course_slug and chapter_slug and i want to check if the given course and chapter exist in the database so what's the best way to do that :
def Chapter_Detail(request,course_slug,chapter_slug):
try:
course = Course.objects.get(slug=course_slug)
except Course.DoesNotExist:
raise Http404("course does not exist")
try:
chapter = Chapter.objects.get(slug=chapter_slug)
except Chapter.DoesNotExist:
raise Http404("chapter does not exist")
'''
continue view logic
'''
context = {
'chapter':chapter,
'course' :course,
}
return render(request,'courses/chapter-detail.html',context)
or:
def Chapter_Detail(request,course_slug,chapter_slug):
try:
course = Course.objects.get(slug=course_slug)
chapter = Chapter.objects.get(slug=chapter_slug)
'''
continue view logic
'''
except Course.DoesNotExist:
raise Http404("course does not exist")
except Chapter.DoesNotExist:
raise Http404("chapter does not exist")
context = {
'chapter':chapter,
'course' :course,
}
return render(request,'courses/chapter-detail.html',context)
or:
def Chapter_Detail(request,course_slug,chapter_slug):
try:
course = Course.objects.get(slug=course_slug)
chapter = Chapter.objects.get(slug=chapter_slug)
except Course.DoesNotExist:
raise Http404("course does not exist")
except Chapter.DoesNotExist:
raise Http404("chapter does not exist")
else :
'''
continue view logic
'''
context = {
'chapter':chapter,
'course' :course,
}
return render(request,'courses/chapter-detail.html',context)
or there is a better way
continue view logic means that we are going to work with the course and chapter objects
As mentioned by Aiden, you can use the shortcut specifically made for this.
from django.shortcuts import get_object_or_404
def Chapter_Detail(request,course_slug,chapter_slug):
course = get_object_or_404(Course, slug=course_slug)
chapter = get_object_or_404(Chapter, slug=chapter_slug)
'''
continue view logic
'''
context = {
'chapter':chapter,
'course' :course,
}
return render(request,'courses/chapter-detail.html',context)
Your three variants will also work of course. The else-block in the third example is strictly not necessary, since either error will get raised or code will proceed.

ValueError: The view create.views.CheckoutView didn't return an HttpResponse object. It returned None instead

I am getting a ValueError that the class below didn't return any httpresponse when i try to redirect to a template. the redirect is supposed to go to the stripe payment view.
here is an entire class that has the redirect call
class CheckoutView(View):
def get(self, *args, **kwargs):
form = forms.CheckoutForm()
context = {
'form': form
}
return render(self.request, "checkout.html", context)
def post(self, *args, **kwargs):
form = forms.CheckoutForm(self.request.POST or None)
try:
equipment_order = models.EquipmentOrder.objects.get(user=self.request.user, ordered=False)
if form.is_valid():
street_address = form.cleaned_data.get('street_address')
apartment_address = form.cleaned_data.get('apartment_address')
country = form.cleaned_data.get('country')
zip = form.cleaned_data.get('zip')
'''
TODO: add functionality to these fields
same_shipping_address = form.cleaned_data.get('same_shipping_address')
save_info = form.cleaned_data.get('save_info')
'''
payment_option = form.cleaned_data.get('payment_option')
billing_address = models.BillingAddress(
user=self.request.user,
street_address=street_address,
apartment_address=apartment_address,
country=country,
zip=zip
)
billing_address.save()
equipment_order.billing_address = billing_address
equipment_order.save()
if payment_option == 'S':
return redirect('create:payment', payment_option='stripe')
elif payment_option == 'P':
return redirect('create:payment', payment_option='paypal')
else:
messages.warning(self.request, "Invalid payment option")
return redirect('create:checkout')
except ObjectDoesNotExist:
messages.error(self.request, "You do not have an active order")
return redirect("create:order_summary")
1) Remove the try/except i think its better
2) I think you have a problem on 'payement_option' , maybe it doesnt give any value of expected , try to print it first to see what does it give
3) remove the ' or None ' from CheckoutForm
4) you can avoid using 'self' by importing form in that way :
from .forms import CheckoutForm
...
form = CheckoutForm(request.POST)
The above answer may work fine but as I tried your code it throws the same error as you described whenever you leave the form field empty or no payment method is selected.
After trying your code the best possible solution I figure out is this. I know this is not a perfect solution but it worked 😅
Suggestion: Try to move your else statement under if instead of nesting it after elif statement. And change your else to given below.
Old:
else:
messages.warning(self.request, "Invalid payment option select")
return redirect('core:checkout')
New:
else :
messages = 'Invalid payment option select'
return HttpResponse(messages)
Proof: Invalid payment option select

Handling multiple exceptions in CBV Django

Is there a way I can handle both the exceptions from different models and still pass none as context individually.
Views.py
class ProfilePage(DetailView):
model = models.UserCreation
context_object_name = 'profile'
def get_context_data(self, *args, **kwargs):
context = super(ProfilePage, self).get_context_data(*args, **kwargs)
user = User.objects.get(username=UserCreation.objects.get(id=self.kwargs.get('pk')))
print(self.request.user,user,self.kwargs.get('pk'))
try:
context['data'] = ProfileData.objects.get( user=user)
context['userdata'] = User.objects.get( username=user)
context['creationdata'] = UserCreation.objects.get(user=user)
context['friends'] = Friends.objects.get( user=self.request.user,added=user)
context['sorted'] = sorted(chain(AddStatus.objects.filter(user=user), ImageLib.objects.filter(user=user)),
key=lambda instance: instance.date, reverse=True)
except ((ProfileData.DoesNotExist as e) or (Friends.DoesNotExistas as f)) :
if e:
context['data']= None
elif f:
context['friends'] = None
return context
Yes, you should use two try-except scopes. In fact it is better not to write long try-except scopes, since then it is no longer clear what triggers the exception. So you can implement this like:
try:
context['data'] = ProfileData.objects.get( user=user)
except ProfileData.DoesNotExist:
context['data']= None
context['userdata'] = User.objects.get( username=user)
context['creationdata'] = UserCreation.objects.get( user=user)
try:
context['friends'] = Friends.objects.get( user=self.request.user,added=user)
except Friends.DoesNotExist:
context['friends'] = None
context['sorted'] = sorted(
chain(AddStatus.objects.filter(user=user),
ImageLib.objects.filter(user=user)),
key=lambda instance: instance.date, reverse=True
)
In case having multiple ProfileDatas, etc. is not a problem, you can make use of .first() instead that will return None if there is no row to return:
context['data'] = ProfileData.objects.filter(user=user).first()
context['userdata'] = User.objects.get(username=user)
context['creationdata'] = UserCreation.objects.get(user=user)
context['friends'] = Friends.objects.filter( user=self.request.user,added=user).first()
context['sorted'] = sorted(
chain(AddStatus.objects.filter(user=user),
ImageLib.objects.filter(user=user)),
key=lambda instance: instance.date, reverse=True
)

functools stops working when switch to Python 3

We have migrated our Django project code base from Python 2.7 to 3.6 and suddenly what used to work stopped. Specifically, this:
map(functools.partial(self._assocUser, user=user), persistedGroupIds)
needed to be replaced with:
for group_id in persistedGroupIds:
self._assocUser(group_id, user)
and this:
persistedGroupIds = map(functools.partial(self._persistGroup, grp_mappings=attrAll.entitlements), saml_authorization_attributes)
needed to go to:
persistedGroupIds = []
for idp_group_name in saml_authorization_attributes:
persistedGroupIds.append(self._persistGroup(idp_group_name, attrAll.entitlements))
before the old functionality reappeared. Python 3's functools don't seem to work.
Here's the full listing of the code that works fine under Python 2:
from django.contrib.auth.models import User
from django.contrib.auth.models import Group
import functools
from mappings import SAMLAttributesConfig
from django.conf import settings
import logging
log = logging.getLogger(__name__)
class SAMLServiceProviderBackend(object):
empty_entitlements_message="IdP supplied incorrect authorization entitlements. Please contact their support."
def _assocUser(self, group_id, user):
group = Group.objects.get(id=group_id)
group.user_set.add(user)
return None
def _persistGroup(self,idp_group_name, grp_mappings):
group_name = grp_mappings[idp_group_name]
try:
group = Group.objects.get(name=group_name)
except Group.DoesNotExist:
group = Group(name=group_name)
group.save()
return group.id
def _extract_grp_entitlements(self,saml_authentication_attributes,groups):
result = []
input_length = len(saml_authentication_attributes[groups])
if input_length == 0:
log.error(self.empty_entitlements_message)
raise RuntimeError(self.empty_entitlements_message)
if input_length == 1:
result = [t.strip() for t in saml_authentication_attributes[groups][0].split(',')]
elif input_length:
result = saml_authentication_attributes[groups]
return result
# return [t.strip() for t in saml_authentication_attributes[groups][0].split(',')] \
# if len(saml_authentication_attributes[groups]) == 1\
# else saml_authentication_attributes[groups]
def authenticate(self, saml_authentication=None):
if not saml_authentication: # Using another authentication method
return None
attrAll = SAMLAttributesConfig(mappings_file_name=settings.AUTH_MAPPINGS_FILE).get_config()
groups = attrAll.entitlements.containerName
if saml_authentication.is_authenticated():
saml_authentication_attributes = saml_authentication.get_attributes()
saml_authorization_attributes = self._extract_grp_entitlements(saml_authentication_attributes,groups)
persistedGroupIds = map(functools.partial(self._persistGroup, grp_mappings=attrAll.entitlements), saml_authorization_attributes)
try:
user = User.objects.get(username=saml_authentication.get_nameid())
except User.DoesNotExist:
user = User(username=saml_authentication.get_nameid())
user.set_unusable_password()
try:
user.first_name = saml_authentication_attributes['samlNameId'][0]
except KeyError:
pass
try:
setattr(user, "first_name", saml_authentication_attributes[attrAll.subject.first_name][0])
except KeyError:
pass
#user.last_name = attributes['Last name'][0]
user.save()
map(functools.partial(self._assocUser, user=user), persistedGroupIds)
user.save()
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
The above code no longer works under Python 3 environment and only starts working to something like this, with a functools.partial() calls spelled out in a for loop:
from django.contrib.auth.models import User
from django.contrib.auth.models import Group
import functools
from .mappings import SAMLAttributesConfig
from django.conf import settings
import logging
log = logging.getLogger(__name__)
class SAMLServiceProviderBackend(object):
empty_entitlements_message="IdP supplied incorrect authorization entitlements. Please contact their support."
def _assocUser(self, group_id, user):
group = Group.objects.get(id=group_id)
group.user_set.add(user)
return None
def _persistGroup(self,idp_group_name, grp_mappings):
group_name = grp_mappings[idp_group_name]
try:
group = Group.objects.get(name=group_name)
except Group.DoesNotExist:
group = Group(name=group_name)
group.save()
return group.id
def _extract_grp_entitlements(self,saml_authentication_attributes,groups):
result = []
input_length = len(saml_authentication_attributes[groups])
if input_length == 0:
log.error(self.empty_entitlements_message)
raise RuntimeError(self.empty_entitlements_message)
if input_length == 1:
result = [t.strip() for t in saml_authentication_attributes[groups][0].split(',')]
elif input_length:
result = saml_authentication_attributes[groups]
return result
# return [t.strip() for t in saml_authentication_attributes[groups][0].split(',')] \
# if len(saml_authentication_attributes[groups]) == 1\
# else saml_authentication_attributes[groups]
def authenticate(self, saml_authentication=None):
if not saml_authentication: # Using another authentication method
return None
attrAll = SAMLAttributesConfig(mappings_file_name=settings.AUTH_MAPPINGS_FILE).get_config()
groups = attrAll.entitlements.containerName
if saml_authentication.is_authenticated():
saml_authentication_attributes = saml_authentication.get_attributes()
saml_authorization_attributes = self._extract_grp_entitlements(saml_authentication_attributes,groups)
persistedGroupIds = map(functools.partial(self._persistGroup, grp_mappings=attrAll.entitlements), saml_authorization_attributes)
try:
user = User.objects.get(username=saml_authentication.get_nameid())
except User.DoesNotExist:
user = User(username=saml_authentication.get_nameid())
user.set_unusable_password()
try:
user.first_name = saml_authentication_attributes['samlNameId'][0]
except KeyError:
pass
try:
setattr(user, "first_name", saml_authentication_attributes[attrAll.subject.first_name][0])
except KeyError:
pass
#user.last_name = attributes['Last name'][0]
user.save()
for group_id in persistedGroupIds:
self._assocUser(user = user, group_id = group_id)
# map(functools.partial(self._assocUser, user=user), persistedGroupIds)
user.save()
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
What can be wrong?
I'm using PyDev plugin in Eclipse. Here's how my Python interpreter is configured there:
Here's Eclipse's .pydevproject file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?eclipse-pydev version="1.0"?><pydev_project>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">venv3.6</pydev_property>
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python interpreter</pydev_property>
<pydev_variables_property name="org.python.pydev.PROJECT_VARIABLE_SUBSTITUTION">
<key>DJANGO_SETTINGS_MODULE</key>
<value>reporting.settings</value>
<key>DJANGO_MANAGE_LOCATION</key>
<value>./manage.py</value>
<key>SAML_PLUGIN</key>
<value>/Users/sl/abc/venv3.6/lib/python3.6/site-packages/onelogin/saml2</value>
<key>PY</key>
<value>36</value>
</pydev_variables_property>
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
<path>/${PROJECT_DIR_NAME}</path>
</pydev_pathproperty>
<pydev_pathproperty name="org.python.pydev.PROJECT_EXTERNAL_SOURCE_PATH">
<path>${SAML_PLUGIN}</path>
</pydev_pathproperty>
</pydev_project>
In Python 3, the map function returns an iterator instead of a list.
This means that if you call map on a collection, the effects of the call are not materialised until you iterate over the resulting iterator.
Consider this class:
>>> class C:
... def __init__(self, x):
... self.x = x
... def double(self):
... self.x *= 2
... def __repr__(self):
... return '<C:{}>'.format(self.x)
...
Let's make a list of instances:
>>> cs = [C(x) for x in range(1, 4)]
>>> cs
[<C:1>, <C:2>, <C:3>]
Now use map to call each instance's double method:
>>> res = map(C.double, cs)
Note the result is not a list:
>>> res
<map object at 0x7ff276350470>
And the instances have not changed:
>>> cs
[<C:1>, <C:2>, <C:3>]
if we call next on the iterator, the instances are updated in turn.
>>> next(res)
>>> cs
[<C:2>, <C:2>, <C:3>]
>>> next(res)
>>> cs
[<C:2>, <C:4>, <C:3>]
>>> next(res)
>>> cs
[<C:2>, <C:4>, <C:6>]
In the code samples that you have provided, the result of calling map is not assigned to a variable, so map is being used for its side effects rather than its output. In Python 3 the correct way to do this is to loop over the iterable and call the function on each element:
>>> for c in cs:
c.double()
As the linked doc puts it:
Particularly tricky is map() invoked for the side effects of the function; the correct transformation is to use a regular for loop (since creating a list would just be wasteful).

Categories