简体   繁体   English

Django为每个模型字段设置隐私选项

[英]Django set privacy options per model field

I have gone through the question, best way to implement privacy on each field in model django and Its answers doesn't seem solve my problem so I am asking some what related question here, 我已经解决了问题, 在模型django中每个字段实现隐私的最佳方法 ,它的答案似乎没有解决我的问题,所以我在这里问一些相关的问题,

well, I have a User model. 好吧,我有一个用户模型。 I want the user to make possible to control the privacy of each and every field of their profile (may be gender , education , interests etc . ..). 我希望用户能够控制他们个人资料的每个领域的隐私(可能是gendereducationinterests等......)。

The privacy options must not to be limited to just private or public, but as descriptive as 隐私选项不得仅限于私人或公共,而是描述为

  • public 上市
  • friends 朋友
  • only me 只有我
  • friend List 1 (User.friendlist.one) 朋友列表1(User.friendlist.one)
  • friend List 2 (User.friendlist.two) 朋友列表2(User.friendlist.two)
  • friend List 3 (User.friendlist.three) 朋友列表3(User.friendlist.three)
  • another infinte lists that user may create. 用户可以创建的另一个infinte列表。

I also don't want these privacy options to be saved on another model, but the same so that with one query I could get the user object along with the privacy options. 我也不希望这些隐私选项保存在另一个模型上,但是相同,因此使用一个查询我可以获得用户对象以及隐私选项。

so If I have the UserModel, 所以,如果我有UserModel,

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

How do I setup a privacy setting here? 如何在此设置隐私设置? I am using postgres, can I map a JSON field or Hstore even an ArrayField? 我正在使用postgres,我可以映射JSON字段或Hstore甚至是ArrayField吗?

what is the best solution that people used to do with Django with same problem? 人们过去常常使用Django解决同样问题的最佳解决方案是什么?

update: 更新:

I have n model fields. 我有n个模型字段。 What I really want is to store the privacy settings of each instance on itself or some other convenient way. 我真正想要的是将每个实例的隐私设置存储在自身或其他一些方便的方式。

I have worked on my issue, tried solutions with permissions and other relations. 我已经解决了我的问题,尝试了具有权限和其他关系的解决方案。 I have a Relationship Model and all other relationship lists are derived from the Relationship model, so I don't want to maintain a separate list of Relationships. 我有一个Relationship模型,所有其他关系列表都是从Relationship模型派生的,所以我不想维护一个单独的关系列表。

So my pick was to go with a Postgres JSONField or HStoreField. 所以我的选择是使用Postgres JSONField或HStoreField。 Since Django has good support for postgres freatures, I found these points pro for the choice I made. 由于Django对postgres freatures有很好的支持,我发现这些点是我所做出的选择。

  • JSON/HashStore can be queried with Django ORM. 可以使用Django ORM查询JSON / HashStore。
  • The configurations are plain JSON/HashStore which are easy to edit and maintain than permissions and relations. 配置是普通的JSON / HashStore,它们比权限和关系易于编辑和维护。
  • I found database query time taken are larger with permissions than with JSON/HStore. 我发现使用权限的数据库查询时间比使用JSON / HStore要大。 (hits are higher with permissions) (点击率更高,有权限)
  • Adding and validating permissions per field are complex than adding/validating JSON. 添加和验证每个字段的权限比添加/验证JSON更复杂
  • At some point in future if comes a more simple or hassle free solution, I can migrate to it having whole configuration at a single field. 在将来的某个时候, 如果出现一个更简单或更轻松的解决方案,我可以在单个字段中迁移到整个配置。

So My choice was to go with a configuration model. 所以我的选择是采用配置模型。

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

