首页 > 解决方案 > 将 Django 管理面板对象创建功能与多对多模型一起使用

问题描述

我正在尝试使用 django 管理板功能,以便能够将管理面板中的数据插入到具有一对多和多对多关系的表中。我使用__str__功能(Python 3.6)在管理面板中创建可理解的字符串,而不是"Testcase object(1)"类似的描述,以便能够为执行测试模型选择正确的测试用例 ID 和测试运行 ID。但它看起来像在执行测试对象创建期间管理面板而不是测试用例 id 值和 testrun id 值尝试将外部 int 键设置为相应的文本值。我因错误而惨遭失败:

tc = Testcases.objects.get(pk=self.testcase_id)
...
TypeError: int() argument must be a string, a bytes-like object or a number, not 'Testcases'

楷模:

class Testcases(models.Model):
    name = models.CharField(max_length=30)

    def __str__(self):
        return f"Testcase: {self.name}"


class Testruns(models.Model):
    starttime = models.TimeField()
    endtime = models.TimeField()

    def __str__(self):
        return f"Testrun: {self.starttime} - {self.endtime}"


class Executedtests(models.Model):
    testcase_id = models.ForeignKey("testcases", models.CASCADE)
    testrun_id = models.ForeignKey("testruns", models.CASCADE)
    teststart = models.TimeField(blank=True, null=True)  # This field type is a guess.
    testend = models.TimeField(blank=True, null=True)  # This field type is a guess.

    def __str__(self):
        tc = Testcases.objects.get(pk=self.testcase_id)
        tr = Testruns.objects.get(pk=self.testrun_id)
        return f"{tc}(tr), Start: {self.teststart}, End: {self.testend}"

在应用程序admin.py中,我只注册了所有这些模型。

管理表单的选择标签看起来不错:

<select id="id_testcase_id" name="testcase_id">
    <option value="1">Testcase: Test1</option>
    ...
</select>

标签: djangodjango-modelsdjango-admin

解决方案


如果你定义 afieldname是 a ,Django 会自动添加一个包含该对象主键的ForeignKey额外字段。fieldname_id所以这里 Django 构造了一个testcase_id_id,它包含它所引用的实例的主键Testcases,但这使得它在语义上相当“丑陋”。

因此,在它引用的项目之后命名关系更加一致,并让 Django 生成fieldname_id,这样您仍然可以提取(和查询)该值。

因此,最小的修复是:

class Executedtests(models.Model):
    # rename the relations (drop the _id suffix)
    testcase = models.ForeignKey("testcases", models.CASCADE)
    testrun = models.ForeignKey("testruns", models.CASCADE)
    teststart = models.TimeField(blank=True, null=True)  # This field type is a guess.
    testend = models.TimeField(blank=True, null=True)  # This field type is a guess.

    def __str__(self):
        tc = Testcases.objects.get(pk=self.testcase_id)
        tr = Testruns.objects.get(pk=self.testrun_id)
        return f"{tc}(tr), Start: {self.teststart}, End: {self.testend}"

然后您的视图将起作用,因为testcase_id将不再包含Testcases实例(外键采用您引用的模型的类型),而是主键。

因此,通过调用someexecutedtests.testcase不会获得 that 的主键testcase,而是Testcases实例本身(如果尚未获取,Django 通常会执行另一个查询)。


推荐阅读