如何在Django中创建多对一关系并在管理界面显示

1 投票
2 回答
2528 浏览
提问于 2025-04-17 08:33

我遇到了一个问题——我想在Django中创建一种多对一的关系,用来表示对象和对象的部分之间的关系,比如:

class Website(models.Model):
    name = models.CharField(max_length = 100)

class WebsiteIp(models.Model):
    website = models.ForeignKey(Website, primary_key = True)
    ip = models.CharField(max_length = 40, primary_key = True)
    introduction_date = models.DateField()

这些关系都应该在网站上(父对象)的编辑页面上展示。虽然听起来这个问题很简单,但我真的找不到什么有用的资料来解决这个问题。

2 个回答

0

解决这个问题的方法是修改依赖关系的主键设置(但这种方法只适用于像这种情况——当有一个可能在整个表中唯一的键时,比如这里的ip)。

class WebsiteIp(models.Model):
    website = models.ForeignKey(Website)
    ip = models.CharField(max_length = 40, primary_key = True)
    introduction_date = models.DateField()

在做完这个步骤之后(而且只有在这个步骤之后),mkoistinen 提出的部分解决方案才会按预期工作。一般来说,问题在于django在检查能否创建新对象时,错误地检查了主键列的唯一性。因此,我猜也可以通过重写一些models.Model的方法来修复这个问题,但我对django的内部机制了解不够,无法指出具体是哪个方法。

3

在你的WebsiteIP的ForeignKey中添加related_name参数,像这样:

class Website(models.Model):
    name = models.CharField(max_length = 100)

class WebsiteIp(models.Model):
    website = models.ForeignKey(Website, primary_key = True, related_name="IPs")
    ip = models.CharField(max_length = 40)
    introduction_date = models.DateField()

然后,你可以像这样从Website引用多个IP,形成一个多对一的关系:

website = Website.objects.filter(name="blah")
if website.count():
  IPs = website[0].IPs

当然这只是个初步的想法,具体还需要测试,但这应该能帮你找到正确的方向。另外,你可以查看这个链接了解更多:https://docs.djangoproject.com/en/dev/topics/db/models/#many-to-one-relationships

在你的admin.py文件中,假设你有类似这样的代码:

class WebsiteAdmin(admin.ModelAdmin):
  list_display = ('name',)
  search_fields = ['name']
  ordering = ('name', )

更新为以下内容:

class WebsiteIpInline(admin.TabularInline):
  model = WebsiteIp
  extra = 1

class WebsiteAdmin(admin.ModelAdmin):
  list_display = ('name',)
  search_fields = ['name']
  inlines = ( WebsiteIpInline, )
  ordering = ('name', )

这样应该能显示你想要的结果!

撰写回答