使用Python在Django中建模多态

Modeling polymorphism in relational databases is a challenging task. In this article, we present several modeling techniques to represent polymorphic objects in a relational database using the Django object-relational mapping (ORM).

在关系数据库中对多态进行建模是一项艰巨的任务。 在本文中,我们介绍了几种建模技术,这些技术使用Django对象关系映射( ORM )来表示关系数据库中的多态对象。

This intermediate-level tutorial is designed for readers who are already familiar with the fundamental design of Django.

本中级教程适用于已经熟悉Django基本设计的读者。

Free Bonus: Click here to get the most popular Django tutorials and resources on Real Python and improve your Django + Python web development skills.

免费奖金: 单击此处可获取Real Python上最受欢迎的Django教程和资源,并提高您的Django + Python Web开发技能。

什么是多态? (What Is Polymorphism?)

Polymorphism is the ability of an object to take on many forms. Common examples of polymorphic objects include event streams, different types of users, and products in an e-commerce website. A polymorphic model is used when a single entity requires different functionality or information.

多态是对象采取多种形式的能力。 多态对象的常见示例包括事件流,不同类型的用户以及电子商务网站中的产品。 当单个实体需要不同的功能或信息时,将使用多态模型。

In the examples above, all events are logged for future use, but they can contain different data. All users need be able to log in, but they might have different profile structures. In every e-commerce website, a user wants to put different products in their shopping cart.

在上面的示例中,所有事件都记录下来以备将来使用,但是它们可以包含不同的数据。 所有用户都需要能够登录,但是他们可能具有不同的配置文件结构。 在每个电子商务网站中,用户都希望将不同的产品放入他们的购物车中。

为什么建模多态性具有挑战性? (Why Is Modeling Polymorphism Challenging?)

There are many ways to model polymorphism. Some approaches use standard features of the Django ORM, and some use special features of the Django ORM. The main challenges you’ll encounter when modeling polymorphic objects are the following:

有多种方法可以对多态性进行建模。 一些方法使用Django ORM的标准功能,而某些方法使用Django ORM的特殊功能。 在对多态对象进行建模时,您将遇到的主要挑战如下:

  • How to represent a single polymorphic object: Polymorphic objects have different attributes. The Django ORM maps attributes to columns in the database. In that case, how should the Django ORM map attributes to the columns in the table? Should different objects reside in the same table? Should you have multiple tables?

  • How to reference instances of a polymorphic model: To utilize database and Django ORM features, you need to reference objects using foreign keys. How you decide to represent a single polymorphic object is crucial to your ability to reference it.

  • 如何表示单个多态对象:多态对象具有不同的属性。 Django ORM将属性映射到数据库中的列。 在这种情况下,Django ORM应该如何将属性映射到表中的列? 不同的对象应该驻留在同一张表中吗? 您应该有多个表吗?

  • 如何引用多态模型的实例:要利用数据库和Django ORM功能,您需要使用外键引用对象。 您决定如何表示单个多态对象对于引用它的能力至关重要。

To truly understand the challenges of modeling polymorphism, you are going to take a small bookstore from its first online website to a big online shop selling all sorts of products. Along the way, you’ll experience and analyze different approaches for modeling polymorphism using the Django ORM.

为了真正理解建模多态性的挑战,您将从一家第一家在线网站的小型书店转到一家出售各种产品的大型网上商店。 在此过程中,您将体验并分析使用Django ORM建模多态性的不同方法。

Note: To follow this tutorial, it is recommended that you use a PostgreSQL backend, Django 2.x, and Python 3.

注意:要遵循本教程,建议您使用PostgreSQL后端,Django 2.x和Python 3。

It’s possible to follow along with other database backends as well. In places where features unique to PostgreSQL are used, an alternative will be presented for other databases.

也可以与其他数据库后端一起使用。 在使用PostgreSQL独有功能的地方,将为其他数据库提供替代方案。

天真的实现 (Naive Implementation)

You have a bookstore in a nice part of town right next to a coffee shop, and you want to start selling books online.

您在城镇的一处不错的地方,有一家书店,就在一家咖啡店旁边,您想开始在线销售书籍。

You sell only one type of product: books. In your online store, you want to show details about the books, like name and price. You want your users to browse around the website and collect many books, so you also need a cart. You eventually need to ship the books to the user, so you need to know the weight of each book to calculate the delivery fee.

您只销售一种产品:书籍。 在您的在线商店中,您想显示有关书籍的详细信息,例如名称和价格。 您希望用户浏览网站并收集许多书籍,因此还需要购物车。 您最终需要将书籍运送给用户,因此您需要知道每本书的重量来计算送货费用。

Let’s create a simple model for your new book store:

让我们为您的新书店创建一个简单的模型:

 from from django.contrib.auth django.contrib.auth import import get_user_model
get_user_model
from from django.db django.db import import models


models


class class BookBook (( modelsmodels .. ModelModel ):
    ):
    name name = = modelsmodels .. CharFieldCharField (
        (
        max_lengthmax_length == 100100 ,
    ,
    )
    )
    price price = = modelsmodels .. PositiveIntegerFieldPositiveIntegerField (
        (
        help_texthelp_text == 'in cents''in cents' ,
    ,
    )
    )
    weight weight = = modelsmodels .. PositiveIntegerFieldPositiveIntegerField (
        (
        help_texthelp_text == 'in grams''in grams' ,
    ,
    )

    )

    def def __str____str__ (( selfself ) ) -> -> strstr :
        :
        return return selfself .. name


