Django задает параметры конфиденциальности для каждой модели

Я рассмотрел этот вопрос, лучший способ реализовать конфиденциальность каждого поля в модели django, и ответы на него, похоже, не решают мою проблему, поэтому я задаю некоторые вопросы, связанные с этим,

хорошо, у меня есть модель User. Я хочу, чтобы пользователь мог контролировать конфиденциальность каждой области своего профиля (может быть gender , education , interests т. Д.).

Параметры конфиденциальности не должны ограничиваться только частными или публичными, но как описательными, как

  • общественности
  • друзья
  • только я
  • friend List 1 (User.friendlist.one)
  • friend List 2 (User.friendlist.two)
  • Список друзей 3 (User.friendlist.three)
  • другой infinte список, который пользователь может создать.

Я также не хочу, чтобы эти параметры конфиденциальности сохранялись на другой модели, но то же самое, чтобы с одним запросом я мог получить объект пользователя вместе с параметрами конфиденциальности.

поэтому, если у меня есть UserModel,

 class User(models.Model): name = models.CharField() email = models.EmailField() phone = models.CharField() 

Как настроить настройку конфиденциальности здесь? Я использую postgres, могу ли я отобразить поле JSON или Hstore даже ArrayField?

Какое лучшее решение, с которым люди обычно сталкивались с Django с такой же проблемой?

Обновить:

У меня есть n полей модели. Я действительно хочу сохранить настройки конфиденциальности каждого экземпляра самостоятельно или каким-либо другим удобным способом.

5 Solutions collect form web for “Django задает параметры конфиденциальности для каждой модели”

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

Поэтому мне нужно было пойти с Postgres JSONField или HStoreField. Поскольку Django имеет хорошую поддержку для postgres freatures, я нашел эти очки для выбора, который я сделал.

  • JSON / HashStore можно запросить с помощью Django ORM.
  • Конфигурации – это простой JSON / HashStore, которые легко редактировать и поддерживать, чем разрешения и отношения.
  • Я обнаружил, что время запроса к базе данных больше с разрешениями, чем с JSON / HStore. (хиты выше с разрешениями)
  • Добавление и проверка разрешений на одно поле сложнее, чем добавление / проверка JSON.
  • В какой-то момент в будущем, если вы получите более простое или бесплатное решение, я могу перейти на него, имея полную конфигурацию в одном поле.

Итак, мой выбор состоял в том, чтобы пойти с конфигурационной моделью.

 class UserConfiguration(models.Model): user = # link to the user model configuration = #either an HStore of JSONFeild 

Затем написал валидатор, чтобы убедиться, что модель данных конфигурации не испорчена при сохранении и обновлении. Я сгруппировал поля, чтобы свести к минимуму поля проверки. Затем написал простой синтаксический анализатор, который принимает пользователей и находит связь между ними, а затем отображает конфигурацию, чтобы возвращать разрешенные данные поля (регистрируется в 2-4 мс в неоптимизированной реализации, чего достаточно на данный момент). ( С разрешения мне понадобится отдельный список друзей, который будет поддерживаться, и должен обновить все групповые разрешения при обновлении конфигурации конфиденциальности, тогда мне все равно придется проверять разрешения и обрабатывать их, что может занять меньше времени, чем это, но для стоимость сложной системы ).

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

Обновить

У меня есть более подробные запросы к базе данных. В предыдущей реализации отношения между пользователями, где итерация, которая была рассчитана примерно на 1-2 мс, изменили эту реализацию на .value_list('relations', flat=True) сократили время запроса до 400-520 мкс.

Я также не хочу, чтобы эти параметры конфиденциальности сохранялись на другой модели, но то же самое, чтобы с одним запросом я мог получить объект пользователя вместе с параметрами конфиденциальности.

Я бы посоветовал вам отделить объекты конфиденциальности от UserModel , чтобы не испортить ваши данные пользователей вместе с этими параметрами. Чтобы свести к минимуму количество запросов к базе данных, используйте djangos select_related и prefetch_related .

Требования, определенные вами IMO, приводят к набору объектов, связанных с конфиденциальностью, которые привязаны к UserModel . django.contrib.auth – хороший момент для начала. Он будет расширяться. Прочитайте документы по этой теме.

Если вы ожидаете большого количества пользователей и, следовательно, еще большее количество групп, вы можете захотеть написать разрешения, разрешенные для одного пользователя на сеансе на основе redis, чтобы иметь возможность быстро их загружать при каждой загрузке страницы.

ОБНОВИТЬ:

Я подумал немного больше о ваших требованиях и пришел к выводу, что вам нужно разрешение на объект, как это реализовано в django-guardian . Сначала вы должны начать чтение своих образцов и кода. Они создают это поверх django.contrib.auth но не зависят от него, что делает его также полезным с пользовательскими реализациями, которые следуют интерфейсам в django.contrib.auth .

Как насчет чего-то подобного?

 class EditorList(models.Model): name = models.CharField(...) user = models.ForeignKey(User) editor = models.ManyToManyField(User) class UserPermission(models.Model): user = models.ForeignKey(User) name = models.BooleanField(default=False) email = models.BooleanField(default=False) phone = models.BooleanField(default=False) ... editor = models.ManyToManyField(User) editor_list = models.ManyToManyField(EditorList) 

Если пользователь хочет предоставить права «электронной почты» для public , она создает UserPermission с editor=None и « editor_list=None и « email=True .

Если она хочет разрешить пользователю «ривадиз» редактировать электронную почту, она создает UserPermission с editor='rivadiz' и email=True .

