Reputation: 412
Say object contains multiple types of objects (Models
) in an array, like a Page
, that could contain a Post
, Blog
, Picture
, in any quantity or order, where the user scrolls down and sees the following element and that depending on the page
, is next element one of these types of elements. Thus a Page
could contain:
Post
Post
Picture
Or something pretty different such as:
Picture
Blog
Picture
An element could be an abstract entity that has an attribute as a ForeignKey
relating itself with Page
, and its inheritance would gain access to that relationship:
class Page(models.Model):
...
class PageElement(models.Model):
page = models.ForeignKey(Page, verbose_name="Page", on_delete=CASCADE)
class Meta:
abstract = True
class Post(PageElement):
...
class Blog(PageElement):
...
class Picture(PageElement):
...
With this approach, you can serialize Page
with a REST serializer, but you wouldn't have access to an pageElement_set
, instead you would need to call post_set
, blog_set
, picture_set
and loose the order of the objects.
By just adding a related_name
key in the ForeignKey
, we get an error:
pages.Picture.page: (fields.E305) Reverse query name for 'Picture.page' clashes with reverse query name for 'Post.page'.
HINT: Add or change a related_name argument to the definition for 'Picture.page' or 'Post.page'.
The question is: How do you implement such relationships in Django?
So that you can have an order set of PageElement
instances, and be able to have the desired order.
Upvotes: 0
Views: 465
Reputation: 21812
Since you want to query multiple Models in order and you can see that your models are in Model is a PageElement
relationship, then instead of inheriting from an abstract Model you need to have a OneToOneField
with a common model:
class PageElement(models.Model):
POST = 'PO'
BLOG = 'BL'
PICTURE = 'PI'
ELEMENT_TYPE_CHOICES = [
(POST, 'Post'),
(BLOG, 'Blog'),
(PICTURE, 'Picture'),
]
element_type = models.CharField(
max_length=2,
choices=ELEMENT_TYPE_CHOICES,
default=POST,
)
# common fields
class Post():
page_element = models.OneToOneField(
PageElement,
on_delete=models.CASCADE,
related_name = "post"
)
class Blog():
page_element = models.OneToOneField(
PageElement,
on_delete=models.CASCADE,
related_name = "blog"
)
class Picture():
page_element = models.OneToOneField(
PageElement,
on_delete=models.CASCADE,
related_name = "picture"
)
You can inherit from a common abstract class that has the OneToOneField
for ease if needed.
Upvotes: 1