我有两个 Django 应用程序,它们之间有外键
一个 api 应用程序和另一个名为 blog
的应用程序这是我的博客应用程序的 models.py
class Post(models.Model):
uuid = models.UUIDField(default=uuid.uuid4, primary_key=False, unique=True)
title = models.CharField(max_length=600)
authors = models.ManyToManyField('Author', related_name='authors')
tags = models.ManyToManyField('Tag', related_name='tags')
date_published = models.DateField(auto_now_add=True)
# store table of contents as JSON
table_of_contents = models.TextField(default=dict)
# s3 link to thumbnail
thumbnail = models.URLField(max_length=300)
# each post belongs to a blog
blog = models.ForeignKey('api.Blog', on_delete=models.CASCADE, default=0)
slug = models.SlugField(max_length=100, default='')
# store markdown as text
content = models.TextField(default='')
# link to post
url = models.URLField(default='')
# for json serialization
def as_dict(self):
return {
"title": self.title,
"slug": self.slug,
"authors": [ author.as_dict() for author in self.authors.all() ],
"tags": [ tag.as_dict() for tag in self.tags.all() ],
"date_published": "01/01/2001",
"table_of_contents": self.table_of_contents,
"thumbnail": self.thumbnail,
"id": str(self.uuid),
}
def __str___(self):
return self.title
class Author(models.Model):
name = models.CharField(max_length=100)
blog = models.ForeignKey('api.Blog', on_delete=models.CASCADE, default=0)
def as_dict(self):
return {
"name": self.name,
"profile": self.name
}
def __str__(self):
return self.name
class Tag(models.Model):
name = models.CharField(max_length=50)
blog = models.ForeignKey('api.Blog', on_delete=models.CASCADE, default=0)
def as_dict(self):
return {
"name": self.name
}
def __str__(self):
return self.name
还有我的“api”应用程序的 models.py
class Blog(models.Model):
# Foreign key to the associated tenant in case we need to changve schema_name
tenant = models.ForeignKey('Client', on_delete=models.CASCADE, related_name="tenant_blog", default=0)
class Templates(models.TextChoices):
SAAS = 'SAAS'
CHANGELOG = 'CHANGELOG'
HELP = 'HELP'
DEFAULT = 'DEFAULT'
PERSONAL = 'PERSONAL'
class CTAS(models.TextChoices):
DEFAULT = 'DEFAULT'
NEWSLETTER = 'NEWSLETTER'
uuid = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=False)
schema_name = models.CharField(default='', max_length=20)
useCustomDomain = models.BooleanField(default=False)
customDomain = models.CharField(max_length=100, default="")
landing_header = models.CharField(max_length=100, default="")
landing_subheader = models.CharField(max_length=100, default="")
# choose template from the list
template = models.CharField(max_length=18, choices=Templates.choices, default=Templates.DEFAULT)
url = models.URLField(max_length=300, default='')
name = models.CharField(max_length=100, default='')
owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='blogs')
posts = models.ManyToManyField('blog.Post', related_name='posts')
featuredPosts = models.ManyToManyField('blog.Post', related_name='featured')
authors = models.ManyToManyField('blog.Author', related_name="blog_authors")
tags = models.ManyToManyField("blog.Tag", related_name="blog_tags")
# call to action (newsletter or sign up)
ctaType = models.CharField(max_length=50, choices=CTAS.choices, default=CTAS.DEFAULT)
# display options
defaultModeLight = models.BooleanField(default=True)
showThemeToggle = models.BooleanField(default=True)
showSpotlight = models.BooleanField(default=True)
showFooter = models.BooleanField(default=True)
showPoweredByBadge = models.BooleanField(default=True)
showCTA = models.BooleanField(default=True)
page_views_used = models.IntegerField(default=0)
# Is the blog up/accesible to the public?
isActive = models.BooleanField(default=True)
正如您所看到的,两个应用程序都有相互依赖的外键,这会导致循环依赖。
当我跑步
makemigrations
和 migrate
时,我得到 relation "blog_author" does not exist
我已经尝试过仅删除外键字段,进行迁移,将它们添加回来并重新进行迁移。但我得到了同样的
relation "blog_author" does not exist
错误...
如何让 Django 迁移而不会遇到此错误?
当您在对象上定义
ForeignKey
关系时,Django 将自动创建一种从其他模型访问这些关系的方法。由于您要在 ForeignKey
、Post
和 Author
上定义 Tag
,因此无需从 ManyToMany
定义 Blog
关系。
如果您有
Blog
对象,您可以通过执行以下操作来访问与博客关联的帖子、作者和标签:blog.[modelname]_set
。例如,要访问与博客文章关联的所有帖子,您可以执行 blog.author_set.filter...
。
如果要指定这些属性的名称,可以使用
related_name
字段作为 ForeignKey
字段。
class Author(models.Model):
blog = models.ForeignKey('api.Blog', on_delete=models.CASCADE, default=0, related_name="authors")
这样,如果您有博客对象,您现在就可以执行
blog.authors.filter...
操作。
此外,与其为
ForeignKey
设置默认值 0,不如只允许该字段可为空:
blog = models.ForeignKey('api.Blog', on_delete=models.CASCADE, null=True, related_name="authors")
要么这样,要么删除
null
和 default
,这样当您尝试添加没有博客的作者/帖子/标签时会出现错误(如果每个作者/帖子/标签必须始终有一个关联到的博客)它)。