Referring to objects via foreign keys

The key that we use to uniquely identify an object is its primary key. When child objects refer to a parent object, we have additional design decisions to make. How do we structure the children's primary keys? There are two common design strategies for child keys, based on the kind of dependence that exists between the classes of objects:

  • "Child:cid": We can use this when we have children that can exist independently of an owning parent. For example, an item on an invoice refers to a product; the product can exist even if there's no invoice item for the product.
  • "Parent:pid:Child:cid": We can use this when the child cannot exist without a parent. A customer address doesn't exist without a customer to contain the address in the first place. When the children are entirely dependent on the parent, the child's key can contain the owning parent's ID to reflect this dependency.

As with the parent class design, it's easiest if we keep the primary key and all foreign keys associated with each child object. We suggest not initializing them in the __init__() method, as they're just features of persistence. Here's the general definition for Post within Blog:

import datetime
from dataclasses import dataclass, field, asdict
from typing import List
@dataclass
class Post:
date: datetime.datetime
title: str
rst_text: str
tags: List[str]
underline: str = field(init=False)
tag_text: str = field(init=False)

# Part of the persistence, not essential to the class.
_id: str = field(default='', init=False, repr=False, compare=False)
_blog_id: str = field(default='', init=False, repr=False, compare=False)

def __post_init__(self) -> None:
self.underline = "-" * len(self.title)
self.tag_text = " ".join(self.tags)

We've provided several attributes for each microblog post. The asdict() function of the dataclasses module can be used with a template to provide a dictionary usable to create JSON notation. We've avoided mentioning the primary key or any foreign keys for Post. Here are two examples of the Post instances:

p2 = Post(date=datetime.datetime(2013,11,14,17,25), 
        title="Hard Aground", 
        rst_text="""Some embarrassing revelation. Including ☹ and ⚓""", 
        tags=("#RedRanger", "#Whitby42", "#ICW"), 
        ) 
 
p3 = Post(date=datetime.datetime(2013,11,18,15,30), 
        title="Anchor Follies", 
        rst_text="""Some witty epigram. Including < & > characters.""", 
        tags=("#RedRanger", "#Whitby42", "#Mistakes"), 
        ) 

We can now associate these two post objects with their owning blog object by setting attributes. We'll do this through the following steps:

  1. Open the shelf and retrieve the parent Blog object. Save it in the owner variable so we have access to the _id attribute:
>>> import shelve 
>>> shelf = shelve.open("blog") 
>>> owner = shelf['Blog:1'] 
  1. Assign this owner's key to each Post object and persist the objects. Put the parent information into each Post. We used the parent information to build the primary key. For this dependent kind of key, the _parent attribute value is redundant; it can be deduced from the key. If we used an independent key design for Posts, however, _parent would not be duplicated in the key:
>>> p2._blog_id = owner._id 
>>> p2._id = p2._blog_id + ':Post:2' 
>>> shelf[p2._id]= p2 
 
>>> p3._blog_id = owner._id 
>>> p3._id = p3._blog_id + ':Post:3' 
>>> shelf[p3._id]= p3 

When we look at the keys, we can see the Blog plus both Post instances:

>>> list(shelf.keys()) 
['Blog:1:Post:3', 'Blog:1', 'Blog:1:Post:2'] 

When we fetch any child Post, we'll know the proper parent Blog for the individual posting:

>>> p2._parent 'Blog:1' 
>>> p2._id 'Blog:1:Post:2'

Following the keys the other way  from parent, Blog, down to its child, Post  becomes a matter of locating the matching keys in the shelf collection.

How to design CRUD operations for complex objects is discussed in the next section.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset