views:

34

answers:

2

What is the best way to pass request information to a model class method?

I'm wondering whether I have my logic in the wrong place. Maybe I need to move it out of my model.

I want to be able to pass in POST variables or a form to filter the model by country or institution.

I can't do that from the template, but the question is whether I should do that from within the model or controller somehow.

My Model:

class AccountExtra(User):

def myPendingPaymentSchedules(self, status=1, **args):

    if self.is_staff:     # status = approved by MFI
        schedules = PaymentSchedule.objects.select_related(depth=3).filter(active=True)

        if country:
            schedules = schedules.filter(country=country)

        if institution:
            schedules = schedules.filter(institution=institution)            

        return schedules

My Controller:

myAccount = get_object_or_404(AccountExtra, id=request.user.id)  

My Template

{% for sample in myAccount.myPendingPaymentSchedules %}  # Can't pass parameters for country, etc
+3  A: 

Yes, I'd say your logic is in the wrong place. I don't know where the values are coming from that you're trying to pass into myPendingPaymentSchedules, but it seems like it should be done in the view rather than the template. Then you can pass the resulting schedules directly into the template context.

(By the way, your naming scheme is not very Pythonic: I'd use my_account and my_pending_payment_schedules - see PEP8.

Daniel Roseman
To bad I can only upvote this answer once. You deserve a vote for both the answer to the question *and* the reference to PEP8.
Mark van Lent
Also, subclassing User is not the preferred way of extending the functionality offered by that model - see http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
Chris Lawlor
A: 

Thanks for the feedback. I've done a little bit of research about how to access business login from within templates and I thought I'd provide an update in case others find this question in the search results:

There are two cases in which the parameters for the method need to be passed:

Case #1) Passing paramaters for a single value

If we only have a single account, we can simply pass them to the model through a single call in the controller, and pass the result to the template as a single context variable.

Model

class AccountExtra(models.Model):
..

def my_pending_payment_schedules(self, status=1, country=None, institution=None)

    if self.is_staff: 
        schedules = payment_schedule.objects.filter(active=True)

        if country:
            schedules = schedules.filter(product__country=country)

        if institution:
            schedules = schedules.filter(product__institution=institution)

        return schedules

Controller

my_account = get_object_or_404(AccountExtra, id=request.user.id)     

form = staff_approval_form(request.POST)

if form.is_valid():
    cd = form.cleaned_data
    pending_schedules = my_account.my_pending_payment_schedules(
        country=cd.get('country', None),     
        institution=cd.get('institution', None)
    )

c = RequestContext( request, {
    'form': form,
    'pending_schedules': pending_schedules,
})

return render_to_response(
    'my/approvals/approvals_index.html', 
    context_instance=RequestContext(request, c)
)

Template

{% for sample in pending_schedules %} 

Case #2: Passing parameters for multiple values

If however, we are trying to iterate through multiple users's pending schedules who each require different parameters, we can't use a simple 'pending_schedules' variable.

We have to either turn that variable into a dictionary to store the results of multiple users.

A collegue of mine developed a template tag that allows you to access the dictionary by key, as you iterate through the loop.

Templatetags

@register.filter
def hash(obj, key):
    """return hash lookup of key in object

    If the key can be hard-coded into the template, then the normal dot-notation
    is sufficient (obj.key). But if the key is referenced by a name in the
    template context then this hash filter becomes useful.

    Template usage: obj|hash:key
    """
    return obj[key]

Template:

    for user in users: 
        for sample in pending_schedules|hash:user.id 
            Do something

        endfor 
    endfor
Tim Langeman