Совместное использование объектов с другими пользователями в Django

Я моделирую довольно сложную систему в Django. Я опубликую здесь только соответствующую часть и покажу упрощенные диаграммы вариантов использования, чтобы лучше выразить свои идеи.

У меня в основном есть 2 типа пользователей: продавец и покупатель.

  1. Продавец "приобретает" Покупателя, что означает, что продавец теперь имеет личную информацию покупателя и может взаимодействовать с ним/ней.
    Продавец не может взаимодействовать с покупателем, которого он не привлекал. введите здесь описание изображения

  2. Продавец создает модель иерархию связанных объектов (каждая модель на подуровне связана внешним ключом со своим родителем)
    введите здесь описание изображения

  3. Продавец делится созданным объектом box и всеми связанными с ним объектами с некоторыми покупателями введите здесь описание изображения

  4. Авторизованные клиенты могут:

    • R-ead some attributes of the Box model
    • R-ead и U-pdate для некоторых атрибутов модели Item
    • Не удается получить доступ к некоторым атрибутам модели Item

    введите здесь описание изображения

Вопросы:

  • О. Каков наилучший подход к созданию отношений между пользователями?
    Я видел, что django-relationship может оказаться полезным.
  • B: как лучше всего поделиться экземплярами модели в Django с другими пользователями?
    В моем случае по умолчанию Customer < strong>не может получить доступ к какой-либо модели, созданной Продавцом, если она не предоставлена ​​явным образом.
  • C: Если я использую только модель Box, означает ли это неявно, что также будут использоваться все связанные с ней модели (внешние ключи к модели Box)?
  • D: каков наилучший подход к управлению полем на уровне разрешений для каждого пользователя?
    Может django-guardian быть здесь полезным?

person Leonardo    schedule 15.07.2013    source источник


Ответы (1)


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 с другими пользователями?

Вы можете использовать пользовательскую сквозную модель 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 сильно фрагментированы. Никогда не будет одного «лучшего» способа сделать что-либо, поэтому тщательно подумайте, нужно ли вам что-то действительно универсальное и можете позволить себе обращения к базе данных, или вам нужно что-то быстрое и специфичное для бизнеса и вы можете позволить себе потерю гибкости.

person Thomas    schedule 15.07.2013
comment
Спасибо, очень содержательный ответ! Меня интересует вопрос D: если я не указываю в шаблоне некоторые атрибуты объекта (скажем, предмета) и если я не включаю эти атрибуты ни в одну из форм, доступных для клиентов, это в основном означает, что клиенты никогда не смогут получить доступ к этим атрибутам, я прав? Так что это было бы чем-то, что меня не должно волновать. Наверное. - person Leonardo; 15.07.2013
comment
Пока эти атрибуты не имеют соответствующего угадываемого URL-адреса, и это представление не проверяет разрешения, вам не нужно об этом беспокоиться. - person Thomas; 16.07.2013