Question

I have a Django app with three models which use ContentTypes and Generic to try and allow the Task model to have a ForeignKey to either of the other two models using How to use dynamic foreignkey in Django? as a guide (although I'll admit that I have no clue what's going on with this approach).

class Task(models.Model):
    date = models.DateTimeField(null = True)
    day = models.IntegerField(null = True)
    task = models.CharField(max_length = 100, null = False)
    owner = models.CharField(max_length = 25, null = True)
    notes = models.CharField(max_length = 250, null = True)
    isDone = models.BooleanField(default = False, null = False)

    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    maintenance = generic.GenericForeignKey('content_type', 'object_id')

class Maintenance(models.Model):
    startMonth = models.CharField(max_length = 15, null = False)
    startYear = models.IntegerField(null = False)
    location = models.CharField(max_length = 20, null = False)
    mode = models.CharField(max_length = 20, null = False)

    taskRef = generic.GenericRelation(Task)

class Template(models.Model):
    name = models.CharField(max_length = 25, null = False)
    location = models.CharField(max_length = 20, null = False)
    mode = models.CharField(max_length = 20, null = False)

    taskRef = generic.GenericRelation(Task)

Normally if Task just has a normal ForeignKey to Maintenance, I can get all the Tasks connected to any given Maintenance with Maintenance.task_set.all() but with this dynamic foreignkey system that function doesn't work. Does anyone know of an alternative function call to achieve this affect?

Was it helpful?

Solution

Like user710907 says, Maintenance.taskRef.all() should do the trick. When you specify a ForeignKey relation, you can set a "related_name" argument that is used for the reverse relationship. If you don't specify, this defaults to "model_name_set".

class Foo(models.Model):
    ...

class Bar(models.Model):
    ...
    foo = models.ForeignKey(Foo, related_name="related_bars")

Now you can access that relationship via bar.foo from the one side, or foo.related_bars from the other. If you don't specify, the latter argument will default to foo.bar_set.

In your example, you define the relationship from both sides; the FK is defined on Task, and the reference is defined on Maintenance and Template. Since you've provided fields on both models that handle the relationship, there's no need to provide a maintenance_set default.

edit: Upon further inspection, I think part of the confusion might be around your Task.maintenance field. If I'm not mistaken, that's the field you want to point to either Maintenance or Template, right? So why is it called maintenance? I definitely recommend reading this section of the docs too.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top