2010-09-09 32 views
13

nềnThêm quyền cho mỗi đối tượng để django quản trị

Tôi đang phát triển một ứng dụng django cho một trang web cho thuê nghỉ. Nó sẽ có hai loại người dùng, người thuê và người quản lý tài sản.

Tôi muốn người quản lý tài sản có thể quản lý tài sản cho thuê của họ trong quản trị viên django. Tuy nhiên, họ chỉ có thể quản lý tài sản của riêng họ.

Tôi nhận ra quản trị viên django mặc định không hỗ trợ tính năng này. Tôi tự hỏi có bao nhiêu rắc rối nó sẽ được thêm chức năng này, và, nếu nó khả thi, cách tốt nhất để xử lý nó là gì.


Goal

Lý tưởng nhất, tôi hình dung nó làm việc như thế này:

auth đã cho phép điều khoản như thế này:

 
vacation | rental | Can add rental 
vacation | rental | Can change rental 
vacation | rental | Can delete rental 

Tôi muốn thay đổi điều này để một cái gì đó như:

 
vacation | rental | Can add any rental 
vacation | rental | Can change any rental 
vacation | rental | Can delete any rental 
vacation | rental | Can add own rental 
vacation | rental | Can change own rental 
vacation | rental | Can delete own rental 

giải pháp có thể

Làm thế nào khuôn khổ sẽ quyết định nếu thuê (hoặc bất kỳ) thuộc về người sử dụng? Tôi nghĩ rằng nó kiểm tra lớp vacation.Rental để xem nó có một ForeignKey đến auth.User (có thể có một số tên cụ thể, như 'chủ sở hữu').

  • On tạo mới vacation.Rental, giá trị của lĩnh vực ForeignKey sẽ buộc phải id của người dùng hiện hành. Trường ForeignKey sẽ không được hiển thị trên biểu mẫu.

  • Cho thuê danh sách, chỉ cho thuê với số ForeignKey khớp với người dùng hiện tại sẽ được hiển thị.

  • Khi thay đổi video cho thuê, chỉ cho thuê với số ForeignKey khớp với người dùng hiện tại mới được hiển thị. Trường ForeignKey sẽ không được hiển thị trên biểu mẫu.

Tất nhiên, điều này sẽ có thể làm việc cho bất kỳ mô hình có một trường thích hợp ForeignKey, không chỉ là mô hình vacation.Rental của chúng tôi.

Tính năng này có khả thi hay không, hoặc tôi có nên đi theo một hướng khác không?


biến chứng

Bây giờ, đây là một phần khó khăn; Tôi không chắc chắn làm thế nào để xử lý này. Giả sử Rental có thể có nhiều "Hình ảnh thuê". RentalPhotoForeignKey đến Rental.Người dùng có thể thêm ảnh vào video cho thuê của riêng mình. Tuy nhiên, ảnh không có người dùng ForeignKey, vì vậy không có cách nào để trực tiếp tìm ra người sở hữu ảnh.

Điều này có thể được giải quyết bằng một số thủ thuật trong khuôn khổ, sau ForeignKey s cho đến khi một đối tượng được tìm thấy với một số ForeignKey cho người dùng không? Hoặc tôi có nên thực hiện một cách dễ dàng và cung cấp cho RentalPhoto (và mọi thứ khác 'thuộc' để Rental) riêng của mình ForeignKey đến auth.User thích hợp không? Cách tiếp cận thứ hai sẽ yêu cầu dự phòng không cần thiết, đầu tiên có thể yêu cầu phí xử lý không cần thiết ...

Nếu tôi hoàn toàn lạc lối xin đừng ngần ngại chỉ cho tôi đi đúng hướng. Cảm ơn trước sự giúp đỡ nào.

Trả lời

22

Tôi chỉ cần thêm phương thức vào từng mô hình is_owned_by(user) và tối đa mô hình để quyết định xem nó có thuộc sở hữu của người dùng đó hay không. Trong hầu hết trường hợp, is_owned_by có thể là một chức năng chung trong một lớp mô hình cơ sở và bạn có thể tinh chỉnh nó trong các trường hợp đặc biệt. ví dụ.

class RentalPhoto(BaseModel): 
    def is_owned_by(self, user): 
     return self.rental.is_owned_by(user) 

