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

Leo*_*rdo 8 django django-models django-permissions django-users django-guardian

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

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

  1. 一个卖家 " 获得 "一个客户,是指卖方现在有客户的个人信息,并可以与他/她交互.
    卖方不能与他未获得的客户互动. 在此输入图像描述

  2. 一个卖家创建模型的层次结构相关的对象(在分段每个模型与外键,其父连)
    在此输入图像描述

  3. 一个卖家 共享创建的对象及其所有相关对象与一些客户 在此输入图像描述

  4. 授权客户可以:

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

    在此输入图像描述

问题:

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

Tho*_*mas 10

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

所有用户都不是平等的.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)
Run Code Online (Sandbox Code Playgroud)

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

您可以使用a的自定义"直通"模型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") 
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

免责声明:这些是我对这个问题的看法.关于Django社区内授权的观点非常分散.永远不会有一种"最好"的方式来做任何事情,所以要仔细考虑是否需要一些非常通用的东西,能够承受数据库命中,或者你是否需要快速和特定于业务的东西,并且能够承受失去灵活性的问题.