SoFunction
Updated on 2024-10-29

Xadmin+rules to implement multi-selected row permission method (cascading effect)

Row Permission Configuration

configured in xadmin and does not require database support.

Install and configure rules

pip install.

pip install rules

configure

# 
INSTALLED_APPS = (
  # ...
  'rules',
)
AUTHENTICATION_BACKENDS = (
  '',
  '',
)

configure

# 
class CompanyUser():
  users = (User, verbose_name='Username', on_delete=User)
  is_admin = ('Whether operational staff', default=False)
  category_code = (user, verbose_name='Manageable', max_length=20, blank=True, default='')
  #ForeignKey is single-select, ManyToManyField is multi-select.

  def __str__(self):
    return str()

  class Meta:
    verbose_name = 'Manage Accounts'
    verbose_name_plural = verbose_name
    
    
    
class user():
  title = (max_length=50, verbose_name="Title of Article")
  author = (max_length=50, null=True, blank=True, verbose_name='Author of the article')
  #category = (Category, verbose_name="Category to which it belongs", null=True, blank=True, on_delete=Category)(Enabled for multiple selection)
  content = UEditorField(verbose_name="Article Content", imagePath='static/img/', filePath="static/img/", upload_settings={"imageMaxSize": 1204000}, default='')
  click_num = (default=0, verbose_name="Views", )
  image = (max_length=200, verbose_name="Article image.", null=True, blank=True, upload_to='static/img', default=None)
  add_time = (default=, verbose_name="Add time")

  def __str__(self):
    return 

  class Meta:
    verbose_name = 'Article Information'
    verbose_name_plural = verbose_name

Using rules

Add a new sibling directory to mods to configure object permissions related to that app

# 
# The following must be added to the top of the file, otherwise you will get an import error when trying to import django-rules itself.
from __future__ import absolute_import 

import rules

# Use modifier @custompredicates (judgment) to return True for privileges, False for no privileges

@
def is_colleague(user, entry):
  if not entry or not hasattr(user, 'companyuser'):
    return False
  return entry.category_code == .category_code


@
def is_admin(user):
  if not hasattr(user, 'companyuser'):
    return False
  return .is_admin


is_admins = is_admin | rules.is_superuser | is_colleague

# Setting up Rules

rules.add_rule('can_view_user', is_admins)
rules.add_rule('can_delete_user', is_admins)
rules.add_perm('can_change_user', is_admins)

# Setting Permissions

rules.add_perm('data_import.view_user', is_admins)
rules.add_perm('data_import.delete_user', is_admins)
rules.add_perm('data_import.add_user', is_admins)
rules.add_perm('data_import.change_user', is_admins)

set up

The rules file must be referenced for the permission rules to take effect, for xadmin, just add from .rules import *.

# 
from __future__ import absolute_import
import xadmin
from xadmin import views
from  import *
from .rules import *


class UserAdmin(object):
  list_display = 'title',
  search_fields = 'title', 'content',
  list_filter = 'category',
  readonly_fields = 'click_num',
  exclude = 'add_time',
  style_fields = {"content": "ueditor"}
  
  def queryset(self):
    qs = super(UserAdmin, self).queryset()
    if .is_superuser or is_admin():
      return qs
    try:
      print('-------------------')
      print(qs)#Print the results of the qs
      print('-------------------')
      print((users=).category_code.filter())
      # Print manageable content for login accounts
      print('-------------------')
      return (users=).category_code.filter()
    except AttributeError:
      return None
      
      
class CompanyUserAdmin(object):
  pass
      
(CompanyUser, CompanyUserAdmin)
(user, UserAdmin)

The effect is demonstrated:

You need to add manageable content to your account in the admin account first.

It's done.

Configuration of row permissions (multiple choice)

To achieve the effect of cascading multiple selection you need to modify the original base and add \ and js can be realized

Create a new category model (compare to the model above), and add the category field in the existing CompanyUser.

# 
class CompanyUser():
  users = (User, verbose_name='Username', on_delete=User)
  is_admin = ('Whether operational staff', default=False)
  category = (Category, on_delete=Category, verbose_name='Manageable Categories', max_length=20, null=True, blank=True, default='')
  category_code = (user, verbose_name='Manageable articles', max_length=20, null=True, blank=True, default='')
  #ForeignKey is single-select, ManyToManyField is multi-select.

  def __str__(self):
    return str()

  class Meta:
    verbose_name = 'Manage Accounts'
    verbose_name_plural = verbose_name
    
class Category():
  name = (max_length=20, verbose_name="Article Categories")
  add_time = (default=, verbose_name="Add time")

  def __str__(self):
    return 

  class Meta:
    verbose_name = "Category information"
    verbose_name_plural = verbose_name

F12 to find the IDs in the SELECT for the primary and secondary directories

My primary catalog id=id_category,secondary catalog id=id_category_code

Here's how to start creating a new js file

and replace the id in the js file

#Name whatever. Mine is.
# 
$('#id_category').change(function () {
  var module = $('#id_category').find('option:selected').val(); //get the parent selected value
  $('#id_category_code')[0]. ();// Empty the child level
  if (module)
    $.ajax({
      type: 'get',
      url: '/select/one_two/?module=' + module,
      data: '',
      async: true,
      beforeSend: function (xhr, settings) {
        ('X-CSRFToken', '{{ csrf_token }}')
      },
      success: function (data) {
        data = ()//convert JSON
        (data);
        for (var i = 0; i < ; i++) {

          var test = {text: data[i]., value: data[i].pk, $order: i + 1}; // Iterate over the data and piece together the format needed for selectize.
          $('#id_category_code')[0]. (test); //add data
        }
      },
    })
  else {
    # Iterate through all subdirectories if first level directory is assigned Optional
    $.ajax({
      type: 'get',
      url: '/select/one_two/?module=all',
      data: '',
      async: true,
      beforeSend: function (xhr, settings) {
        ('X-CSRFToken', '{{ csrf_token }}')
      },
      success: function (data) {
        data = ()//convert JSON
        (data);
        for (var i = 0; i < ; i++) {

          var test = {text: data[i]., value: data[i].pk, $order: i + 1}; // Iterate over the data and piece together the format needed for selectize.
          $('#id_category_code')[0]. (test); //add data
        }
      },
    })
  }
})

Replace 'title' in this line in the js with the name of the database field you want to display There are two (20 lines | 40 lines)

var test = {text: data[i]. , value: data[i].pk, $order: i + 1}; // Iterate over the data and piece together the format needed to selectize it.

Put the written js file into xadmin\static\xadmin\js, as shown in the figure.

Find xadmin\, add the js into it (this is the search class of xadmin)

Adding Views

# Import serializers
from  import serializers
from  import LoginRequiredMixin
from  import View
# Secondary Linkage View Functions
class SelectView(LoginRequiredMixin, View):
  def get(self, request):
    # Get the parent selection via get
    id_category = ('module', '')
    # Filter out all children that meet the requirements of the parent, since the output is a collection, the data needs to be serialized ()
    if id_category == 'all':
      id_category_code = ("json", ())s
      # Query via Ajax request
    else:
      id_category_code = ("json", (category=int(id_category)))
    # Determine if it exists, output
    if id_category_code:
      return JsonResponse({'data': id_category_code})

from import SelectView
url(r'^select/one_two/', SelectView.as_view(), name='one_two'),

Effect.

Operation method as above

Done!

Above this Xadmin + rules to achieve multi-selected rows of permissions way (cascade effect) is all I have to share with you, I hope to be able to give you a reference, but also hope that you support me more.