Điều này là đủ chung và rõ ràng bạn sẽ có toàn quyền kiểm soát mọi thứ hoạt động như thế nào.

Để thêm quyền mới, bạn có thể thêm quyền đó vào mô hình của mình, ví dụ:

class Rental(models.Model): 
    # ... 
    class Meta: 
     permissions = (
      ("can_edit_any", "Can edit any rentals"), 
     ) 

Tôi nghĩ thay vì thêm hai phép anyown, bạn nên thêm chỉ own phép, vì vậy mỗi đối tượng đã có can_edit mà bạn có thể coi như người dùng có thể chỉnh sửa chỉ đối tượng của mình, và nếu người dùng có quyền can_edit_any chỉ có anh ta mới được phép chỉnh sửa tất cả

Sử dụng điều này, chúng tôi có thể mở rộng auth bằng cách thêm một chương trình phụ trợ tùy chỉnh

class PerObjectBackend(ModelBackend): 

    def has_perm(self, user_obj, perm, obj=None): 
     allowed = ModelBackend.has_perm(self, user_obj, perm) 
     if perm.find('any') >=0 : 
      return allowed 

     if perm.find('edit') >=0 or perm.find('delete') >=0: 
      if obj is None: 
       raise Exception("Perm '%s' needs an object"%perm) 
      if not obj.is_owned_by(user_obj): 
       return False 

     return allowed 

Đây là một triển khai rất nhanh, trên thực tế bạn có thể mở rộng các đối tượng quyền để kiểm tra xem nó có cần và đối tượng hay không, ví dụ: permission.is_per_object thay vì thực hiện tìm kiếm chuỗi thô nhưng cũng nên hoạt động nếu bạn có tên chuẩn

+0

Cảm ơn, Anurag; nó không phải là chung chung như tôi muốn nhưng tôi sẽ xem xét nó. Làm thế nào tôi có thể buộc điều này vào 'auth' để các quyền mới của tôi hiển thị trong danh sách? –

+0

@no xem chỉnh sửa. –

1

này có thể được giải quyết bằng một số thủ đoạn gian trá trong khuôn khổ, ForeignKeys sau cho đến khi một đối tượng được tìm thấy với một ForeignKey để sử dụng?

Tôi không thấy nơi có thủ đoạn gian trá necessairy: RentalPhoto -> Thuê -> User Vì vậy, để có được những người dùng cho một RentalPhoto cụ thể bạn sẽ gọi một cái gì đó như thế này trong các trường hợp:

photo.rental.user 

Theo dõi nhiều mối quan hệ trong một bước có thể được coi là không gian lận.

+0

Điều đó sẽ làm việc đối với trường hợp đặc biệt này, nhưng tôi muốn làm điều đó trong một cách chung chung - "Dĩ nhiên, điều này sẽ có thể làm việc cho bất kỳ mô hình có trường 'ForeignKey' thích hợp, không chỉ là mô hình' vacation.Rental' [và related] của chúng ta. " –

+0

Có giống như dozends các cách có thể được chung chung hơn. Ví dụ. có một model.Ownable xác định chủ sở hữu trường và mở rộng nó trong các Mô hình có thể sở hữu. –

+0

Câu trả lời này không hữu ích lắm. Nó để lại hầu hết các câu hỏi chưa được trả lời. Có lẽ tôi đã làm một công việc xấu để giải thích câu hỏi? –

1

Nếu bạn không muốn triển khai Chương trình quyền riêng tư của mình, tôi khuyên bạn nên sử dụng https://github.com/chrisglass/django-rulez Bạn sẽ làm những gì bạn muốn đường.

0

Đó là trong Django docs.

Về cơ bản bạn tạo lớp quản trị tùy chỉnh cho mô hình của mình và xác định phương thức get_queryset. Trong trường hợp của bạn nó có thể là một cái gì đó như dưới đây.Siêu người dùng sẽ thấy tất cả dịch vụ cho thuê, trong khi chủ sở hữu chỉ có mình.

class RentalAdmin(admin.ModelAdmin): 
    def get_queryset(self, request): 
     qs = super(RentalAdmin, self).get_queryset(request) 
     if request.user.is_superuser: 
      return qs 
     return qs.filter(owner=request.user) 

Đây là một khả năng dẫn: https://code.djangoproject.com/wiki/RowLevelPermissions

Các vấn đề liên quan