name


class class CartCart (( modelsmodels .. ModelModel ):
    ):
    user user = = modelsmodels .. OneToOneFieldOneToOneField (
        (
        get_user_modelget_user_model (),
        (),
        primary_keyprimary_key == TrueTrue ,
        ,
        on_deleteon_delete == modelsmodels .. CASCADECASCADE ,
    ,
    )
    )
    books books = = modelsmodels .. ManyToManyFieldManyToManyField (( BookBook )
)

To create a new book, you provide a name, price, and weight:

要创建一本新书,您需要提供名称,价格和重量:

>>>
>>>
 >>>  from naive.models import Book
>>>  book = Book . objects . create ( name = 'Python Tricks' , price = 1000 , weight = 200 )
>>>  book
<Product: Python Tricks>

To create a cart, you first need to associate it with a user:

要创建购物车,您首先需要将其与用户关联:

>>>
>>>
 >>>  from django.contrib.auth import get_user_model
>>>  haki = get_user_model () . create_user ( 'haki' )

>>>  from naive.models import Cart
>>>  cart = Cart . objects . create ( user = haki )

Then the user can start adding items to it:

然后,用户可以开始向其中添加项目:

>>>
>>>
 >>>  cart . products . add ( book )
>>>  cart . products . all ()
<QuerySet [<Book: Python Tricks>]>

Pro

专业版

  • Easy to understand and maintain: It’s sufficient for a single type of product.
  • 易于理解和维护:对于单一类型的产品就足够了。

Con

骗局

  • Restricted to homogeneous products: It only supports products with the same set of attributes. Polymorphism is not captured or permitted at all.
  • 仅限同类产品:仅支持具有相同属性集的产品。 根本不捕获或不允许多态。

稀疏模型 (Sparse Model)

With the success of your online bookstore, users started to ask if you also sell e-books. E-books are a great product for your online store, and you want to start selling them right away.

随着在线书店的成功,用户开始询问您是否也销售电子书。 电子书是您的在线商店的好产品,您想立即开始销售它们。

A physical book is different from an e-book:

一本物理书不同于一本电子书:

  • An e-book has no weight. It’s a virtual product.

  • An e-book does not require shipment. Users download it from the website.

  • 电子书没有分量。 这是一个虚拟产品。

  • 电子书不需要发货。 用户从网站下载它。

To make your existing model support the additional information for selling e-books, you add some fields to the existing Book model:

为了使您的现有模型支持销售电子书的其他信息,您可以在现有的Book模型中添加一些字段:

First, you added a type field to indicate what type of book it is. Then, you added a URL field to store the download link of the e-book.

首先,您添加了一个类型字段,以指示它是什么类型的书。 然后,您添加了URL字段来存储电子书的下载链接。

To add a physical book to your bookstore, do the following:

要将实体书添加到您的书店,请执行以下操作:

>>>
>>> from sparse.models import Book
>>> physical_book = Book.objects.create(
...     type=Book.TYPE_PHYSICAL,
...     name='Python Tricks',
...     price=1000,
...     weight=200,
...     download_link=None,
... )
>>> physical_book
<Book: [Physical] Python Tricks>

>>>

To add a new e-book, you do the following:

要添加新的电子书,请执行以下操作:

>>>
>>> virtual_book = Book.objects.create(
...     type=Book.TYPE_VIRTUAL,
...     name='The Old Man and the Sea',
...     price=1500,
...     weight=0,
...     download_link='https://books.com/12345',
... )
>>> virtual_book
<Book: [Virtual] The Old Man and the Sea>

>>>

Your users can now add both books and e-books to the cart:

您的用户现在可以将书籍和电子书添加到购物车中:

>>>
>>> from sparse.models import Cart
>>> cart = Cart.objects.create(user=user)
>>> cart.books.add(physical_book, virtual_book)
>>> cart.books.all()
<QuerySet [<Book: [Physical] Python Tricks>, <Book: [Virtual] The Old Man and the Sea>]>

>>>

The virtual books are a big hit, and you decide to hire employees. The new employees are apparently not so tech savvy, and you start seeing weird things in the database:

虚拟书籍很受欢迎,您决定雇用员工。 新员工显然不那么精通技术,您开始在数据库中看到怪异的东西:

>>>
>>> Book.objects.create(
...     type=Book.TYPE_PHYSICAL,
...     name='Python Tricks',
...     price=1000,
...     weight=0,
...     download_link='http://books.com/54321',
... )

>>>

That book apparently weighs 0 pounds and has a download link.

那本书显然重达0磅,并有下载链接。

This e-book apparently weighs 100g and has no download link:

这本电子书显然重100克,没有下载链接:

>>>
>>> Book.objects.create(
...     type=Book.TYPE_VIRTUAL,
...     name='Python Tricks',
...     price=1000,
...     weight=100,
...     download_link=None,
... )

>>>

This doesn’t make any sense. You have a data integrity problem.

这没有任何意义。 您有数据完整性问题。

To overcome integrity problems, you add validations to the model:

为了克服完整性问题,您可以向模型添加验证:

 from from django.core.exceptions django.core.exceptions import import ValidationError


ValidationError


class class BookBook (( modelsmodels .. ModelModel ):

    ):

    # ...

    # ...

    def def cleanclean (( selfself ) ) -> -> NoneNone :
        :
        if if selfself .. type type == == BookBook .. TYPE_VIRTUALTYPE_VIRTUAL :
            :
            if if selfself .. weight weight != != 00 :
                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值