Then wrote a validator to make sure configuration data model is not messed up while saving and updating. 然后编写了一个验证器,以确保在保存和更新时不会弄乱配置数据模型。 I grouped up the fields to minimize the validation fields. 我将字段分组以最小化验证字段。 Then wrote a simple parser that takes the users and finds the relationship between them, then maps with the configuration to return the allowed field data (logged at 2-4ms in an unoptimized implementation, which is enough for now). 然后编写了一个简单的解析器,它接受用户并找到它们之间的关系,然后使用配置映射以返回允许的字段数据(在未经优化的实现中以2-4ms记录,现在已足够)。 ( With permission's I would need a separate list of friends to be maintained and should update all the group permissions on updation of privacy configuration, then I still have to validate the permissions and process it, which may take lesser time than this, but for the cost of complex system ). 有了权限我需要一个单独的朋友列表来维护,并且应该更新隐私配置更新的所有组权限,然后我仍然需要验证权限并处理它,这可能需要比这更短的时间,但对于复杂系统的成本 )。

I think this method is scalable as well, as most of the processing is done in Python and database calls are cut down to the least as possible. 我认为这种方法也是可扩展的,因为大多数处理是在Python中完成的,数据库调用尽可能减少。

Update 更新

I have skinned down database queries further. 我进一步剥离了数据库查询。 In the previous implementation the relations between users where iterated, which timed around 1-2ms, changing this implementation to .value_list('relations', flat=True) cut down the query time to 400-520µs. 在前面的实现中,迭代的用户之间的关系,其定时大约1-2ms,将该实现改变为.value_list('relations', flat=True)将查询时间减少到400-520μs。

I also don't want these privacy options to be saved on another model, but the same so that with one query I could get the user object along with the privacy options. 我也不希望这些隐私选项保存在另一个模型上,但是相同,因此使用一个查询我可以获得用户对象以及隐私选项。

I would advice you to decouple the privacy objects from the UserModel , to not mess your users data together with those options. 我建议你将隐私对象与UserModel ,以免将用户数据与这些选项混为一谈。 To minimize the amount of database queries, use djangos select_related and prefetch_related . 为了尽量减少数据库查询量,使用Django的select_relatedprefetch_related

The requirements you have defined IMO lead to a set of privacy related objects, which are bound to the UserModel . 您定义的要求IMO会导致一组与隐私相关的对象绑定到UserModel django.contrib.auth is a good point to start with in this case. 在这种情况下, django.contrib.auth是一个很好的开始。 It is build to be extendable. 它是可扩展的构建。 Read the docs on that topic. 阅读有关该主题的文档

If you expect a large amount of users and therefore also an even larger amount of groups you might want to consider writing the permissions resolved for one user in a redis based session to be able to fetch them quickly on each page load. 如果您希望有大量用户,因此也需要更多的组,您可能需要考虑在基于redis的会话中编写为一个用户解析的权限,以便能够在每次加载页面时快速获取它们。

UPDATE: 更新:

I thought a little more about your requirements and came to the conclusion that you need per object permission as implemented in django-guardian . 我更多地考虑了你的要求,并得出结论,你需要在django-guardian中实现每个对象的权限。 You should start reading their samples and code first. 你应该先开始阅读他们的样本代码。 They build that on top of django.contrib.auth but without depending on it, which makes it also usable with custom implementations that follow the interfaces in django.contrib.auth . 他们在django.contrib.auth之上构建它,但不依赖于它,这使得它也可以用于遵循django.contrib.auth的接口的自定义实现。

What about something like this? 这样的事情怎么样?

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)

If a user wants to give 'email' permissions to public , then she creates a UserPermission with editor=None and editor_list=None and email=True . 如果用户想要向public提供“电子邮件”权限,那么她会创建一个UserPermission其中editor=Noneeditor_list=Noneemail=True

If she wants to allow user 'rivadiz' to edit her email, then she creates a UserPermission with editor='rivadiz' and email=True . 如果她想允许用户'rivadiz'编辑她的电子邮件,那么她创建一个带有editor='rivadiz'email=TrueUserPermission

If she wants to create a list of friends that can edit her phone, then she creates and populates an EditorList called 'my_friends', then creates a UserPermission with editor_list='my_friends' and phone=True 如果她想创建好友列表,可以编辑她的电话,然后她创建并填充一个EditorList称为“my_friends”,然后创建一个UserPermissioneditor_list='my_friends'phone=True

You should then be able to query all the users that have permission to edit any field on any user. 然后,您应该能够查询所有有权编辑任何用户的任何字段的用户。 You could define some properties in the User model for easily checking which fields are editable, given a User and an editor . 您可以在User模型中定义一些属性,以便在给定Usereditor轻松检查哪些字段是可editor You would first need to get all the EditorLists an editor belonged to, then do something like 你首先需要获得所有EditorLists编辑属于,然后像做

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

This will be much more cumbersome without a separate permissions model. 没有单独的权限模型,这将更加麻烦。 The fact that you can associate a given field of an individual user's profile with more than one friend list implies a Many to Many table, and you're better off just letting Django handle that for you. 您可以将单个用户配置文件的给定字段与多个朋友列表相关联,这意味着可以使用“多对多”表,而您最好只让Django为您处理。

