【问题标题】:Sharing Objects with other users in Django在 Django 中与其他用户共享对象
【发布时间】:2013-07-12 19:53:24
【问题描述】:

我在 Django 中为一个相当复杂的系统建模。我将在这里只发布它的相关部分,并展示简化的用例图以更好地表达我的想法。

我基本上有两种类型的用户:卖家和客户。

  1. A Selleracquires”一个客户,这意味着卖家现在拥有 客户的个人信息,并可以与他/她互动。
    卖家不能与他没有获得的客户互动。

  2. Seller 创建相关对象的模型hierarchy(子级别中的每个模型都与其父级的外键连接)
    @987654324 @

  3. 一个 Seller 与一些 customers 共享创建的 box 对象及其所有相关对象

  4. 授权的客户可以:

    • R-读取Box模型的一些属性
    • R-ead 和 U-pdate Item 模型的一些属性
    • 无法访问 Item 模型的某些属性

问题:

  • A:在用户之间建立关系的最佳方法是什么?
    我发现django-relationship 可能很有用。
  • B:在 Django 中共享模型实例的最佳方法是什么 与其他用户?
    就我而言,默认情况下,客户 无法访问由卖家创建的任何模型(如果未明确共享)。
  • C:如果我只共享 Box 模型,是否意味着它的所有相关模型(Box 模型的外键)也将被共享?
  • D:控制字段级别权限的最佳方法是什么 每个用户?
    django-guardian 在这里有用吗?

【问题讨论】:

    标签: django django-models django-users django-permissions django-guardian


    【解决方案1】:

    答:在用户之间建立关系的最佳方法是什么?

    并非所有用户生来都是平等的。 django-relationship 在任意用户之间创建任意关系,这可能不是您想要的。您真正想要的是将这种关系严格限制为Seller -> Customer

    # This example assumes that both customers and sellers have user table entries.
    from django.contrib.auth.models import User
    
    class Customer(User): pass
    
    class Seller(User):
        acquired_customers = ManyToManyField(Customer,
            related_name="acquired_sellers")
    
        def acquire(customer):
            " A convenience function to acquire customers "
            self.acquired_customers.add(customer.id)
    

    B:在 Django 中与其他用户共享模型实例的最佳方法是什么?

    您可以使用ManyToManyField 的自定义“直通”模型来添加要跟踪的额外信息。在这种情况下,我们添加了卖家,以及共享时的自动时间戳。这使您可以执行一些操作,例如显示与您共享的产品(按共享时间排序),以及向您发送产品的卖家名称。

    # Install mptt for heirararchical data.
    from mptt.models import MPTTModel
    
    class Box(MPTTModel):
        " Nestable boxen for your Items "
        owner       = ForeignKey(Seller)
        title       = CharField(max_length=255)
        shared_with = ManyToManyField(Customer,
            related_name='boxes_sharedwithme', through=SharedBox)
    
    class Item(Model):
        " A shareable Item "
        box         = ForeignKey(Box)
        title       = CharField(max_length=255)
    
    class SharedBox(Model):
        " Keeps track of who shares what to whom, and when "
        when        = DateTimeField(auto_now_add=True)
        box         = ForeignKey(Box)
        seller      = ForeignKey(Seller)
        customer    = ForeignKey(Customer)
    
    #----------------------------
    
    # share an Item with a Customer
    def share_item(request, box_id, customer_id, **kwargs):
        # This will fail if the user is not a seller
        seller   = request.user.seller
        # This will fail if the seller is not the owner of the item's box
        box      = Box.objects.get(
            id=box_id, owner=seller)
        # This will fail if the seller has not acquired the customer
        customer = Customer.objects.get(
            id=customer_id, acquired_sellers=seller)
        # This will share the item if it has not already been shared.
        SharedBox.objects.create_or_update(
            box=box, seller=seller, customer=customer)
        return HttpResponse("OK") 
    

    C:如果我只共享 Box 模型,是否意味着它的所有相关模型(#Foreign 模型的 Box 模型)也将被共享?

    隐式权限是“业务逻辑”,这意味着您可能需要自己实现它。幸运的是,Django 的权限系统是可插入的,因此您可以添加自己的规则来递归层次结构以检查权限。或者,您可以创建自定义管理器,将适当的规则添加到使用的查询中。

    from django.db.models import Manager
    from django.db.models.query import EmptyQuerySet
    
    class ItemManager(Manager):
    
        def visible(user):
            iqs = self.get_query_set()
            oqs = EmptyQuerySet()
            # add all the items a user can see as a seller
            try: oqs |= iqs.filter(box__owner=user.seller)
            except Seller.DoesNotExist: pass
            # add all the items a user can see as a customer
            try: oqs |= iqs.filter(box__shared_with=user.customer)
            except Customer.DoesNotExist: pass
            # return the complete list of items.
            return oqs
    
    class Item(Model): objects = ItemManager()
    
    class ItemListView(ListView):
        model = Item
    
        def get_queryset(request):
            return self.model.objects.visible(request.user)
    

    D:控制每个用户的字段级别权限的最佳方法是什么?

    如果这需要超级粒度或每个用户,那么 django-guardian 是要走的路。如果权限是基于规则的,那么您最好使用一个简单的字段,以降低数据库查询的复杂性。

    class Property(Model):
        title = CharField(max_length=255)
        units = CharField(max_length=10,
            choices=UNIT_TYPES, null=True, blank=True)
    
    # -- A simple field that toggles properties for all users
    
    class ItemProperty(Model):
        item     = ForeignKey(Item)
        property = ForeignKey(Property)
        value    = CharField(max_length=100)
        customer_viewable = BooleanField(default=False)
        customer_editable = BooleanField(default=False)
    
    # -- A simple field that defines user classes who can view/edit
    
    from django.contrib.auth.models import Group
    
    class ItemProperty(Model):
        item     = ForeignKey(Item)
        property = ForeignKey(Property)
        value    = CharField(max_length=100)
        viewable_by = ForeignKey(Group)
        editable_by = ForeignKey(Group)
    

    免责声明:这些是我对这个主题的看法。 Django 社区中关于授权的观点非常分散。永远不会有一种“最佳”方式来做任何事情,因此请仔细考虑您是否需要真正通用的东西并且能够承受数据库命中,或者您是否需要快速和特定于业务的东西并且能够承受失去灵活性的代价。

    【讨论】:

    • 谢谢,非常有见地的回答!关于问题 D,我想知道:如果我没有在模板中公开对象的某些属性(比如说一个项目),并且我没有在客户可以访问的任何表单中包含这些属性,这基本上意味着客户将永远无法访问这些属性,对吗?所以这将是我不应该关心的事情。我猜。
    • 只要这些属性没有对应的可猜测的 url,并且该视图不检查权限,那么不,您不必担心。
    猜你喜欢
    • 1970-01-01
    • 2013-08-25
    • 2018-07-13
    • 2020-09-26
    • 2017-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多