vittoriozamboni / django-groups-manager Goto Github PK
View Code? Open in Web Editor NEWManage django groups collection based on django-mptt.
License: MIT License
Manage django groups collection based on django-mptt.
License: MIT License
Installing the groups manager 0.5.0 wth pip install does not also pull the django_helper_forms dependency resulting in following crash while adding in urls. No explicit mention in the docs to install as such as well.
url(r'^groups-manager/', include('groups_manager.urls', namespace='groups_manager')),
File "/Users/rs/projects/lipton/lib/python2.7/site-packages/groups_manager/urls.py", line 3, in
from groups_manager import views
File "/Users/rs/projects/lipton/lib/python2.7/site-packages/groups_manager/views.py", line 9, in
from groups_manager import models, forms, settings
File "/Users/rs/projects/lipton/lib/python2.7/site-packages/groups_manager/forms.py", line 3, in
from django_helper_forms.forms import DictionaryFieldsForm
ImportError: No module named django_helper_forms.forms
Hello, I'm trying to build a test that checks permissions and memberships as I'm still trying to understand how I will use this permissions. I have custom Member and Group (app core
):
class Usuario(Member):
...
class Meta:
verbose_name = "Usuario"
verbose_name_plural = "Usuarios"
class Organizacion(Group):
....
class Meta:
verbose_name = "Organizacion"
verbose_name_plural = "Organizaciones"
class GroupsModelMeta:
model_name = 'core.Usuario'
And the (simplified) test is:
# Prep
org = Organizacion.objects.create(name="org")
org_child = Organizacion.objects.create(name="org_child", parent=org)
org_grand_child = Organizacion.objects.create(name="org_grand_child", parent=org_child)
user1 = Usuarios.objects.create(username="user1")
org.add_member(user1)
user2 = Usuarios.objects.create(username="user2")
org_child.add_member(user2)
user3 = Usuarios.objects.create(username="user3")
org_grand_child.add_member(user3)
# Test Membership
self.assertTrue(user_1 in org.members)
self.assertTrue(user_2 in org_child.members)
self.assertTrue(user_2 in org.members)
self.assertTrue(user_3 in org_grand_child.members)
self.assertTrue(user_3 in org_child.members)
self.assertTrue(user_3 in org.members)
All asserts fails here as members are instances of Member
and not Usuario
. If I use this instead:
class Organizacion(Group):
....
class Meta:
verbose_name = "Organizacion"
verbose_name_plural = "Organizaciones"
class GroupsManagerMeta:
member_model = "core.Usuario"
users are of instance Usuario
in the main Organizacion
but not in it's children.
Any ideas?
Thank you!
can u preview or tell step by step when to use standard templates, from groups_manager’s urls?
i already run it, but i still confuse to use it...
I already change it to be working for django 1.9.
.... working (change to bootstrap 3.3.7)
Hi, I'm still integrating this lib and have some questions.
I'm trying to model a hierarchical organization. I have Organization extending from Group and User extending from Member. I want to create Users that have permissions over the sub organization of which they are members.
After creating the user I'm using add_member
to add the User to the Org and assign_object
to assign the Org object to the Org group.
Running some tests I see that permissions are correct over the Organization objects, but the Users have no permissions over the models. This is causing for example that a user has no permissions for Django admin.
Do I have to add these permissions manually, or I'm using this the wrong way?
Thank you for your patience!
Hello, I believe I have issues understanding how the permissions manager is suposed to work.
I can see how the downstream and upstream priviledges are granted. But I cannot figure out how to revoke them properly.
Here a test I tried:
# Create company structure
companyA = Group.objects.create(name="CompanyA")
division1 = Group.objects.create(name="Division1", parent=companyA)
division2 = Group.objects.create(name="Division2", parent=companyA)
# Create user and and assign to division
member_div_1 = Member.objects.create(username="memberDiv1", first_name="MemberDiv1")
division1.add_member(member_div_1)
# Creating Mock Document
document = MyDocumentModel.objects.create(title="TestDocument")
# Assign permissions
custom_permissions = {
'groups_downstream': ['view', 'change'],
}
companyA.assign_object(document, custom_permissions=custom_permissions)
member_div_1.has_perm("view_document", document)
# This returns True
member_div_1.has_perm("change_document", document)
# This returns True
Until here everything works as expected but if I want to modify the permissions on the document for companyA and remove the change option:
# Modify permissions
custom_permissions = {
'group' : [],
'groups_downstream': ['view',],
}
companyA.assign_object(document, custom_permissions=custom_permissions)
member_div_1.has_perm("view_document", document)
# This returns True
member_div_1.has_perm("change_document", document)
# This returns True -> In this test this was expected to return False
I think I don't fully understand how to revoke privileges using this manager.
I haven't found any documentation on revoking/modifying permissions and I haven't seen other users requesting this feature, which means I am probably doing/understading something wrong.
Could you point me in the direction to achieve this?
Thank you in advance!
Fran
The moment I add groups_manger to INSTALLED_APPS, I get this exception. I think we can simply use JSONField which is now natively supported in Django which is now supported by both postgres as well as MySQL.
Hi @OskarPersson , @vittoriozamboni ,
is possible create a general groups for moderate/handle the group like Tohir is "leader", like this example:
from groups_manager.models import Group, Member
fc_internazionale = Group.objects.create(name='F.C. Internazionale Milan')
staff = Group.objects.create(name='Staff', parent=fc_internazionale)
players = Group.objects.create(name='Players', parent=fc_internazionale)
thohir = Member.objects.create(first_name='Eric', last_name='Thohir')
staff.add_member(thohir)
palacio = Member.objects.create(first_name='Rodrigo', last_name='Palacio')
players.add_member(palacio)
I need a general group staff for each "football club" who can handle only for specific "football club"
Thanks for support!
Sorry for my bad english
The github release has this file, but the pypi release does not have it. This causes trouble when deploying the package when the groups_manager.css
is processed.
I am trying to use this app with a Django deployment under Docker compose (DB + web app).
After installing the app I get this error message
RuntimeError: Model class guardian.models.UserObjectPermission doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
The app is installed and listed in INSTALLED_APPS, what am I missing?
thank you!
Claudio
Hey guys, I tried to use the groups-manager url and got the following exception.
Template loader postmortem
Django tried loading these templates, in this order:
Using engine django:
* django.template.loaders.filesystem.Loader: /code/vitapio/static/base.html (Source does not exist)
* django.template.loaders.app_directories.Loader: /usr/local/lib/python3.6/site-packages/django/contrib/admin/templates/base.html (Source does not exist)
* django.template.loaders.app_directories.Loader: /usr/local/lib/python3.6/site-packages/django/contrib/auth/templates/base.html (Source does not exist)
* django.template.loaders.app_directories.Loader: /usr/local/lib/python3.6/site-packages/rest_framework/templates/base.html (Source does not exist)
* django.template.loaders.app_directories.Loader: /usr/local/lib/python3.6/site-packages/django_filters/templates/base.html (Source does not exist)
* django.template.loaders.app_directories.Loader: /usr/local/lib/python3.6/site-packages/drf_yasg/templates/base.html (Source does not exist)
* django.template.loaders.app_directories.Loader: /usr/local/lib/python3.6/site-packages/guardian/templates/base.html (Source does not exist)
* django.template.loaders.app_directories.Loader: /usr/local/lib/python3.6/site-packages/groups_manager/templates/base.html (Source does not exist)
* django.template.loaders.app_directories.Loader: /usr/local/lib/python3.6/site-packages/bootstrap3/templates/base.html (Source does not exist)
Template error:
In template /usr/local/lib/python3.6/site-packages/groups_manager/templates/groups_manager/bootstrap3/groups_manager.html, error at line 1
base.html
1 : {% extends "base.html" %}
2 :
3 :
4 : {% block breadcrumbs %}
5 : {{ block.super }}
6 : <li>
7 : <a href="{% url 'groups_manager:groups_manager' %}">Groups Manager</a>
8 : </li>
9 : {% endblock breadcrumbs %}
10 :
11 :
Traceback:
File "/usr/local/lib/python3.6/site-packages/django/template/backends/django.py" in render
61. return self.template.render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in render
171. return self._render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in _render
163. return self.nodelist.render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in render
937. bit = node.render_annotated(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in render_annotated
904. return self.render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py" in render
150. return compiled_parent._render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in _render
163. return self.nodelist.render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in render
937. bit = node.render_annotated(context)
File "/usr/local/lib/python3.6/site-packages/django/template/base.py" in render_annotated
904. return self.render(context)
File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py" in render
127. compiled_parent = self.get_parent(context)
File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py" in get_parent
124. return self.find_template(parent, context)
File "/usr/local/lib/python3.6/site-packages/django/template/loader_tags.py" in find_template
104. template_name, skip=history,
File "/usr/local/lib/python3.6/site-packages/django/template/engine.py" in find_template
130. raise TemplateDoesNotExist(name, tried=tried)
The above exception (base.html) was the direct cause of the following exception:
File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
34. response = get_response(request)
File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
156. response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
154. response = response.render()
File "/usr/local/lib/python3.6/site-packages/django/template/response.py" in render
106. self.content = self.rendered_content
File "/usr/local/lib/python3.6/site-packages/django/template/response.py" in rendered_content
83. content = template.render(context, self._request)
File "/usr/local/lib/python3.6/site-packages/django/template/backends/django.py" in render
63. reraise(exc, self.backend)
File "/usr/local/lib/python3.6/site-packages/django/template/backends/django.py" in reraise
84. raise new from exc
Exception Type: TemplateDoesNotExist at /api/v1/groups-manager/
Exception Value: base.html
Note: I am using a custom user model in Django and not a default user model (replaced username with email)
def create_member(sender, instance,created, **kwargs):
if created:
if not instance.is_staff:
try:
Member.objects.create(first_name=instance.first_name, last_name=instance.last_name, django_user_id=instance.id)
except:
pass
post_save.connect(create_member,sender=User)
This creates an instance of Member when an instance of CustomUser is created, but Under customuser the users email disappears.
If I remove "django_user_id=instance.id" everything is normal but, django_user is unassigned as expected.
How can I create an instance of member class ?
My application has a customized User
class derived from AbstractUser
. Instead of defining separate Member
class and sync
or one to one
to User
, I am wondering if it is more straightforward to do
class User(AbstractUser, MemberMixin)
so that every user would automatically be a Member
.
I understand MemberMixin
has some conflicting fields with AbstractUser
, so I was basically asking if it is ok to copy the code for MemberMixin
into class User
, and do something like
class User(AbstractUser, MemberRelationsMixin):
class GroupsManagerMeta:
group_model = 'organization.OrganizationGroups'
group_member_model = 'users.User'
Hi,
I added the ImageField for class GroupMixin(GroupRelationsMixin, MPTTModel):
But doesn't work the makemigrations and migrate commands.
This is my fields:
no_picture = django_settings.MEDIA_URL +'/group_pictures/avatar-team.jpg'
no_cover = django_settings.MEDIA_URL +'/group_covers/covers.jpg'
url_back = 'group_covers/'
url_photo = 'group_pictures/'
background_photo = models.ImageField(upload_to =url_back, default=no_cover, null=True, blank=True)
profile_photo = models.ImageField(upload_to=url_photo, default=no_picture, null=True, blank=True)
At least for testing. I can prepare a PR if you are interested.
I have configure the library as indicated in the documentation. But having the following error:
ModuleNotFoundError: No module named 'jsonfield'
He are my settings:
INSTALLED_APPS += (
'guardian', # installed
'groups_manager', # also installed
)
Hi.
I'm studying the module. I have some questions to understand it well.
In groups:
On the members.
When sync with the django users, when create a member create an user. But not create a password. Son i have to go to the user form and create the other information. Or only sync with existing users?
That's all for the moment
django-groups-manager
is released under a MIT license. It requires awesome-slugify
, which is released under GPLv3. Is it true that this effectively revokes the MIT license of django-groups-manager
?
I tried to use python-slugify
but to_lower
is not an acceptable option to its slugify
function and triggers an error due to
Currently this does not work with Django 4.0 as far as I could see the only problem is the usage of the deprecated alias
django.conf.urls.url
I would propose a quick fix later, however it should be discussed whether the old behaviour of using the alias is still kept for backwards compatibility or not.
I have this warning at makemigrations:
System check identified some issues:
WARNINGS:
groups_manager.Group.group_entities: (fields.W340) null has no effect on ManyToManyField.
groups_manager.GroupMember.roles: (fields.W340) null has no effect on ManyToManyField.
No changes detected
Python 3.5.2
Django 1.9.7
django-groups-manager 0.4.1
We can create fields such as username, e-mail. However, the password field is not available. When I add a member to the member add page, I want to set the password on the page. How can I do it?
forms.py
class CalisanForm(forms.ModelForm):
member = forms.CharField(max_length=100, label='Çalışan Adı')
class Meta:
model = User
fields = [
'member',
]
views.py
def calisan(request):
form = CalisanForm(request.POST or None)
if form.is_valid():
member = form.cleaned_data['member']
member = Member.objects.create(first_name=member)
return redirect('home')
return render(request, 'accounts/calisan/calisan.html', {'form': form})
I bugfixed the assign_object()
team = Group.objects.create(name=society.name, group_type=g_type, parent=society)
member = Member.objects.get(django_user=user)
team.add_member(member, roles = [GroupMemberRole.OWNER])
But when I try to modify the groups_downstream I have error:
this is example:
'PERMISSIONS': {
'owner': ['view', 'change', 'delete'],
'group': ['view', 'change'],
'groups_upstream': ['view'],
'groups_downstream': [],
'groups_siblings': ['view'],
},
this is my:
PERMISSIONS = {
#'owner': ['view', 'change', 'delete',],
'owner': {
'leader': ['change', 'delete', 'can_add_member_custom', 'can_remove_member_custom'],
'referent': ['change', 'delete', 'can_add_member_custom', 'can_remove_member_custom'],
'default': ['view', 'change', 'delete'],
},
'group': ['view', 'change',],
'groups_upstream': ['view'],
'groups_downstream': {
'leader': ['change', 'delete', 'can_add_member_custom', 'can_remove_member_custom'],
'referent': ['change', 'delete', 'can_add_member_custom', 'can_remove_member_custom' ],
#'default': ['view']
},
'groups_siblings': ['view'],
}
Is possibile have the role permission for downstream permss?
Thanks
this is error:
Permission matching query does not exist.
Hi @OskarPersson ,
I would need that when a user is associated with the staff or referent role can have the privileges of being able to modify the group, add users or remove them both for the belonging group and the children of the group.
It's possible?
from django.conf import settings
GROUPS_MANAGER_SETTINGS = getattr(settings, 'GROUPS_MANAGER', {})
SETTINGS_PERMISSIONS = GROUPS_MANAGER_SETTINGS.get('PERMISSIONS', {})
PERMISSIONS = {
#'owner': ['view', 'change', 'delete',],
'owner': {
'leader': ['change', 'delete'],
'referent': ['change', 'delete'],
'default': ['view', 'change', 'delete',],
},
'group': ['view', 'change',],
#'groups_upstream': ['view'],
#'groups_downstream': ,
'groups_upstream': {
'leader': ['change', 'delete'],
'referent': ['change', 'delete'],
'default': ['view']
},
'groups_downstream': {
'leader': ['change', 'delete'],
'referent': ['change', 'delete'],
'default': ['view']
},
'groups_siblings': ['view'],
}
PERMISSIONS.update(SETTINGS_PERMISSIONS)
GROUPS_MANAGER = {
# User and Groups sync settings
'AUTH_MODELS_SYNC': GROUPS_MANAGER_SETTINGS.get('AUTH_MODELS_SYNC', False),
'AUTH_MODELS_GET_OR_CREATE': GROUPS_MANAGER_SETTINGS.get('AUTH_MODELS_GET_OR_CREATE', True),
'GROUP_NAME_PREFIX': GROUPS_MANAGER_SETTINGS.get('GROUP_NAME_PREFIX', 'DGM_'),
'GROUP_NAME_SUFFIX': GROUPS_MANAGER_SETTINGS.get('GROUP_NAME_SUFFIX', '_$$random'),
'USER_USERNAME_PREFIX': GROUPS_MANAGER_SETTINGS.get('USER_USERNAME_PREFIX', 'DGM_'),
'USER_USERNAME_SUFFIX': GROUPS_MANAGER_SETTINGS.get('USER_USERNAME_SUFFIX', '_$$random'),
# Permissions
'PERMISSIONS': PERMISSIONS,
# Templates
'TEMPLATE_STYLE': GROUPS_MANAGER_SETTINGS.get('TEMPLATE_STYLE', 'bootstrap3')
}
My problem is how does the GROUPS_MANAGER ['PERMISSIONS'] work?
mppt used to model group hierarchies is no longer maintained. This is probably not a big problem for a while.
Switching to another tree library could be done as part of a 2.0 release.
:\Users\Emauele Di Molfetta\Desktop\ALLAN\django>python manage.py migrate
Traceback (most recent call last):
File "manage.py", line 22, in
execute_from_command_line(sys.argv)
File "C:\Users\Emauele Di Molfetta\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\core\management_init_.py", line 371, in execute_from_command_line
utility.execute()
File "C:\Users\Emauele Di Molfetta\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\core\management_init_.py", line 347, in execute
django.setup()
File "C:\Users\Emauele Di Molfetta\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django_init_.py", line 24, in setup
apps.populate(settings.INSTALLED_APPS)
File "C:\Users\Emauele Di Molfetta\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\apps\registry.py", line 112, in populate
app_config.import_models()
File "C:\Users\Emauele Di Molfetta\AppData\Local\Programs\Python\Python36-32\lib\site-packages\django\apps\config.py", line 198, in import_models
self.models_module = import_module(models_module_name)
File "C:\Users\Emauele Di Molfetta\AppData\Local\Programs\Python\Python36-32\lib\importlib_init_.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "", line 994, in _gcd_import
File "", line 971, in _find_and_load
File "", line 955, in _find_and_load_unlocked
File "", line 665, in load_unlocked
File "", line 678, in exec_module
File "", line 219, in call_with_frames_removed
File "C:\Users\Emauele Di Molfetta\AppData\Local\Programs\Python\Python36-32\lib\site-packages\groups_manager\models.py", line 295, in
class GroupMixin(GroupRelationsMixin, MPTTModel):
File "C:\Users\Emauele Di Molfetta\AppData\Local\Programs\Python\Python36-32\lib\site-packages\groups_manager\models.py", line 326, in GroupMixin
related_name='sub%(app_label)s%(class)s_set')
TypeError: init() missing 1 required positional argument: 'on_delete'
I noticed in #41, that you addressed an issue with line 33 in migration 0006 regarding the JSON field. I have an existing project that uses groups_manager version 1.0.2 that is working fine. However, I was doing a clean install from source to test deployment and during makemigrations
, I am getting the following error:
File "<frozen importlib._bootstrap>", line 1014, in _gcd_import File "<frozen importlib._bootstrap>", line 991, in _find_and_load File "<frozen importlib._bootstrap>", line 975, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 671, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 783, in exec_module File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed File "/home/smontalbano/work/tmpMartie/martie_stripped/venv/lib/python3.8/site-packages/groups_manager/migrations/0006_1_0_0_default.py", line 8, in <module> class Migration(migrations.Migration): File "/home/smontalbano/work/tmpMartie/martie_stripped/venv/lib/python3.8/site-packages/groups_manager/migrations/0006_1_0_0_default.py", line 33, in Migration field=jsonfield.fields.JSONField(blank=True, default={}, load_kwargs={'object_pairs_hook': collections.OrderedDict}, verbose_name='properties'), File "/home/smontalbano/work/tmpMartie/martie_stripped/venv/lib/python3.8/site-packages/jsonfield/fields.py", line 39, in __init__ super(JSONField, self).__init__(*args, **kwargs) TypeError: __init__() got an unexpected keyword argument 'load_kwargs'
I'm unsure why this error exists only when doing a clean install and not on an existing instance of the project. I even tried moving my db file into source control and skipping the migration process and going right into runserver
but this error is still raised.
I have this admin.py and models.py
from django.contrib import admin
from bootcamp.groups_manager.models import Group, Member, GroupType, GroupEntity, GroupMember, GroupMemberRole
from guardian.admin import GuardedModelAdmin
class GroupAdmin(GuardedModelAdmin):
pass
#admin.site.register(models.Group)
admin.site.register(Group, GroupAdmin)
admin.site.register(Member)
admin.site.register(GroupType)
admin.site.register(GroupEntity)
admin.site.register(GroupMember)
admin.site.register(GroupMemberRole)
class GroupMixin(GroupRelationsMixin, MPTTModel):
name = models.CharField(max_length=255)
codename = models.SlugField(blank=True, max_length=255)
description = models.TextField(default='', blank=True)
comment = models.TextField(default='', blank=True)
parent = TreeForeignKey('self', null=True, blank=True,
related_name='sub_%(app_label)s_%(class)s_set')
full_name = models.CharField(max_length=255, default='', blank=True)
properties = JSONField(default={}, blank=True,
load_kwargs={'object_pairs_hook': OrderedDict})
django_auth_sync = models.BooleanField(default=True, blank=True)
#Custom permission
background_photo = models.CharField(max_length=255, null=True, blank=True)
profile_photo = models.CharField(max_length=255, null=True, blank=True)
#type = models.TextField(default='', blank=True)
class Meta:
abstract = True
ordering = ('name', )
class MPTTMeta:
level_attr = 'level'
order_insertion_by = ['name', ]
class GroupsManagerMeta(GroupRelationsMixin.GroupsManagerMeta):
pass
def __unicode__(self):
return '%s' % self.name
def __str__(self):
return '%s' % self.name
def save(self, *args, **kwargs):
self.full_name = self._get_full_name()[:255]
if not self.codename:
self.codename = slugify(self.name, to_lower=True)
super(GroupMixin, self).save(*args, **kwargs)
def _get_full_name(self):
if self.parent:
return '%s - %s' % (self.parent._get_full_name(), self.name)
return self.name
@property
def subgroups(self):
message = 'The "subgroups" attribute will be removed in next version. ' + \
'Use "sub_groups_manager_group_set" instead.'
warnings.warn(message, DeprecationWarning)
return self.sub_groups_manager_group_set
def get_members(self, subgroups=False):
"""Return group members.
The result is a list of GroupsManagerMeta's attribute ``member_model`` instances.
:Parameters:
- `subgroups`: return also descendants members (default: `False`)
"""
member_model = self.member_model
group_member_model = self.group_member_model
if group_member_model == GroupMember:
members_relation = getattr(self, self.group_members_attribute)
if member_model == Member:
members = list(members_relation.all())
else:
# proxy model
if member_model._meta.proxy:
members = list(member_model.objects.filter(
id__in=members_relation.values_list('id', flat=True)))
# subclassed
else:
members = list(member_model.objects.filter(
member_ptr__in=members_relation.all()))
else:
members = [gm.member for gm in group_member_model.objects.filter(group=self)]
if subgroups:
for subgroup in self.subgroups.all():
members += subgroup.members
members = list(set(members))
return members
@property
def members(self):
"""Return group members. """
return self.get_members(True)
@property
def users(self):
"""Return group django users. """
users = []
for member in self.members:
if member.django_user:
users.append(member.django_user)
return users
def get_entities(self, subgroups=False):
"""Return group entities.
:Parameters:
- `subgroups`: return also descendants entities (default: `False`)
"""
entities = list(self.group_entities.all())
if subgroups:
for subgroup in self.subgroups.all():
entities += subgroup.entities
entities = list(set(entities))
return entities
@property
def entities(self):
"""Return group entities."""
return self.get_entities(True)
def add_member(self, member, roles=None):
"""Add a member to the group.
:Parameters:
- `member`: member (required)
- `roles`: list of roles. Each role could be a role id, a role label or codename,
a role instance (optional, default: ``[]``)
"""
print("add_member() method")
if roles is None:
roles = []
if not self.id:
raise exceptions_gm.GroupNotSavedError(
"You must save the group before to create a relation with members")
if not member.id:
raise exceptions_gm.MemberNotSavedError(
"You must save the member before to create a relation with groups")
group_member_model = self.group_member_model
group_member = group_member_model(member=member, group=self)
group_member.save()
if roles:
for role in roles:
if isinstance(role, GroupMemberRole):
group_member.roles.add(role)
elif isinstance(role, int):
role_obj = GroupMemberRole.objects.get(id=role)
group_member.roles.add(role_obj)
else:
try:
role_obj = GroupMemberRole.objects.get(models.Q(label=role) |
models.Q(codename=role))
group_member.roles.add(role_obj)
except Exception as e:
raise exceptions_gm.GetRoleError(e)
return group_member
def remove_member(self, member):
"""Remove a member from the group.
:Parameters:
- `member`: member (required)
"""
group_member_model = self.group_member_model
try:
group_member = group_member_model.objects.get(member=member, group=self)
except Exception as e:
raise exceptions_gm.GetGroupMemberError(e)
group_member.delete()
def assign_object(self, obj, **kwargs):
"""Assign an object to the group.
:Parameters:
- `obj`: the object to assign (required)
:Kwargs:
- `custom_permissions`: a full or partial redefinition of PERMISSIONS setting.
.. note::
This method needs django-guardian.
"""
return assign_object_to_group(self, obj, **kwargs)
#Custom Method
def get_picture(self):
no_picture = django_settings.MEDIA_URL +'/group_pictures/avatar-team.jpg'
try:
filename = django_settings.MEDIA_ROOT + '/group_pictures/' +\
self.user.username + '.jpg'
picture_url = django_settings.MEDIA_URL + 'group_pictures/' +\
self.user.username + '.jpg'
if os.path.isfile(filename): # pragma: no cover
return picture_url
else: # pragma: no cover
gravatar_url = 'http://www.gravatar.com/avatar/{0}?{1}'.format(
hashlib.md5(self.user.email.lower()).hexdigest(),
urllib.urlencode({'d': no_picture, 's': '256'})
)
return gravatar_url
except Exception:
return no_picture
#Retrieve users' cover
def get_cover(self):
no_cover = django_settings.MEDIA_URL +'group_covers/cover.jpg'
try:
filename = django_settings.MEDIA_ROOT + '/group_covers/' +\
self.user.username + '.jpg'
cover_url = django_settings.MEDIA_URL + 'group_covers/' +\
self.user.username + '.jpg'
if os.path.isfile(filename) and os.path.exists(filename): # pragma: no cover
if cover_url != None:
return cover_url
else:
return no_cover
else:
no_cover
except Exception:
return no_cover
class Group(GroupMixin):
group_type = models.ForeignKey(GroupType, null=True, blank=True, on_delete=models.SET_NULL,
related_name='%(app_label)s_%(class)s_set')
group_entities = models.ManyToManyField(GroupEntity, blank=True,
related_name='%(app_label)s_%(class)s_set')
django_group = models.ForeignKey(DjangoGroup, null=True, blank=True, on_delete=models.SET_NULL)
group_members = models.ManyToManyField(Member, through='GroupMember',
related_name='%(app_label)s_%(class)s_set')
# this is just required for easy explanation
class Meta(GroupMixin.Meta):
abstract = False
permissions = (
('can_add_member_custom', 'Can Add Member Custom'),
('can_remove_member_custom', 'Can Remove Member Custom'),
('can_edit_group_custom', 'Can Edit Group Custom'),
)
It works, but there isn't the autosearch for users, how can I implement it?
Hi.
I am trying to introduce django groups manager to my django site but I found there are some behavior when syncing with main django auth models. It will add some suffix and prefix to original model. I am planing to re-design this behavior. Could you tell why you need to add prefix and suffix ?
Chang
Like the example,
Thoir is in staff group and can handle the budget or does other for Inter group.
I extend the permission in settings.py with:
from django.conf import settings
GROUPS_MANAGER_SETTINGS = getattr(settings, 'GROUPS_MANAGER', {})
SETTINGS_PERMISSIONS = GROUPS_MANAGER_SETTINGS.get('PERMISSIONS', {})
#print(SETTINGS_PERMISSIONS)
PERMISSIONS = {
#'owner': ['view', 'change', 'delete',],
'owner': {
'leader': ['change', 'delete'],
'referent': ['change', 'delete'],
'default': ['view', 'change', 'delete',],
},
'group': ['view', 'change',],
#'groups_upstream': ['view'],
#'groups_downstream': ,
'groups_upstream': {
'leader': ['change', 'delete'],
'referent': ['change', 'delete'],
'default': ['view']
},
'groups_downstream': {
'leader': ['change', 'delete'],
'referent': ['change', 'delete'],
'default': ['view']
},
'groups_siblings': ['view'],
}
PERMISSIONS.update(SETTINGS_PERMISSIONS)
GROUPS_MANAGER = {
# User and Groups sync settings
'AUTH_MODELS_SYNC': GROUPS_MANAGER_SETTINGS.get('AUTH_MODELS_SYNC', False),
'AUTH_MODELS_GET_OR_CREATE': GROUPS_MANAGER_SETTINGS.get('AUTH_MODELS_GET_OR_CREATE', True),
'GROUP_NAME_PREFIX': GROUPS_MANAGER_SETTINGS.get('GROUP_NAME_PREFIX', 'DGM_'),
'GROUP_NAME_SUFFIX': GROUPS_MANAGER_SETTINGS.get('GROUP_NAME_SUFFIX', '_$$random'),
'USER_USERNAME_PREFIX': GROUPS_MANAGER_SETTINGS.get('USER_USERNAME_PREFIX', 'DGM_'),
'USER_USERNAME_SUFFIX': GROUPS_MANAGER_SETTINGS.get('USER_USERNAME_SUFFIX', '_$$random'),
# Permissions
'PERMISSIONS': PERMISSIONS,
# Templates
'TEMPLATE_STYLE': GROUPS_MANAGER_SETTINGS.get('TEMPLATE_STYLE', 'bootstrap3')
}
But the member that have role referent doesn't have the permission, why?
Please answer me, thanks @OskarPersson
How can I fix?
Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/usr/local/lib/python3.5/dist-packages/django/core/handlers/base.py", line 249, in _legacy_get_response
response = self._get_response(request)
File "/usr/local/lib/python3.5/dist-packages/django/core/handlers/base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python3.5/dist-packages/django/core/handlers/base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/ies/bootcamp/bootcamp/authentication/views.py", line 422, in create_society
fsociety = Group(**form.cleaned_data)
File "/usr/local/lib/python3.5/dist-packages/mptt/models.py", line 388, in __init__
super(MPTTModel, self).__init__(*args, **kwargs)
File "/usr/local/lib/python3.5/dist-packages/django/db/models/base.py", line 567, in __init__
_setattr(self, prop, kwargs[prop])
File "/usr/local/lib/python3.5/dist-packages/django/db/models/fields/related_descriptors.py", line 536, in __set__
manager = self.__get__(instance)
File "/usr/local/lib/python3.5/dist-packages/django/db/models/fields/related_descriptors.py", line 513, in __get__
return self.related_manager_cls(instance)
File "/usr/local/lib/python3.5/dist-packages/django/db/models/fields/related_descriptors.py", line 830, in __init__
(instance, self.pk_field_names[self.source_field_name]))
ValueError: "<Group: Compravo>" needs to have a value for field "id" before this many-to-many relationship can be used.
Hello, I run into following issue while using Django-groups-manager. When I create a first company making the use of the serialiser below, it works fine. But when I try to register another company, I get error as shown in the track back. What did I do wrong?
class OrganisationCreateSerializer(serializers.ModelSerializer):
vat = serializers.CharField(allow_blank=False, write_only=True)
default_admin = CorporateAdminSerializer(many=False)
def create(self, validated_data):
validated_data_admin = validated_data.pop('default_admin')
default_admin = CorporateUser.objects.create(**validated_data_admin)
company_name = ('%s' % (validated_data['name'])).capitalize()
default_team_permissions = {
'owner': {'administrator': ['change','delete'], 'default': ['view']},
'group': ['view'],
'groups_upstream': [''],
'groups_downstream': ['view'],
'groups_siblings': [''],
}
team_type_company = GroupType.objects.get_or_create(codename='%s-company' % company_name.lower(),
label='%s company' % company_name)[0]
default_team = Team.objects.get_or_create(
group_type=team_type_company,
short_name="%s Team" % company_name,
name="%s Company Team" % company_name,
codename="%s" % company_name.lower()
)[0]
company = Organisation.objects.create(
default_team=default_team, default_admin=default_admin, **validated_data)
corp_user = default_admin
admin_role = GroupMemberRole.objects.get_or_create(
codename='administrator', label="Company Administrator")[0]
member_role = GroupMemberRole.objects.get_or_create(
codename='member', label="Company Member")[0]
company.default_team.add_member(corp_user, [admin_role])
corp_user.assign_object(company.default_team, company,
custom_permissions=default_team_permissions)
company.default_team.assign_object(company, custom_permissions=default_team_permissions)
return company
class Meta:
model = Organisation
fields = ('id', 'name', 'vat', 'default_admin')
ref_name = "Organisation"
Trackback:
Request Method: POST
Request URL: http://0.0.0.0:8000/api/v1/register/organisation/
Django Version: 2.1.2
Python Version: 3.6.7
Installed Applications:
('django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework.authtoken',
'django_filters',
'drf_yasg',
'guardian',
'groups_manager',
'bootstrap3',
'users',
'candidates',
'organisations',
'django_nose')
Installed Middleware:
('django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware')
Traceback:
File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
34. response = get_response(request)
File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
126. response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
124. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.6/site-packages/django/views/decorators/csrf.py" in wrapped_view
54. return view_func(*args, **kwargs)
File "/usr/local/lib/python3.6/site-packages/rest_framework/viewsets.py" in view
116. return self.dispatch(request, *args, **kwargs)
File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py" in dispatch
495. response = self.handle_exception(exc)
File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py" in handle_exception
455. self.raise_uncaught_exception(exc)
File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py" in dispatch
492. response = handler(request, *args, **kwargs)
File "/usr/local/lib/python3.6/site-packages/rest_framework/mixins.py" in create
21. self.perform_create(serializer)
File "/usr/local/lib/python3.6/site-packages/rest_framework/mixins.py" in perform_create
26. serializer.save()
File "/usr/local/lib/python3.6/site-packages/rest_framework/serializers.py" in save
214. self.instance = self.create(validated_data)
File "/code/vitapio/organisations/serializers.py" in create
97. custom_permissions=default_team_permissions)
File "/usr/local/lib/python3.6/site-packages/groups_manager/models.py" in assign_object
122. return assign_object_to_member(group_member, obj, **kwargs)
File "/usr/local/lib/python3.6/site-packages/groups_manager/perms.py" in assign_object_to_member
82. assign_related(siblings_groups, siblings_perms, obj)
File "/usr/local/lib/python3.6/site-packages/groups_manager/perms.py" in assign_related
33. assign_perm(perm_name, django_group, obj)
File "/usr/local/lib/python3.6/site-packages/guardian/shortcuts.py" in assign_perm
109. return model.objects.assign_perm(perm, group, obj)
File "/usr/local/lib/python3.6/site-packages/guardian/managers.py" in assign_perm
39. permission = Permission.objects.get(content_type=ctype, codename=perm)
File "/usr/local/lib/python3.6/site-packages/django/db/models/manager.py" in manager_method
82. return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.6/site-packages/django/db/models/query.py" in get
399. self.model._meta.object_name
Exception Type: DoesNotExist at /api/v1/register/organisation/
Exception Value: Permission matching query does not exist.
I can set the page permission according to the user in the group in the decorator below. So how can I set this up for the member's role? Thus, only the member with this role can see the page. I'm waiting for your help.
decorators.py
def sahip_only(view_func):
def wrapper_function(request, *args, **kwargs):
group = None
if request.user.groups.exists():
group = request.member.groups.all()[0].name
if group == 'PC':
return redirect('home')
if group == 'Console':
return view_func(request, *args, **kwargs)
else:
return HttpResponse('You are not authorized to access this page.')
return wrapper_function
views.py
@login_required(login_url='/accounts/login/')
@sahip_only
def calisan(request):
queryset = request.user.groups
form = CalisanForm(request.POST or None, group_qs=queryset)
if form.is_valid():
user = form.save()
group = form.cleaned_data['group']
user.groups.add(AGroup.objects.get(name=group))
username = form.cleaned_data['username']
member = Member.objects.create(first_name=username)
group = Group.objects.get(name=form.cleaned_data['group'])
group.add_member(member, [form.cleaned_data.get('roles')])
user.save()
password = form.cleaned_data.get('password1')
new_user = authenticate(username=user.username, password=password)
return redirect('home')
return render(request, 'accounts/calisan/calisan.html', {'form': form, 'title': 'Üye Ol'})
forms.py
class CalisanForm(UserCreationForm):
username = forms.CharField(max_length=100, label='Kullanıcı Adı')
email = forms.EmailField(max_length=200, help_text='Required')
password1 = forms.CharField(max_length=100, label='Parola', widget=forms.PasswordInput)
password2 = forms.CharField(max_length=100, label='Parola Doğrulama', widget=forms.PasswordInput)
group = forms.ModelChoiceField(queryset=Group.objects.all(), widget=forms.widgets.RadioSelect(), empty_label=None)
roles = forms.ModelChoiceField(queryset=GroupMemberRole.objects.all(), widget=forms.widgets.RadioSelect(), empty_label=None)
def __init__(self, *args, **kwargs):
qs = kwargs.pop("group_qs")
super().__init__(*args, **kwargs)
self.fields["group"].queryset = qs
class Meta:
model = User
fields = [
'username',
'email',
'password1',
'password2',
'group',
'roles',
]
def clean_password2(self):
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Parolalar eşleşmiyor!")
return password2
def clean_email(self):
email = self.cleaned_data.get('email')
lenghtw = len(User.objects.filter(email=email))
if lenghtw > 0 :
raise forms.ValidationError('Bu email adresine sahip bir kullanıcı zaten var.')
return email
Hi, first of all, thank you, this library is amazing.
I've noticed in my migrations that I have dependencies on a 0007_alter_group_group_entities_alter_group_group_members_and_more.py
This is being created, but it's difficult to version in git. Is this missing from your repo? Or am I doing something wrong?
Migrations for 'groups_manager':
venv/lib/python3.8/site-packages/groups_manager/migrations/0007_alter_group_group_entities_alter_group_group_members_and_more.py
- Alter field group_entities on group
- Alter field group_members on group
- Alter field group_type on group
- Alter field id on group
- Alter field parent on group
- Alter field id on groupentity
- Alter field id on groupmember
- Alter field id on groupmemberrole
- Alter field id on grouptype
- Alter field django_user on member
- Alter field id on member
thank you!
Is this intentionally left unimplemented in order to implement in a subclass?
I'd like to be able to do (as the API shows) e.g.
my_group.assign_object(some_object)
instead of having to associate that with a user (which the docs show) e.g.
my_user.assign_object(my_group, some_object)
From the documentation I had the feeling that guardian
is optional, however, guardian
is listed as a required package and will be installed with django-groups-manager
,
django-groups-manager/setup.py
Line 21 in 729d76c
Then because guardian can be imported,
django complains about
File "manage.py", line 30, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 357, in execute
django.setup()
File "/usr/local/lib/python3.7/site-packages/django/__init__.py", line 24, in setup
apps.populate(settings.INSTALLED_APPS)
File "/usr/local/lib/python3.7/site-packages/django/apps/registry.py", line 114, in populate
app_config.import_models()
File "/usr/local/lib/python3.7/site-packages/django/apps/config.py", line 211, in import_models
self.models_module = import_module(models_module_name)
File "/usr/local/lib/python3.7/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 728, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/usr/local/lib/python3.7/site-packages/groups_manager/models.py", line 22, in <module>
from groups_manager.perms import assign_object_to_member, assign_object_to_group
File "/usr/local/lib/python3.7/site-packages/groups_manager/perms.py", line 4, in <module>
from guardian.shortcuts import assign_perm
File "/usr/local/lib/python3.7/site-packages/guardian/shortcuts.py", line 27, in <module>
GroupObjectPermission = get_group_obj_perms_model()
File "/usr/local/lib/python3.7/site-packages/guardian/utils.py", line 228, in get_group_obj_perms_model
from guardian.models import GroupObjectPermissionBase
File "/usr/local/lib/python3.7/site-packages/guardian/models/__init__.py", line 1, in <module>
from .models import (
File "/usr/local/lib/python3.7/site-packages/guardian/models/models.py", line 69, in <module>
class UserObjectPermission(UserObjectPermissionAbstract):
File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 111, in __new__
"INSTALLED_APPS." % (module, name)
RuntimeError: Model class guardian.models.models.UserObjectPermission doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.
So guardian
has to be installed to INSTALLED_APPS
. Should not django-guardian
be removed from setup.py
if it is indeed optional?
Hello,
There is a function to assign the object to the member.
But If I want to change or remove the ownership of the object, there is not an explicit description in the document.
Hi again!
I think the Member class could has a relationship with django user OneToOne, in that way the reverse call is direct.
Like 'user.member' despite 'user.members.first()' (because uses foreignkey'.
Is a bit more consistent because identifies one member with one user....
could help
When subclassing Group and Member classes, the check on signal functions are made against GROUPS_MANAGER's AUTH_MODELS_SYNC
key.
With a kwarg it will be easily controlled separately for each subclassed model.
Hi,
I need to have a permission, that let the users of a specific group to add, delete or remove only for the specific group.
Hi,
in template view doesn't work the get_obj_perms.
{% load guardian_tags %}
{% get_obj_perms request.user for groups_manager as "context_var" %}
{{context_var}}
{{perms.groups_manager}}
{{perms.groups}}
<!--PERMISSIONS_HERE-->
{% if perms.groups_manager.can_add_member_custom %}
<p>
<a href="{% url 'groups_manager:group_member_add_member' group.id %}">
<i class="fa fa-plus"></i>
Add member to group
</a>
</p>
{% endif %}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.