Отношения "многие ко многим" в Django

В настоящее время я занимаюсь личным проектом, чтобы лучше понять, как работает фреймворк Django REST. По сути, я пытаюсь создать веб-приложение, которое позволяет пользователям обмениваться файлами, своего рода упрощенная версия Google Drive/Dropbox.

Однако у меня возникли проблемы с отношениями "многие ко многим" в моих моделях. По сути, я хочу, чтобы у каждого пользователя были свои папки, в каждой папке было бы ноль или более файлов. Затем пользователь может поделиться (доступ только для чтения или разрешить запись/удаление) всей папкой или только отдельными файлами.

  • У пользователя может быть одна (домашняя папка) или более папок
  • Папка может иметь ноль (пустая папка) или более файлов
  • Папку может читать один (владелец) или более пользователей, то же самое относится и к файлам
  • Многие пользователи могут получить доступ (только чтение или запись) к папке/файлу в зависимости от их уровня прав

Я пытаюсь смоделировать эти отношения следующим образом:

from django.db import models
from django.contrib.auth.models import User


class Folder(models.Model):
    title = models.CharField(max_length=50)
    description = models.TextField()
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    users_can_edit = models.ManyToManyField(User)
    users_can_see = models.ManyToManyField(User)



class File(models.Model):
    title = models.CharField(max_length=50)
    description = models.TextField()
    folder = models.ForeignKey(Folder, on_delete=models.CASCADE)
    created_on = models.DateTimeField(auto_now=True, editable=False)
    users_can_edit = models.ManyToManyField(User)
    users_can_see = models.ManyToManyField(User)

Однако, я получаю эту ошибку, которую я не смог исправить, когда я пытаюсь запустить сервер:

ERRORS:
api.File.users_can_edit: (fields.E304) Reverse accessor for 'api.File.users_can_edit' clashes with reverse accessor for 'api.File.users_can_see'.
        HINT: Add or change a related_name argument to the definition for 'api.File.users_can_edit' or 'api.File.users_can_see'.
api.File.users_can_see: (fields.E304) Reverse accessor for 'api.File.users_can_see' clashes with reverse accessor for 'api.File.users_can_edit'.
        HINT: Add or change a related_name argument to the definition for 'api.File.users_can_see' or 'api.File.users_can_edit'.
api.Folder.user: (fields.E304) Reverse accessor for 'api.Folder.user' clashes with reverse accessor for 'api.Folder.users_can_edit'.
        HINT: Add or change a related_name argument to the definition for 'api.Folder.user' or 'api.Folder.users_can_edit'.
api.Folder.user: (fields.E304) Reverse accessor for 'api.Folder.user' clashes with reverse accessor for 'api.Folder.users_can_see'.
        HINT: Add or change a related_name argument to the definition for 'api.Folder.user' or 'api.Folder.users_can_see'.
api.Folder.users_can_edit: (fields.E304) Reverse accessor for 'api.Folder.users_can_edit' clashes with reverse accessor for 'api.Folder.user'.
        HINT: Add or change a related_name argument to the definition for 'api.Folder.users_can_edit' or 'api.Folder.user'.
api.Folder.users_can_edit: (fields.E304) Reverse accessor for 'api.Folder.users_can_edit' clashes with reverse accessor for 'api.Folder.users_can_see'.
        HINT: Add or change a related_name argument to the definition for 'api.Folder.users_can_edit' or 'api.Folder.users_can_see'.
api.Folder.users_can_see: (fields.E304) Reverse accessor for 'api.Folder.users_can_see' clashes with reverse accessor for 'api.Folder.user'.
        HINT: Add or change a related_name argument to the definition for 'api.Folder.users_can_see' or 'api.Folder.user'.
api.Folder.users_can_see: (fields.E304) Reverse accessor for 'api.Folder.users_can_see' clashes with reverse accessor for 'api.Folder.users_can_edit'.
        HINT: Add or change a related_name argument to the definition for 'api.Folder.users_can_see' or 'api.Folder.users_can_edit'.

Я все еще новичок и знаю только основы SQL. Учитывая это, подходит ли такой подход или есть другой способ моделирования этих отношений?

У вас два ManyToManyField к одной модели, поэтому related_name=…s [Django-doc] одинаковы и будут конфликтовать. Вы должны указать related_name=…s, так:

from django.db import models
from django.conf import settings

class Folder(models.Model):
    title = models.CharField(max_length=50)
    description = models.TextField()
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    users_can_edit = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        related_name='folders_that_can_be_edited'
    )
    users_can_see = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        related_name='folders_that_can_be_seen'
    )

class File(models.Model):
    title = models.CharField(max_length=50)
    description = models.TextField()
    folder = models.ForeignKey(Folder, on_delete=models.CASCADE)
    created_on = models.DateTimeField(auto_now=True, editable=False)
    users_can_edit = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        related_name='files_that_can_be_edited'
    )
    users_can_see = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        related_name='files_that_can_be_seen'
    )

Но может быть лучше определить single ManyToManyField с through=… моделью [Django-doc], которая затем кодирует разрешения этой комбинации пользователь-файл, это потребует меньше таблиц, и сделает фильтрацию и т.д. более эффективной.


Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Вернуться на верх