【问题标题】:Simplify Django models for an eStore and assistance with ManyToManyField简化 eStore 的 Django 模型并使用 ManyToManyField 提供帮助
【发布时间】:2014-06-10 13:31:46
【问题描述】:

建立一个专门销售衬衫、书籍和专辑的电子商务网站,以了解不同的款式。让我失望的两件事是:

1.) 我不确定我是否在我的模型中创建了过多的冗余,如果是的话,我该如何最小化它。例如,对于音乐专辑,我正在为专辑、艺术家和曲目创建一个模型,并且在每个模型中我多次引用其他模型。

2.) 关于我的 ManyToManyFields,通过引用一个直到在 models.py 中进一步向下定义的模型,python manage.py syncdb 会抛出一个我没有定义关系的错误。在这个 SO 问题中进一步解释了这一点:Django says my model is not defined

这是我的models.py:

from django.db import models

#Artist, Album, and Tracks are tables for music albums

class Artist(models.Model):
    artist_name = models.CharField(max_length=100, null=False, blank=False)
    short_bio = models.CharField(max_length=2000, null=False, blank=False)
    albums = models.ManyToManyField(Album)
    tracks = models.ManyToManyField(Track)
    added = models.DateTimeField(auto_now=True, auto_now_add=False)
    updated = models.DateTimeField(auto_now=False, auto_now_add=True)

class Album(models.Model):
    album_name = models.CharField(max_length=150, null=False, blank=False)
    artists = models.ManyToManyField(Artist)
    tracks = models.ManyToManyField(Track)
    active = models.BooleanField(default=True)
    slug = models.SlugField(null=True, blank=True)
    added = models.DateTimeField(auto_now=True, auto_now_add=False)
    updated = models.DateTimeField(auto_now=False, auto_now_add=True)

    def __unicode__(self):
        return self.album_name

class Track(models.Model):
    track_name = models.CharField(max_length=200, null=False, blank=False)
    artists = models.ManyToManyField(Artist)
    album_name = models.ManyToManyField(Album)

class AlbumImage(models.Model):
    album_name = models.ForeignKey(Album)
    description = models.CharField(max_length=200, null=True, blank=False)
    main = models.BooleanField(default=False)
    image = models.ImageField(upload_to='albums/images/')
    added = models.DateTimeField(auto_now=True, auto_now_add=False)
    updated = models.DateTimeField(auto_now=False, auto_now_add=True)


#Book, BookGenre, Author tables for books

class Book(models.Model):
    title = models.CharField(max_length=200, null=False, blank=False)
    authors = models.ManyToManyField(Author)
    pages = models.PositiveSmallIntegerField(null=True, blank=True)
    genre = models.ManyToManyField(BookGenre)
    active = models.BooleanField(default=True)
    slug = models.SlugField(null=True, blank=True)
    added = models.DateTimeField(auto_now=True, auto_now_add=False)
    updated = models.DateTimeField(auto_now=False, auto_now_add=True)

    def __unicode__(self):
        return self.title

class Author(models.Model):
    author_name = models.CharField(max_length=50, null=False, blank=False)
    short_bio = models.CharField(max_length=2000, null=True, blank=True)
    titles = models.ManyToManyField(Book)
    genre = models.ManyToManyField(BookGenre)
    added = models.DateTimeField(auto_now=True, auto_now_add=False)
    updated = models.DateTimeField(auto_now=False, auto_now_add=True)

class BookGenre(models.Model):
    genre = models.CharField(max_length=50, null=False, blank=False)

class BookImage(models.Model):
    title = models.ForeignKey(Book)
    description = models.CharField(max_length=200, null=True, blank=False)
    main = models.BooleanField(default=False)
    image = models.ImageField(upload_to='books/images/')
    added = models.DateTimeField(auto_now=True, auto_now_add=False)
    updated = models.DateTimeField(auto_now=False, auto_now_add=True)


#Shirt and Colors are for tables exclusively for shirts

class Shirt(models.Model):
    title = models.CharField(max_length=50)
    description = models.CharField(max_length=2000, null=True, blank=False)
    styles = models.ManyToManyField('ShirtStyle.style')
    sz_xs = models.PositiveSmallIntegerField(null=False, blank=False)
    sz_sm = models.PositiveSmallIntegerField(null=False, blank=False)
    sz_md = models.PositiveSmallIntegerField(null=False, blank=False)
    sz_lg = models.PositiveSmallIntegerField(null=False, blank=False)
    sz_xl = models.PositiveSmallIntegerField(null=False, blank=False)
    active = models.BooleanField(default=True)
    slug = models.SlugField(null=True, blank=True)
    added = models.DateTimeField(auto_now=True, auto_now_add=False)
    updated = models.DateTimeField(auto_now=False, auto_now_add=True)

    def __unicode__(self):
        return self.title

class ShirtStyle(models.Model):
    style = models.CharField(max_length=50, null=False, blank=False)
    title = models.ForeignKey('Shirt.title')

