10

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

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

  1. 卖家获得”了一个客户这意味着卖家现在拥有了客户的个人信息,并且可以与他/她进行互动。
    卖家不能与他没有获得的客户互动。 在此处输入图像描述

  2. 卖方创建相关对象的模型层次结构(子级别中的每个模型都通过外键连接到其父级)
    在此处输入图像描述

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

  4. 授权客户可以:

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

    在此处输入图像描述

问题:

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

1 回答 1

16

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

并非所有用户生来都是平等的。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 中与其他用户共享模型实例的最佳方法是什么?

您可以使用 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") 

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 社区中关于授权的观点非常分散。永远不会有一种“最佳”方式来做任何事情,因此请仔细考虑您是否需要真正通用的东西并且能够承受数据库命中,或者您是否需要快速和特定于业务的东西并且能够承受灵活性的损失。

于 2013-07-15T09:21:36.033 回答