Mark Finch
Mark Finch

Reputation: 766

GAE/Python - What is the best way to pass the request from the controller to the model?

In the following example code I illustrate how I solved passing the request from the controller to the model. Is there a better way to do this?

models/MyModel.py

from google.appengine.ext import db

class MyModel(db.model):
    a = db.StringProperty(required=True)
    b = db.StringProperty(required=True)
    c = db.StringProperty(required=True)

class Update:
    def __init__(self, x)
        self.x = x

    def do_something(self)
        myquery = db.GqlQuery('SELECT * FROM MyModel WHERE a = :1' self.x)
        v = myquery.get()

        if not v:
            somevalue = MyModel(a = self.request.get('a'), # Doesn't work unless
                                b = self.request.get('b'), # the request has been
                                c = self.request.get('c')) # passed
            somevalue.put()

controllers/MyController.py

import webapp2
from models.MyModel import Update

class WebHandler(webapp2.RequestHandler):
    def get(self):
        var_x = "string"
        var_y = "string"
        z = Update(var_x)
        z.request = self.request  # <--- Is there a better way?
        z.do_something()

Edit: (5/30/2012) I ended up creating a function to pass the request variables to the Model as arguments. I was hoping there was some python magic that would avoid all the repetition but I didn't find one.

Upvotes: 1

Views: 189

Answers (3)

Robert Rossney
Robert Rossney

Reputation: 96920

You need a little more encapsulation. Another level of abstraction is useful.

Create a class representing the actual thing that you're using MyModel to persist, with a, b, and c attributes or properties:

class Thing(object):

   def __init__(a, b, c):
      self.a = a
      self.b = b
      self.c = c 

This class doesn't know anything about requests, or the datastore, or persistence. It's where all the actual business logic surrounding the thing itself lives.

You can instantiate this class without needing a request or a database, and you can unit test all of the business logic without having to mock out any of GAE's plumbing.

You can then write code in your request handler that instantiates this thing, e.g.:

def get(request):
  thing = Thing(a=request.get('a'), b=request.get('b'), c=request.get('c'))
  u = Update(some_params)
  u.do_something(thing)

You can add a class method to MyModel that puts a thing, e.g.:

@classmethod
def put_thing(thing):
  model = MyModel(a=thing.a, b=thing.b, c=thing.c)
  model.put()

and then your do_something logic can just call MyModel.put_thing(thing) if it needs to add it to the database.

Upvotes: 2

mata
mata

Reputation: 69092

handing over the request to the model means you're mixing model and controller.

normaly the model shouldn't even be aware that ther even is a request. geting the parameters from the request is the controller's job, not the models. if your do_something method has to work with parameters, then it should get them as arguments and return a result (usually an entity).

Upvotes: 4

voscausa
voscausa

Reputation: 11706

You can add update as a class method to the MyModel class with a @classmethod decorator and call MyModel.update(a=x)

Upvotes: 1

Related Questions