how do I make django search for male or female without needing to specify an age?

142 views
Skip to first unread message

eil...@themaii.org

unread,
Jan 26, 2018, 12:05:04 PM1/26/18
to Django users
I have a file: views.py which refers to two main fields on the page: age and gender
Right now, the search requires that an age to be chosen whether or not the gender is, and I'd like to make the age optional as well. I.e get all the children.
Additionally, I'd like to search for only males or females without selecting an age...

-Eileen
from __future__ import unicode_literals
from django.contrib.auth import get_user_model
from django.shortcuts import redirect
from django.template.response import TemplateResponse
from django.http import HttpResponse
from django.db.models import Q
from django.db.models import F
from mezzanine.conf import settings
from sponsorship.forms import FilterForm
from sponsorship.models import Child
from pinax.stripe.models import Customer
import json
import logging

logger = logging.getLogger(__name__)

User = get_user_model()

steps = [{'title': 'Find a child to sponsor', 'no': '1'}, {'title': 'Sign up or sign in', 'no': '2'}]

def filterchain_all(request, app_name, model_name, method_name, gender):
    gender_dict = {'MALE': 0, 'FEMALE': 1}
    if gender in gender_dict:
        qs = Child.objects.filter(gender=gender_dict[gender]).order_by('age')
        results = list(qs)
        final = []
        for item in results:
            if int(item.age) not in [d['display'] for d in final]:
                final.append({'value': int(item.age), 'display': int(item.age)})
        return HttpResponse(json.dumps(final), content_type='application/json')
    else:
        return HttpResponse(json.dumps({'success': True}), content_type='application/json')

def children_list(request, template="pages/sponsorship.html", extra_context=None):
    templates = []
    templates.append(template)
    children = Child.objects.filter(Q(has_photo=1) & Q(image__isnull=False) & Q(sponsor__isnull=True))
    context = {"child_filter": children, "filter_form": FilterForm(), "steps": steps, "activestep": "1"}
    if request.method == "POST":
        if "id" in request.POST:
            child_id = context['child_filter'].filter(id=request.POST['id'])[0].child_id
            authenticated = request.user.is_authenticated()
            if settings.SHOP_CHECKOUT_ACCOUNT_REQUIRED and not authenticated:
                url = "/accounts/signup/?next=/donate/product/sponsor-a-child/new_customer/%s" % child_id
                return redirect(url)
            else:
                url = "/donate/product/sponsor-a-child/%s" % child_id
                return redirect(url)
        else:
          form = FilterForm(request.POST)
          gender_dict = {'MALE': 0, 'FEMALE': 1}

          search_message = "There are no children that match your selection"
          if form.is_valid() and form.data['gender'] != '-----':
            if form.data['gender'] is 0 or 1:
              q = context['child_filter'].filter(Q(gender=gender_dict[request.POST['gender']]))

            import pdb; pdb.set_trace()
            if form['handicapped'].data == 1 or 2:
                q = context['child_filter'].filter(Q(handicapped=handicapped_dict[request.POST['handicapped']]))

            if request.POST['age'] != '':
                q = context['child_filter'].filter(Q(age=request.POST['age']))

# start of output using search parameters

            if q.count() > 1:
              search_message = "There are %s children that match your selection of %s"  %  (q.count(), request.POST['gender'])
            else:
              search_message = "There is 1 child that matches your selection of %s"  %  (request.POST['gender'])

            if q.count() > 1:
               search_message = ", age: %s"  %  (request.POST['age'])
            else:
               search_message = ", age: %s"  % (request.POST['age'])

            context['child_filter'] = q
            context['filter_form'] = FilterForm()
            context['activestep'] = "1"
            context['search_message'] = search_message
            extra_context = {"message": "Updating filter"}
            context.update(extra_context or {})
            return TemplateResponse(request, templates, context)
          else:
              context['filter_form'] = form
              extra_context = {"message":"Something went wrong"}
              context.update(extra_context or {})
              return TemplateResponse(request, templates, context)

    else:
        context.update(extra_context or {})
        return TemplateResponse(request, templates, context)


def child_detail(request, template="pages/sponsorship.html", extra_context=None, pk=None):
    templates = []
    templates.append(template)
    children = Child.objects.filter(pk=pk)

    if request.method == "GET":
        context = {"child_filter": children, "filter_form": FilterForm(), "steps": steps, "activestep": "3"}
    else:
        context = {"child_filter": children, "filter_form": FilterForm(), "steps": steps, "activestep": "4"}

    context.update(extra_context or {})
    return TemplateResponse(request, templates, context)


def final_order_handler(request, order_form, order):
    """
    Default order handler - called when the order is complete and
    contains its final data. Implement your own and specify the path
    to import it from via the setting ``SHOP_HANDLER_ORDER``.
    """
    child_id = order.items.all()[0].child_id
    if child_id != "":
        child = Child.objects.get(child_id=child_id)
        current_customer = Customer.objects.get(user=request.user)
        child.sponsor = current_customer
        child.save()

eil...@themaii.org

unread,
Jan 26, 2018, 12:26:06 PM1/26/18
to Django users
I should add that this initally loads a list of children without specifying either gender or age

Julio Biason

unread,
Jan 26, 2018, 12:51:40 PM1/26/18
to django...@googlegroups.com
Hi Eileen,

Your problem seems to be the line


          if form.is_valid() and form.data['gender'] != '-----':

It seems it will only accept the form if the gender is not "-----"; if you change that (say, removing the part after the and), it should solve it.

... although you should have a better understanding of what your application does to know if that will work or not.

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/b2510159-5162-4c5b-9b57-7847f42b0a0a%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Julio Biason, Sofware Engineer
AZION  |  Deliver. Accelerate. Protect.
Office: +55 51 3083 8101  |  Mobile: +55 51 99907 0554

Andy

unread,
Jan 28, 2018, 4:43:48 PM1/28/18
to Django users
Why do you make a POST request for displaying a list? Use GET parameters like its done for admin filters.
And for building an API that returns JSON Data use DjangoRestFramework and you will just need to define your serializer fields .. the rest is taken care of for you. That code above looks overly complicated!

For instance you define app_name, model_name, method_name in filterchain_all although its not used.
Your are sending male and female intstead of the values itself as a normal django form would have done it.
Dont make a list out of the qs for no reason.
And instead of doing this "if int(item.age) not in [d['display'] for d in final]" over and over again use a set() to not get multiple results.

BUT moreover to get all distinct ages use:
Child.objects.vales_list('age', flat=True).order_by('age')
Done in one single line by your database instead of the handwritten view!

Please have a look at the django tutorial (https://docs.djangoproject.com/en/2.0/intro/tutorial01/) and keep an eye out for how the admin filters things in a way that can be linked from the outside with GET parameters (you cannot linkt to a filtered list that is requested by a post request)

Please stop using Q() in cases where its not neccessary .. all parameters in a queryset do mean AND. You only need a Q for more complex stuff or an actual OR.
Use a class based FormView to erase even more of the handwritten code and secure it with the LoginRequiredMixin.
Please dont ever again use a TemplateView for dynamic content use the render() method like shown in the tutorial!

Once you have completed the tutorial and embraced the concepts your code will be about 1/10 of the above and it will save you a lot of time figuring out how to do things that are already taken care of by Django if only you knew how. :)


Reply all
Reply to author
Forward
0 new messages