I’ve a model that gives details about a stadium. Once user is on the page of stadium, there’ll be list of other stadiums which are in neighbouring vicinity to current stadium, along with their distances from current stadium. I want to implement this in django. So, suppose there are two stadiums , Stadium A and stadium B which are closer to each other. Then adding stadium B as neighbour of stadium A should automatically create stadium A as neighbour of stadium B. This is different than facebook friends or twitter followers. In facebook, symmetrical relationship is not established as long as friend request isn’t accepted by the person whom request has been sent. So, person A can be said as friend of person B when he sends friend request to person B but reverse is not true if person B does not accept the request. In twitter followers, person A may follow person B but reverse may not be true. So, those are not truly symmetrical relationships. But, in my case, if two stadiums are in close proximity then they are each other’s neighbours. Adding one as neighbour of another should automatically create reverse relation. I am not able to implement this in Django. I’ve referred similar questions and referred article https://charlesleifer.com/blog/self-referencing-many-many-through/ on this. I’ve created a model where neighbour can be added but it’s not creating reverse relationship.
What I have tried:
The model for stadium is:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericRelation
from autoslug import AutoSlugField
class Stadium(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
neighbours = models.ManyToManyField(
'self', through='Neighbour', symmetrical=False, related_name='related_to+')
name = models.CharField(max_length=65)
capacity = models.PositiveIntegerField()
built = models.CharField(max_length=20, blank=True, null=True)
slug = AutoSlugField(
populate_from="name")
def add_neighbour(self, stadium, distance_in_length, distance_in_time, symm=True):
neighbour, created = Neighbour.objects.get_or_create(
from_stadium=self, to_stadium=stadium, distance_in_length=distance_in_length, distance_in_time=distance_in_time)
if symm:
# avoid recursion by passing 'symm=False'
stadium.add_neighbour(self, distance_in_length,
distance_in_time, False)
return neighbour
def remove_neighbour(self, stadium, distance_in_length, distance_in_time, symm=True):
Neighbour.objects.filter(
from_stadium=self,
to_stadium=stadium,
distance_in_length=distance_in_length,
distance_in_time=distance_in_time).delete()
if symm:
# avoid recursion by passing `symm=False`
stadium.remove_neighbour(self, distance_in_length,
distance_in_time, False)
def get_neighbours(self, distance_in_length, distance_in_time):
return self.neighbours.filter(
to_stadium__distance_in_length=distance_in_length,
to_stadium__distance_in_time=distance_in_time,
to_stadium__from_stadium=self)
def __str__(self):
return self.name
class Neighbour(models.Model):
from_stadium = models.ForeignKey(Stadium, related_name='from_stadium')
to_stadium = models.ForeignKey(Stadium, related_name='to_stadium')
distance_in_length = models.DecimalField(
max_digits=5, decimal_places=2, blank=True, null=True)
distance_length_units = (
('km', 'KiloMeters'),
('m', 'meters')
)
distance_length_unit = models.CharField(
max_length=3, choices=distance_length_units, blank=True, null=True)
distance_in_time = models.DecimalField(
max_digits=4, decimal_places=2, blank=True, null=True)
distance_time_units = (
('hours', 'Hrs'),
('minutes', 'minutes')
)
distance_time_unit = models.CharField(
max_length=7, choices=distance_time_units, blank=True, null=True)
class Meta:
unique_together = ('from_stadium', 'to_stadium')
Admin.py is:
from django.contrib import admin
from .models import (
Stadium,
NearByFacilities,
Neighbour
)
class NeighbourInline(admin.StackedInline):
model = Neighbour
fk_name = 'from_stadium'
class StadiumAdmin(admin.ModelAdmin):
inlines = [NeighbourInline]
admin.site.register(Stadium, StadiumAdmin
Suppose there are two stadiums, 1. Old Trafford and 2. Etihaad Stadium. They both are neighbouring stadiums with distance of 12.5km between them. If I add Etihaad stadium as neighbour of Old Trafford then Old Trafford should be automatically added as neighbour in Etihaad's model data. Right now, it's now happening with my code. What am I doing wrong? How can self referencing ManyToMany relation be made truly symmetrical in Django? Is there any third party library for this? Also, how to enable data entry in django admin and serialize it in DRF ?