Creating our Post Class

The application that we are building in this section is a blog system. Users will be able to register, create their blog, and then create posts within their blog.

Each post will have the following properties:

  • A title;
  • Some content;
  • An author;
  • The blog in which is was written; and
  • A created date.

Finally, it is also going to have an extra property called _id, which MongoDB uses for storage. We will look at exactly why it is necessary further on.

As we know from the previous chapter, we can create a class which allows us to model these Post obects:

class Post:
  def __init__(self, title, content, author, blog_id, created_date, _id):
    self.title = title
    self.content = content
    self.author = author
    self.blog_id = blog_id
    self.created_date = created_date
    self._id = _id

JSON representation for storage in MongoDB

We have already seen that MongoDB only stores JSON data. It is necessary that we are able to represent our Post objects as JSON so that we can store them in MongoDB.

The pymongo library converts Python dictionaries to JSON for us, so all we have to do is represent the Post object as a Python dictionary, as opposed to a Python object. Here's one way we might go about doing that:

def json(self):
  return {
    '_id': self._id,
    'blog_id': self.blog_id,
    'author': self.author,
    'content': self.content,
    'title': self.title,
    'created_date': self.created_date
  }

Easy, right? All we have to do is give each of the properties a key, and put the key-property pair in a dictionary.

Writing to MongoDB

Then, writing to MongoDB just requires us to use the Database class we wrote earlier to insert that JSON into the database. This is what the Post class would look like now:

from src.common.database import Database


class Post(object):

  def __init__(self, blog_id, title, content, author, created_date, _id):
    self.blog_id = blog_id
    self.title = title
    self.content = content
    self.author = author
    self.created_date = created_date
    self._id = _id

  def save_to_mongo(self):
    Database.insert(collection='posts',
                    data=self.json())

  def json(self):
    return {
      '_id': self._id,
      'blog_id': self.blog_id,
      'author': self.author,
      'content': self.content,
      'title': self.title,
      'created_date': self.created_date
    }

Creating an object from data stored in MongoDB

When we retrieve data from MongoDB, we get a Python dictionary back. We can then use the data in the dictionary to create an object with the same properties as the object we saved.

We can retrieve the data related to one object by executing the following:

post_data = Database.find_one(collection='posts', query={'_id': id})

Then, we can use the data to create a Post object:

post_object = Post(
                blog_id=post_data['blog_id'],
                title=post_data['title'],
                content=post_data['content'],
                author=post_data['author'],
                created_date=post_data['created_date'],
                _id=post_data['_id'],
              )

Thus we can place the method inside the Post class, like so:

def from_mongo(self, post_id):
  post_data = Database.find_one(collection='posts', query={'_id': post_id})
  post_object = Post(
                  blog_id=post_data['blog_id'],
                  title=post_data['title'],
                  content=post_data['content'],
                  author=post_data['author'],
                  created_date=post_data['created_date'],
                  _id=post_data['_id'],
                )
  return post_object

However, we are not using self inside that method at all. That means the method isn't using one specific instance of an object. However, it does use Post, which is the class in which the method lives.

We can make this method into a classmethod, a type of method used when the method uses the class in which it lives, but not a specific object. To do this, we just add @classmethod and change one parameter of the method:

@classmethod
def from_mongo(cls, post_id):
  post_data = Database.find_one(collection='posts', query={'_id': post_id})
  post_object = cls(
                  blog_id=post_data['blog_id'],
                  title=post_data['title'],
                  content=post_data['content'],
                  author=post_data['author'],
                  created_date=post_data['created_date'],
                  _id=post_data['_id'],
                )
  return post_object

Argument unpacking

Finally, there is one more improvement we can make on this method, and that is to use argument unpacking.

Argument unpacking allows us to pass a dictionary as parameters to a method, by using the keys as parameter names, and the values as parameter values.

Instead of doing this:

cls(
  blog_id=post_data['blog_id'],
  title=post_data['title'],
  content=post_data['content'],
  author=post_data['author'],
  created_date=post_data['created_date'],
  _id=post_data['_id'],
)

We can do this:

cls(**post_data)

results matching ""

    No results matching ""