class ShirtImage(models.Model):
    title = models.ForeignKey(Shirt)
    description = models.CharField(max_length=200, null=True, blank=False)
    main = models.BooleanField(default=False)
    image = models.ImageField(upload_to='shirts/images/')
    added = models.DateTimeField(auto_now=True, auto_now_add=False)
    updated = models.DateTimeField(auto_now=False, auto_now_add=True)

感谢您的宝贵时间。

【问题讨论】:

    标签: python database django sqlite django-models


    【解决方案1】:

    很好的开始,但是,正如您所猜想的那样,您的模型中的冗余有点过多。我会提供以下提示:

    1) 尽量不要使用ManyToManyField。

    ManyToMany 应该用在每个模型都与其他模型相关的地方。对于您的某些模型,情况并非如此。例如,虽然每个Album 有很多Tracks,但反过来可能不正确;每个Track 属于一个,并且只有一个Album。 “Smells Like Teen Spirit”是 Album“Nevermind”上的 Track,但它不是任何其他 Album 上的 Track。因此,您应该改用ForeignKey。

    class Track(models.Model):
        track_name = models.CharField(max_length=200, null=False, blank=False)
        album_name = models.ForeignKey(Album)
    

    这里的一个例外是如果Track 实际上会出现在多个Albums 上,即如果它也出现在“Greatest Hits”Album 或除“Nevermind”之外的其他内容上”。

    2) 不要重复关系

    在上面的示例中,我们通过ForeignKey 将每个Track 连接到Album。我们不需要做相反的事情。也就是说,Album 不需要显式字段来跟踪其所有Tracks。您可以在查询时执行此操作。有关进行跨关系查询的 Django 文档是 here。

    这也有更深一层的含义。您可能会通过ForeignKey 将您的Album 连接到Artist。因为可以跨越关系,所以不需要显式连接Tracks 和Artists。因此,三个模型的简单示例应该如下所示:

    from django.db import models
    
    #Artist, Album, and Tracks are tables for music albums
    
    class Artist(models.Model):
        artist_name = models.CharField(max_length=100, null=False, blank=False)
        short_bio = models.CharField(max_length=2000, null=False, blank=False)
        added = models.DateTimeField(auto_now=True, auto_now_add=False)
        updated = models.DateTimeField(auto_now=False, auto_now_add=True)
    
    class Album(models.Model):
        album_name = models.CharField(max_length=150, null=False, blank=False)
        artist = models.ForeignKey(Artist)
        active = models.BooleanField(default=True)
        slug = models.SlugField(null=True, blank=True)
        added = models.DateTimeField(auto_now=True, auto_now_add=False)
        updated = models.DateTimeField(auto_now=False, auto_now_add=True)
    
        def __unicode__(self):
            return self.album_name
    
    class Track(models.Model):
        track_name = models.CharField(max_length=200, null=False, blank=False)
        album_name = models.ForeignKey(Album)
    

    这还需要注意,如果您要将Album 连接到多个Artists,则需要对其进行一些调整。这就像您将乐队成员单独分开,即“Abbey Road”是四个不同的Artists 的Album:John、Paul、George 和 Ringo。

    3) 定义模型误差

    一旦您停止重复关系,您在 (2) 中提到的与模型有关的问题应该会消失。基本上,在您定义模型之前,您不能将模型用作关系。当您在 两个 模型上对彼此执行 ManyToMany 时,这会导致问题。其中一个必须先于另一个,这将导致导入问题。如果你想在定义之前使用一个null=True,你也可以设置它,但在这种情况下确实没有必要。

    如果您有任何不清楚或有任何其他问题,请告诉我。

    编辑:

    附加提示:

    如果您要在许多模型上使用added 和modified 字段,您可能需要使用django-model-utils 包。文档here。您可以将自动生成 created 和 modified 字段的 TimeStampedModel 子类化。见here。

    因此:

    from model_utils.models import TimeStampedModel
    
    class Artist(TimeStampedModel):
        artist_name = models.CharField(max_length=100, null=False, blank=False)
        short_bio = models.CharField(max_length=2000, null=False, blank=False)
    

    【讨论】:

    • 谢谢亚历克斯。这是非常有见地的,并且极大地帮助了我对 DB 模式的理解。我一直在剖析您的答案,并深入阅读有关 Django 模型的兔子洞。两个问题: 1.) 由于 ForeignKey 关系较少,我遇到了 admin.py 的问题,它需要 ForeignKeys 进行内联编辑。您如何在不更改模型的情况下创建一个添加艺术家、专辑、曲目和图像的一站式界面? 2. 你最成功的例子是我使用 ManyToMany 的原因。如果 95% 的歌曲是原创歌曲,只有 5% 是翻唱歌曲,还有必要吗?
    • @SeanDominguez: Re (1): 你试过InlineModelAdmin 对象吗?请参阅文档here。这允许使用外键进行内联模型编辑。如果您对此有疑问,我建议您创建一个新问题,因为在没有看到您的代码的情况下很难在 cmets 中回答。至于(2):如果您有理由将一个子模型分配给多个父模型,则需要使用 ManyToMany。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-01
    • 1970-01-01
    • 2023-03-18
    • 2020-07-27
    • 2020-05-11
    • 1970-01-01
    相关资源
    最近更新 更多