Sharing objects with other users in Django

I am modeling a rather complex system in Django. I will publish here only the corresponding part, and I will show simplified diagrams of use cases in order to better express my ideas.

I basically have 2 types of users: Seller and Client.

  • The seller “ acquires ” the Client, which means that the seller now has the client’s personal information and can interact with him / her.
    The seller cannot interact with a customer that he has not acquired. enter image description here

  • The seller creates a model of the hierarchy of related objects (each model on the sublevel is associated with a foreign key with its parent)
    enter image description here

  • The seller shares the created box object and all related objects with some customers enter image description here

  • Authorized customers can:

    • R - Find Some Box Model Attributes
    • R- id and U -sign some attributes of the model Element
    • Unable to access some attributes of the model. Element

    enter image description here

Questions:

  • A. What is the best approach for creating user relationships ?
    I saw that django-relationship can be useful.
  • B. What is the best approach for sharing model instances in Django with other users?
    In my case, by default, the Client cannot access any model created by the Seller if it is not clearly separated.
  • C. If I only share the Box model, does this mean that all related models (foreign keys for the Box model) will also be shared?
  • D What is the best level management approach . per user?
    Can a django-guardian be useful here?
+4
source share
1 answer

A: What is the best approach for creating user relationships?

All users are not created equal. django-relationship creates arbitrary relationships between arbitrary users, which is most likely not what you want. Are you sure you want to limit this relationship strictly 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) 

Q: What is the best approach for sharing model instances in Django with other users?

You can use the ManyToManyField custom “ ManyToManyField -through” model to add additional information that you want to track. In this case, we add a seller and an automatic timestamp when it was provided. This allows you to do things such as displaying products that you have shared, sorted by their sharing along with the name of the seller who sent it to you.

 # 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 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: If I only share the Box model, does it implicitly mean that all related models (#Foreign keys to Box model) will also be shared?

Implicit permissions are “business logic,” which means you will most likely have to implement it yourself. Fortunately, Django's permission system is plugged in, so you can add your own rules that return a hierarchy to check permissions. Or you can create custom managers who add the appropriate rules to the request wherever they are used.

 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: What is the best approach for managing field level resolution for each user?

If this should be super-granular or for every user, then django-guardian is the way to go. If permissions are rule-based, then you might be better off with a simple field to reduce the complexity of database queries.

 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) 

Disclaimer: This is my opinion on this. The views on authorization in the Django community are highly fragmented. There will never be a single “better” way to do something, so think carefully whether you need something really common and can afford to get into the database, or you need something fast and business-specific and can afford loss of flexibility.

+6
source

Source: https://habr.com/ru/post/1491354/


All Articles