在Django中与其他用户共享对象

时间:2013-07-15 02:33:24

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

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

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

  1. 卖方获取客户,这意味着卖家现在拥有 客户的个人信息,可以与他/她互动 卖家无法与他未获得的客户进行互动。 enter image description here

  2. 卖方创建相关对象的模型层次结构(子级中的每个模型都与其父级的外键相关联)
    enter image description here

  3. 卖方 分享创建的对象及其所有与客户相关的对象 enter image description here

  4. 授权客户可以:

    • R - 了解 Box 模型的一些属性
    • R -ead和 U - 更新模型的一些属性
    • 无法访问模型的某些属性

    enter image description here

  5. 问题:

    • A :在用户之间创建关系的最佳方法是什么?
      我已经看到django-relationship可能有用了。
    • B :Django中分享模型实例的最佳方法是什么? 与其他用户?
      在我的情况下,默认情况下,客户 无法访问 Seller 创建的任何模型(如果未明确共享)。
    • C :如果我只共享 Box 模型,它是否隐含意味着还将共享其所有相关模型(Box模型的外键)?
    • D :控制字段级别权限的最佳方法是什么? 每个用户?
      django-guardian可以在这里使用吗?

1 个答案:

答案 0 :(得分:9)

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

所有用户都不是平等的。 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模型,它是否隐含意味着它的所有相关模型(Box模型的#Foreign键)都将被共享?

隐式权限是“业务逻辑”,这意味着您可能需要自己实现它。幸运的是,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社区内授权的观点非常分散。永远不会有一种“最好”的方式来做任何事情,所以要仔细考虑你是否需要一些非常通用的东西,能够承受数据库命中,或者你是否需要快速和安全的东西。特定于业务,可以承受失去灵活性。