08 - Model objects
Once the models are created, we can interact with those objects from the controllers using very convenient methods.
Instantiating an object
Simple instantiation
customer = models.Customer()
A dictionary or dictionary-like object with keys/values matching the class attributes can also be supplied as arguments.
Instantiation with supplied dictionary
vals = dict(first_name='Michael', last_name='Jackson', age='12')
customer = models.Customer(vals)
A typical use of this way of instantiating is to supply the post object
Instantiation with supplied post object
if post:
customer = models.Customer(post)
If the posted values were submitted from a form with elements named for example first_name, last_name, age, etc., then these values will be used to appropriately instantiate the customer object.
Using get() to rudely demand an object
The get() method is a classmethod which which returns an object if found or None if no object is found. But it goes one step further than that. If no object is found, get() will raise a 404 error. This is used in controller methods in situations where we expect the object to be found. If the 404 behavior is not desired, use the ask() method instead which is identical to get() with the exception that no 404 error is raised if no such object is found.
The simplest way to get an object from the database is using get() with no arguments like this:
Calling get() with no arguments
customer = models.Customer.get()
Since no arguments are supplied in the above example, the returned object will simply be the first record found. Using get() with no arguments like this obviously pretty limited in its usefulness.
Calling get() with a single int
customer = models.Customer.get(25)
This will return the Customer object with an id of 25. If there is no such record in the database, we'll get a 404 error. A common idiom is to combine get() with expect() for fetching an object with the id appended to the URI.
Using get() together with expect()
# Example URI: /customer/edit/25
def edit():
customer_id = expect(1)
customer = models.Customer.get(customer_id)
In the first line of our controller method, we expect that something will be appended to the URI beyond "edit/". If not, we get a 404 error. In the second line, we demand a record from the database matching the customer_id. If no record is found, a 404 is raised.
NOTE: We could of course make the supplied customer id optional by either silently setting a default customer id or by redirecting to a default customer id.
Example using default customer id
def edit():
customer_id = expect(0,1) or 1 # No redirect, default to 1
customer = models.Customer.get(customer_id)
Example redirecting to a default customer id
def edit():
customer_id = expect(0,1) or redirect_to('/customer/edit/1')
customer = models.Customer.get(customer_id)
Calling get() with named arguments
Let's say that instead of passing the customer id, we want to instead find the record by customer's first and last name. Here's how we might do that:
def edit():
first, last = expect(2)
customer = models.Customer.get(first_name = first, last_name = last)
Note that this code assumes there are no duplicate records with the same first and last name. If multiple matching records did exist, the get() method in this example would simply return the matching record it finds.
Using ask() to politely request an object
As noted above, the ask() method is nearly identical to get(). The only difference is that it will not raise a 404 error when it can't find a result. It is generally advisable to use ask() instead of get() when fetching records from anywhere other than a controller. Otherwise it can get a bit confusing as to why you're seeing a 404. To keep things clear, 404 errors should only be raised from within the context of a controller method. And subsequently, the get() method should also only be used within controller methods. Tip: If you're getting a 404 and you don't know why, there's a good chance that a call to get() is involved.
Object method: delete()
Once an object has been found, deleting the record from the database is very easy.
def edit():
customer = models.get( expect(1) )
if post and post.delete:
customer.delete()
This one requires a bit of explanation. We start by getting the customer record from the database. If not id was appended to the URI or if no matching record was found, a 404 error is immediately raised and the rest of this method will never be executed. The next line if post and post.delete assumes that we have a submit button in the form with name="delete". So this line checks first to see if the form was submitted at all, and if so whether the delete button specifically was pushed (because there might be a save button too). The last line will call the delete() method of the customer object which not only deletes the object from memory -- it actually deletes the record from the database too.
Note that we check for post.delete and then call the method customer.delete() -- notice the parentheses. It's important to understand clearly that the former is checking an attribute and the latter is calling a method.
Object method: collect()
Object method: save()
Object method: update_with()
Object method: get_sql()
Object method: ask_sql()
Object method: collect_sql()
Validation errors
Next: 09 - Logging