Если она хочет создать список друзей, которые могут редактировать свой телефон, то она создает и заполняет EditorList под названием «my_friends», а затем создает UserPermission с editor_list='my_friends' и phone=True

Затем вы можете запросить всех пользователей, у которых есть разрешение на редактирование любого поля для любого пользователя. Вы можете определить некоторые свойства в модели User чтобы легко проверить, какие поля доступны для редактирования, с учетом User и editor . Сначала вам нужно будет получить EditorLists редакторов, к которым принадлежит редактор, а затем сделать что-то вроде

perms = UserPermissions.objects.filter(user=self).filter(Q(editor=editor) | Q(editor_list=editor_list))

Это будет намного более громоздким без отдельной модели разрешений. Тот факт, что вы можете связать заданное поле профиля отдельного пользователя с более чем одним списком друзей, подразумевает таблицу Many to Many, и вам лучше просто позволить Django обрабатывать это для вас.

Я думаю, что-то более похожее:

 class Visibility(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) field = models.CharField(max_length=32) public = models.BooleanField(default=False) friends = models.BooleanField(default=False) lists = models.ManyToManyField(FriendList) @staticmethod def visible_profile(request_user, profile_user): """Get a dictionary of profile_user's profile, as should be visible to request_user...""" 

(Я оставлю детали такого метода, как упражнение, но это не слишком сложно).

Я предупреждаю, что пользовательский интерфейс, используемый для пользователя для установки этих разрешений, скорее всего, будет проблемой из-за связи «многие-ко-многим» с списками друзей. Не невозможно, определенно, но немного утомительно.

Ключевым преимуществом таблицы M2M здесь является то, что она будет самоподдерживаться, если пользователь или любой список друзей удалены – за одним исключением. Идея в этой схеме заключается в том, что без каких-либо записей Visibility все данные являются частными (чтобы все могли видеть ваше имя, вы добавили бы запись видимости с пользователем = (самостоятельно), поле = «имя» и public = True. Поскольку запись Видимости, где public = False, friends = False и lists = [] бессмысленна, я проверял бы эту ситуацию после того, как пользователь ее отредактирует и полностью удалит эту запись.

Другая правильная стратегия состоит в том, чтобы иметь две специальные записи FriendList: один для «public», а другой для «всех друзей». Это упрощает модель видимости совсем немного за счет немного большего количества кода в другом месте.

Прежде всего, на мой взгляд, вы должны пойти на несколько моделей и ускорить выполнение запросов, как уже упоминалось в других ответах, вы можете использовать кеширование или select_related или prefetch_related в соответствии с вашей usecase.

Итак, вот мое предлагаемое решение:

Модель пользователя

 class User(models.Model): name = models.CharField() email = models.EmailField() phone = models.CharField() ... public_allowed_read_fields = ArrayField(models.IntegerField()) friends_allowed_read_fields = ArrayField(models.IntegerField()) me_allowed_read_fields = ArrayField(models.IntegerField()) friends = models.ManyToManyField(User) part_of = models.ManyToManyField(Group, through=GroupPrivacy) 

Модель группы (список друзей)

 class Group(models.Model): name = models.CharField() 

Через модель

 class GroupPrivacy(models.Model): user = models.ForeignKey(User) group = models.ForeignKey(Group) allowed_read_fields = ArrayField(models.IntegerField()) 

Отображение полей модели пользователя для целых чисел

 USER_FIELDS_MAPPING = ( (1, User._meta.get_field('name')), (2, User._meta.get_field('email')), (3, User._meta.get_field('phone')), ... ) 

КАК ЭТО ПОМОГАЕТ?

  • для каждого из public , friends и me вы можете иметь поле в самой модели пользователя, как уже упоминалось выше, т.е. public_allowed_read_fields , friends_allowed_read_fields и me_allowed_read_fields соответственно. Каждое из этих полей будет содержать список целых чисел, сопоставленных с ними внутри USER_FIELDS_MAPPING (подробно объясняется ниже)

  • для friend_list_1 вас будет группа с именем friend_list_1. Теперь дело в том, что пользователь хочет показать или скрыть определенный набор полей в этом списке друзей. Вот где в игру входит through модель, GroupPrivacy . Используя эту модель, вы определяете отношение M2M между пользователем и группой с некоторыми дополнительными свойствами, которые являются уникальными для этого отношения. В этой модели GroupPrivacy вы можете увидеть поле allowed_read_fields , оно используется для хранения массива целых чисел, соответствующих тем, которые указаны в USER_FIELDS_MAPPING . Итак, скажем, для группы friend_list_1 и пользователя A , allowed_read_fields = [1,2]. Теперь, если вы сопоставляете это с USER_FIELDS_MAPPING, вы узнаете, что пользователь A хочет показывать только имя и адрес электронной почты друзьям в этом списке. Аналогично, разные пользователи в группе friend_list_1 будут иметь разные значения в allowed_read_fields для соответствующего экземпляра модели GroupPrivacy .

Это будет похоже на несколько групп.

  • Psycopg2 использует память для большого запроса select
  • Обратный запрос Django по последнему созданному объекту
  • django.db.utils.OperationalError: не удалось подключиться к серверу: нет такого файла или каталога
  • Django ForeignKey показывает данные из PostgreSQL
  • Как заказать данные в sqlalchemy по списку
  • Как вы присоединяетесь к двум таблицам в поле внешнего ключа с помощью django ORM?
  • Поле Integer не автоинкремент в SQLAlchemy
  • Выключить предупреждение в sqlalchemy
  • Python - лучший язык программирования в мире.