官术网_书友最值得收藏!

Creating the Entry model

A model is the data representation of a table of data that we want to store in the database. These models have attributes called columns that represent the data items in the data. So, if we were creating a Person model, we might have columns for storing the first and last name, date of birth, home address, hair color, and so on. Since we are interested in creating a model to represent blog entries, we will have columns for things like the title and body content.

Note

Note that we don't say a People model or Entries model – models are singular even though they commonly represent many different objects.

With SQLAlchemy, creating a model is as easy as defining a class and specifying a number of attributes assigned to that class. Let's start with a very basic model for our blog entries. Create a new file named models.py in the blog project's app/ directory and enter the following code:

import datetime, re
from app import db

def slugify(s):
    return re.sub('[^\w]+', '-', s).lower()

class Entry(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100))
    slug = db.Column(db.String(100), unique=True)
    body = db.Column(db.Text)
    created_timestamp = db.Column(db.DateTime, default=datetime.datetime.now)
    modified_timestamp = db.Column(
        db.DateTime,
        default=datetime.datetime.now, 
        onupdate=datetime.datetime.now)

    def __init__(self, *args, **kwargs):
        super(Entry, self).__init__(*args, **kwargs)  # Call parent constructor.
        self.generate_slug()

    def generate_slug(self):
        self.slug = ''
        if self.title:
            self.slug = slugify(self.title)

    def __repr__(self):
        return '<Entry: %s>' % self.title

There is a lot going on, so let's start with the imports and work our way down. We begin by importing the standard library datetime and re modules. We will be using datetime to get the current date and time, and re to do some string manipulation. The next import statement brings in the db object that we created in app.py. As you recall, the db object is an instance of the SQLAlchemy class, which is a part of the Flask-SQLAlchemy extension. The db object provides access to the classes that we need to construct our Entry model, which is just a few lines ahead.

Before the Entry model, we define a helper function slugify, which we will use to give our blog entries some nice URLs (used in Chapter 3, Templates and Views). The slugify function takes a string such as A post about Flask and uses a regular expression to turn a string that is human-readable in to a URL, and so returns a-post-about-flask.

Next is the Entry model. Our Entry model is a normal class that extends db.Model. By extending db.Model, our Entry class will inherit a variety of helpers that we'll use to query the database.

The attributes of the Entry model, are a simple mapping of the names and data that we wish to store in the database and are listed as follows:

  • id: This is the primary key for our database table. This value is set for us automatically by the database when we create a new blog entry, usually an auto-incrementing number for each new entry. While we will not explicitly set this value, a primary key comes in handy when you want to refer one model to another, as you'll see later in the chapter.
  • title: The title for a blog entry, stored as a String column with a maximum length of 100.
  • slug: The URL-friendly representation of the title, stored as a String column with a maximum length of 100. This column also specifies unique=True, so that no two entries can share the same slug.
  • body: The actual content of the post, stored in a Text column. This differs from the String type of the Title and Slug as you can store as much text as you like in this field.
  • created_timestamp: The time a blog entry was created, stored in a DateTime column. We instruct SQLAlchemy to automatically populate this column with the current time by default when an entry is first saved.
  • modified_timestamp: The time a blog entry was last updated. SQLAlchemy will automatically update this column with the current time whenever we save an entry.

Note

For short strings such as titles or names of things, the String column is appropriate, but when the text may be especially long it is better to use a Text column, as we did for the entry body.

We've overridden the constructor for the class (__init__) so that, when a new model is created, it automatically sets the slug for us based on the title.

The last piece is the __repr__ method that is used to generate a helpful representation of instances of our Entry class. The specific meaning of __repr__ is not important but allows you to reference the object that the program is working with, when debugging.

A final bit of code needs to be added to main.py, the entry-point to our application, to ensure that the models are imported. Add the highlighted changes to main.py as follows:

from app import app, db
import models
import views

if __name__ == '__main__':
    app.run()

Creating the Entry table

In order to start working with the Entry model, we first need to create a table for it in our database. Luckily, Flask-SQLAlchemy comes with a nice helper for doing just this. Create a new sub-folder named scripts in the blog project's app directory. Then create a file named create_db.py:

(blog) $ cd app/
(blog) $ mkdir scripts
(blog) $ touch scripts/create_db.py

Add the following code to the create_db.py module. This function will automatically look at all the code that we have written and create a new table in our database for the Entry model based on our models:

import os, sys
sys.path.append(os.getcwd())
from main import db

if __name__ == '__main__':
    db.create_all()

Execute the script from inside the app/ directory. Make sure the virtualenv is active. If everything goes successfully, you should see no output.

(blog) $ python create_db.py 
(blog) $

Note

If you encounter errors while creating the database tables, make sure you are in the app directory, with the virtualenv activated, when you run the script. Next, ensure that there are no typos in your SQLALCHEMY_DATABASE_URI setting.

Working with the Entry model

Let's experiment with our new Entry model by saving a few blog entries. We will be doing this from the Python interactive shell. At this stage let's install IPython, a sophisticated shell with features such as tab-completion (that the default Python shell lacks).

(blog) $ pip install ipython

Now check whether we are in the app directory and let's start the shell and create a couple of entries as follows:

(blog) $ ipython

In []: from models import * # First things first, import our Entry model and db object.
In []: db # What is db?
Out[]: <SQLAlchemy engine='sqlite:////home/charles/projects/blog/app/blog.db'>

Note

If you are familiar with the normal Python shell but not IPython, things may look a little different at first. The main thing to be aware of is that In[] refers to the code you type in, and Out[] is the output of the commands you put into the shell.

IPython has a neat feature that allows you to print detailed information about an object. This is done by typing in the object's name followed by a question-mark (?). Introspecting the Entry model provides a bit of information, including the argument signature and the string representing that object (known as the docstring) of the constructor.

In []: Entry? # What is Entry and how do we create it?
Type: _BoundDeclarativeMeta
String Form:<class 'models.Entry'>
File: /home/charles/projects/blog/app/models.py
Docstring: <no docstring>
Constructor information:
 Definition:Entry(self, *args, **kwargs)

We can create Entry objects by passing column values in as the keyword-arguments. In the preceding example, it uses **kwargs; this is a shortcut for taking a dict object and using it as the values for defining the object, as shown next:

In []: first_entry = Entry(title='First entry', body='This is the body of my first entry.')

In order to save our first entry, we will to add it to the database session. The session is simply an object that represents our actions on the database. Even after adding it to the session, it will not be saved to the database yet. In order to save the entry to the database, we need to commit our session:

In []: db.session.add(first_entry)
In []: first_entry.id is None # No primary key, the entry has not been saved.
Out[]: True
In []: db.session.commit()
In []: first_entry.id
Out[]: 1
In []: first_entry.created_timestamp
Out[]: datetime.datetime(2014, 1, 25, 9, 49, 53, 1337)

As you can see from the preceding code examples, once we commit the session, a unique id will be assigned to our first entry and the created_timestamp will be set to the current time. Congratulations, you've created your first blog entry!

Try adding a few more on your own. You can add multiple entry objects to the same session before committing, so give that a try as well.

Note

At any point while you are experimenting, feel free to delete the blog.db file and re-run the create_db.py script to start over with a fresh database.

Making changes to an existing entry

In order to make changes to an existing Entry, simply make your edits and then commit. Let's retrieve our Entry using the id that was returned to us earlier, make some changes, and commit it. SQLAlchemy will know that it needs to be updated. Here is how you might make edits to the first entry:

In []: first_entry = Entry.query.get(1)
In []: first_entry.body = 'This is the first entry, and I have made some edits.'
In []: db.session.commit()

And just like that your changes are saved.

Deleting an entry

Deleting an entry is just as easy as creating one. Instead of calling db.session.add, we will call db.session.delete and pass in the Entry instance that we wish to remove.

In []: bad_entry = Entry(title='bad entry', body='This is a lousy entry.')
In []: db.session.add(bad_entry)
In []: db.session.commit() # Save the bad entry to the database.
In []: db.session.delete(bad_entry)
In []: db.session.commit() # The bad entry is now deleted from the database.
主站蜘蛛池模板: 萍乡市| 上饶市| 梅河口市| 日喀则市| 武陟县| 穆棱市| 澄迈县| 海原县| 万年县| 常宁市| 德阳市| 竹北市| 松江区| 宜章县| 庄浪县| 镇坪县| 龙陵县| 柞水县| 遵义县| 马尔康县| 青海省| 固原市| 青铜峡市| 苏尼特左旗| 宁晋县| 梁河县| 鹤山市| 疏附县| 浦北县| 湖州市| 淮阳县| 伊通| 高州市| 东乡族自治县| 毕节市| 潞西市| 阜阳市| 罗江县| 邛崃市| 湖口县| 保靖县|