Limit Django users to one single group - django

I'm rather surprised that this hasn't been asked before, but I need to limit my Users in Django to only belong to one single Group. How would I do this?

One option can be that in your view or form, before you add more groups to the user you make a validation:
if user.groups.exists():
for g in user.groups.all():
user.groups.remove(g)
user.groups.add(group_to_add)

You need to override the Groups field widget :
groups = forms.ModelMultipleChoiceField(
queryset=Group.objects.all(),
widget=forms.SelectMultiple
)
and then remove the 'multiple' attribute using Javascript :
$(document).ready(function(){
$("#id_groups").removeAttr("multiple");
});

Related

Add password to Django Group model

Is it possible to password protect groups so that a user can only join a group if the user has a password for that group?
I know it's possible to add fields to the Group model with
Group.add_to_class('password', CharField(max_length=180, null=True, blank=True))
But how can I implement this in a secure way? I want the password to be properly hashed and stored. In essence, how can I add the User password field to Group as well?
EDIT:
The docstring for the Group class in the source.
Groups are a generic way of categorizing users to apply permissions,
or some other label, to those users. A user can belong to any number
of groups.
Beyond permissions, groups are a convenient way to categorize users to
apply some label, or extended functionality, to them.
All I'm using a group for here is a label, and I want to password protect that label for when users try to join.
After considering your responses in the comments, I believe your best bet will be to subclass Group and then implement an authentication procedure within it. Then you can use the functions make_password, check_password, and is_password_usable as documented here to manage the authentication process.

Mongoid update association with existing documents, not creating a new one

I'm attempting to figure out how to elegantly update a document's associations with existing documents with Mongoid.
If I have Users and Groups, and want to assign a User to an existing group, how could I do this via update_attributes ?
I want to be able to do something like this:
user.attributes = { groups: [{"_id":"existing group id here"}]}
user.save
When I try to do the above, Mongoid attempts to INSERT a new group, thereby causing a ID duplicate error.
I have tried doing the same via nested attributes:
user.groups_attributes = [{"_id":"existing group id here"}]
user.save
And the same error occurs. Is there anyway I can do this WITHOUT having to manually query the group id and push it into the array? The reason I'm asking is because lets say i have a model with many associations.. i dont want to have to have blocks of code to update each association manually
Assigning an an existing User to an existing Group with update_attributes is very simple (assuming you already added the Group/User relation).
user.update_attributes(:group_id => 'existing group id here')

How to find user group and use of caching in django?

I am new to django/python and working my way through my webapp. I need assistance in solving one of my problems.
In my app, I am planning to assign each user (from auth_user) to one of the group ( from auth_group). Each group can have multiple users. I have entry in auth_group, auth_user and auth_user_groups. Here is my question:
At time of login I want to check that logging user belongs to which group?
I want to keep that group info in session/cache so all pages I can show information about that group only.
If you have any sample code will be great.
Giving support to the very well #trinchet's answer with an example of context_processor code.
Puts inside your webapp a new file called context_processors.py and writes this lines on it:
def user_groups(request):
"""
Add `groups` var to the context with all the
groups the logged in user has, so you can access
in your templates to this var as: {{ groups }}
"""
groups = None
if request.user.is_authenticated():
groups = user.groups
return {'groups': groups}
Finally on your settings.py add 'webbapp.context_processors.user_groups'to TEMPLATE_CONTEXT_PROCESSOR:
TEMPLATE_CONTEXT_PROCESSORS = (
'webbapp.context_processors.user_groups',
)
1) Be user an instance of auth.models.User, you can get all groups the user belong to, through user.groups. If you want to ask at time of login then you should do this in your login view.
2) You can use session or cache approaches to deal with, this is irrelevant, but once you have the group you need to render the pages having this value, i mean, you need to provide the group to the template rendering, to do this I suggest to you using a custom context processor.

Django: How to access the model id's within an AJAX script?

I was wondering what is the correct approach,
Do I create HiddenInput fields in my ModelForm and from the
View I pass in the primaryKey for the models I am about to edit into
the hiddenInput fields and then grab those hiddenInput fields from
the AJAX script to use it like this?
item.load(
"/bookmark/save/" + hidden_input_field_1,
null,
function () {
$("#save-form").submit(bookmark_save);
}
);
Or is there is some more clever way of doing it and I have no idea?
Thanks
It depends upon how you want to implement.
The basic idea is to edit 1. you need to get the existing instance, 2. Save provided information into this object.
For #1 you can do it multiple ways, like passing ID or any other primary key like attribute in url like http://myserver/edit_object/1 , Or pass ID as hidden input then you have to do it through templates.
For #2, I think you would already know this. Do something like
inst = MyModel.objects.get(id=input_id) # input_id taken as per #1
myform = MyForm(request.POST, instance=inst)
if myform.is_valid():
saved_inst = myform.save()
I just asked in the django IRC room and it says:
since js isn't processed by the django template engine, this is not
possible.
Hence the id or the object passed in from django view can't be accessed within AJAX script.

Django: structuring a complex relationship intended for use with built-in admin site

I have a fairly complex relationship that I am trying to make work with the Django admin site. I have spent quite some time trying to get this right and it just seems like I am not getting the philosophy behind the Django models.
There is a list of Groups. Each Group has multiple departments. There are also Employees. Each Employee belongs to a single group, but some employees also belong to a single Department within a Group. (Some employees might belong to only a Group but no Department, but no Employee will belong only to a Department).
Here is a simplified version of what I currently have:
class Group:
name = models.CharField(max_length=128)
class Department
group = models.ForeignKey(Group)
class Employee
department = models.ForeignKey(Department)
group = models.ForeignKey(Group)
The problem with this is that the Department select box on the Employees page must display all Departments, because a group has not yet been set. I tried to rectify this by making an EmployeeInline for the GroupAdmin page, but it is not good to have 500+ employees on a non-paginated inline. I must be able to use the models.ModelAdmin page for Employees (unless there is a way to search, sort, collapse and perform actions on inlines).
If I make EmployeeInline an inline of DepartmentAdmin (instead of having a DepartmentInline in GroupAdmin), then things are even worse, because it is not possible to have an Employee that does not belong to a Group.
Given my description of the relationships, am I missing out on some part of the Django ORM that will allow me to structure this relationship the way it 'should be' instead of hacking around and trying to make things come together?
Thanks a lot.
It sounds like what you want is for the Department options to only be those that are ForeignKey'ed to Group? The standard answer is that the admin site is only for simple CRUD operations.
But doing what you're supposed to do is boring.
You could probably overcome this limitation with some ninja javascript and JSON.
So first of all, we need an API that can let us know which departments are available for each group.
def api_departments_from_group(request, group_id):
departments = Department.objects.filter(group__id=group_id)
return json(departments) # Note: serialize, however
Once the API is in place we can add some javascript to change the <option>'s on the department select...
$(function() {
// On page load...
if ($('#id_group')) {
// Trap when the group box is changed
$('#id_group').bind('blur', function() {
$.getJSON('/api/get-departments/' + $('#id_group').val() + '/', function(data) {
// Clear existing options
$('#id_department').children().remove();
// Parse JSON and turn into <option> tags
$.each(data, function(i, item) {
$('#id_department').append('<option>' + item.name + '</option>');
});
});
});
}
});
Save that to admin-ninja.js. Then you can include it on the admin model itself...
class EmployeeAdmin(models.ModelAdmin):
# ...
class Media:
js = ('/media/admin-ninja.js',)
Yeah, so I didn't test a drop of this, but you can get some ideas hopefully. Also, I didn't get fancy with anything, for example the javascript doesn't account for an option already already being selected (and then re-select it).