I'm thinking something more like: 我在想更像的东西:

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..."""

(I'll leave the details of such a method as an exercise, but it's not too complex.) (我会把这种方法的细节留作练习,但它并不太复杂。)

I'll caution that the UI involved for a user to set those permissions is likely to be a challenge because of the many-to-many connection to friend lists. 我要提醒的是,由于与朋友列表的多对多连接,用户设置这些权限所涉及的UI可能是一个挑战。 Not impossible, definitely, but a little tedious. 绝对不是不可能,但有点单调乏味。

A key advantage of the M2M table here is that it'll be self-maintaining if the user or any friend list is removed -- with one exception. 这里M2M表的一个关键优势是,如果用户或任何朋友列表被删除,它将自我维护 - 除了一个例外。 The idea in this scheme is that without any Visibility records, all data is private (to allow everyone to see your name, you'd add a Visibility record with user=(yourself), field="name", and public=True. Since a Visibility record where public=False, friends=False, and lists=[] is pointless, I'd check for that situation after the user edits it and remove that record entirely. 这个方案中的想法是,如果没有任何可见性记录,所有数据都是私有的(为了让每个人都能看到你的名字,你要添加一个可见性记录,其中user =(你自己),field =“name”和public = True。由于一个可见性记录,其中public = False,friends = False,而lists = []是没有意义的,我会在用户编辑后检查该情况并完全删除该记录。

Another valid strategy is to have two special FriendList records: one for "public", and one for "all friends". 另一个有效的策略是拥有两个特殊的FriendList记录:一个用于“公共”,一个用于“所有朋友”。 This simplifies the Visibility model quite a bit at the expense of a little more code elsewhere. 这在很大程度上简化了可见性模型,但代之以其他地方的更多代码。

First of all, in my opinion you should go for multiple models and for making the queries faster, as already mentioned in other answers, you can use caching or select_related or prefetch_related as per your usecase. 首先,在我看来,你应该选择多个模型并使查询更快,正如其他答案中已经提到的,你可以根据你的用例使用缓存或select_related或prefetch_related。

So here is my proposed solution: 所以这是我提出的解决方案:

User model 用户模型

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)

Group(friends list) model 组(朋友列表)模型

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

Through model 通过模型

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

User Model fields mapping to integers 用户模型字段映射到整数

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

HOW DOES THIS HELPS?? 这有什么用?

  • for each of public , friends and me , you can have a field in the User model itself as already mentioned above ie public_allowed_read_fields , friends_allowed_read_fields and me_allowed_read_fields respectively. 为每个publicfriendsme ,你可以在上面本身即作为已经提到的用户模型场public_allowed_read_fieldsfriends_allowed_read_fieldsme_allowed_read_fields分别。 Each of this field will contain a list of integers mapped to the ones inside USER_FIELDS_MAPPING(explained in detail below) 每个字段都将包含一个映射到USER_FIELDS_MAPPING内部的整数列表(详见下文)

  • for friend_list_1 , you will have group named friend_list_1. 对于friend_list_1 ,您将拥有名为friend_list_1的组。 Now the point is the user wants to show or hide a specific set of fields to this friends list. 现在重点是用户想要向这个朋友列表显示或隐藏一组特定字段。 That's where the through model, GroupPrivacy comes into the play. 这就是through模型, GroupPrivacy进入游戏的地方。 Using this through model you define a M2M relation between a user and a group with some additional properties which are unique to this relation. 使用此直通模型可以定义用户与组之间的M2M关系,并具有此关系所特有的一些附加属性。 In this GroupPrivacy model you can see allowed_read_fields field, it is used to store an array of integers corresponding to the ones in the USER_FIELDS_MAPPING . 在此GroupPrivacy模型中,您可以看到allowed_read_fields字段,它用于存储与USER_FIELDS_MAPPING中的整数对应的整数数组。 So lets say, for group friend_list_1 and user A , the allowed_read_fields = [1,2]. 因此,假设对于group friend_list_1和用户Aallowed_read_fields = [1,2]。 Now, if you map this to USER_FIELDS_MAPPING, you will know that user A wants to show only name and email to the friends in this list. 现在,如果您将此映射到USER_FIELDS_MAPPING,您将知道用户A只想显示此列表中的朋友的姓名和电子邮件。 Similarly different users in friend_list_1 group will have different values in allowed_read_fields for their corresponding GroupPrivacy model instance. 同样, friend_list_1组中的不同用户在allowed_read_fields 中将为其对应的GroupPrivacy模型实例具有不同的值。

This will be similar for multiple groups. 对于多个组,这将是类似的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM