В django, как создать самореферентные, действительно симметричные отношения manytomany с некоторыми дополнительными полями под этими отношениями(в 2019 году)?
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.
Что я уже пробовал:
Модель для стадиона такова:
# -*- 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 есть:
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
Предположим, что есть два стадиона: 1. Олд Траффорд и 2. Стадион Этихад. Оба они являются соседними стадионами с расстоянием между ними 12,5 км. Если я добавлю стадион Etihaad в качестве соседа Олд Траффорда, то Олд Траффорд должен быть автоматически добавлен в качестве соседа в модельных данных Etihaad. Прямо сейчас это происходит с моим кодом. Что я делаю не так? Как можно сделать самореферентное отношение ManyToMany действительно симметричным в Django? Есть ли для этого какая-нибудь сторонняя библиотека? Кроме того, как включить ввод данных в django admin и сериализовать его в DRF ?