2

I am trying to use django admin board functionality to be able to insert data within admin panel into tables with one-to-multiple and multiple-to-multiple relations. I used __str__ functionality (Python 3.6) in order to create understandable strings in admin panel instead of "Testcase object(1)" like description to be able to select proper testcase id and testrun id for executedtests model. But it looks like admin panel during executedtest object creation instead of testcase id value and testrun id value tries to set foreign int keys to a corresponding text value. I miserably fail with error:

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

Models:

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}"

Inside app admin.py I just register all those models.

The select tag of the admin form looks ok though:

<select id="id_testcase_id" name="testcase_id">
    <option value="1">Testcase: Test1</option>
    ...
</select>
1
  • 1
    You defined a foreign key as testcase_id (and others with _id), but the _id is automatically generated. Commented May 28, 2018 at 13:43

1 Answer 1

2

If you define a fieldname that is a ForeignKey, Django automatically adds an extra field fieldname_id that contains the primary key of that object. So here Django has constructed a testcase_id_id, which contains the primary key of the Testcases instance it refers to, but this makes it semantically rather "ugly".

It is therefore more consistent to name the relation after the item it refers to, and let Django generate the fieldname_id, such that you can still extract (and query with) that value.

A minimal fix is thus:

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}"

Your view will then work, since testcase_id will contain no longer a Testcases instance (the foreign key takes the type of the model you refer to), but the primary key.

By calling someexecutedtests.testcase you thus do not obtain the primary key of that testcase, but the Testcases instance itself (in case it was not fetched yet, Django will usually perform another query).

Sign up to request clarification or add additional context in comments.

1 Comment

Very much appreciated for an instant solution! I will accept answer within 7 minutes when stackexchange allows me to

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.