Re: Multi Client Django System

383 views
Skip to first unread message

Bino Oetomo

unread,
Feb 22, 2013, 10:54:46 PM2/22/13
to Django users
Hi Delcio

On Feb 23, 10:43 am, Delcio Torres <delciotor...@gmail.com> wrote:
> Dear Sirs,
>
> Maybe this is a concept question, but here we go.
>
> I'm doing test development to learn django and using admin for everything.
>
> This is a Company/Employee/HeathInsurance CRUD system.
>
> The main ideia is that I want to provide this for different companies and
> still not allow them to see each others registers.
>
> A Django Admin user , should belong to Company or be associated with it
> somehow and only see the registers created by other members of the same
> company.
>
...
looks we share the same interest/need.

My Scenario is to build what I will call it as 'Second Level Auth'.
I Made a copy of User and Group, and modified Permission to have one
more field 'is_delegate'

What I try to do is to enable each company 'admin' to CRUD and Assign
permission to users under their company.

check my thread https://groups.google.com/group/django-users/browse_thread/thread/d3c508ce2a0f2dec

Sincerely
-bino-

Delcio Torres

unread,
Feb 22, 2013, 11:10:04 PM2/22/13
to django...@googlegroups.com
Thanks, will check! I'm really struggling to find the best approach. 

Gabriel - Iulian Dumbrava

unread,
Feb 23, 2013, 11:00:10 AM2/23/13
to django...@googlegroups.com
How I would do it would be to have a special column (foreign key) in each table (model) called Company (company_id) and change all default managers to filter on company_id = logged_in_user.company_id.

In this way you are sure tha users only see what belongs to their company.

You would have to pass the company_id to models, probably with a middleware which gets it from the logged in user and saves it somewhere.

And you also have to save the default value of company_id to each newly created entry in every table, probably from the same source as above.

Gabriel - Iulian Dumbrava

unread,
Feb 23, 2013, 11:03:20 AM2/23/13
to django...@googlegroups.com
As far as I remember there is already a package out called django-saas or something like that.

Let me know how you solve it.
Gabriel

Bino Oetomo

unread,
Feb 23, 2013, 9:28:35 PM2/23/13
to django...@googlegroups.com

Dear Gabriel Sir.
I really appreciate your response

On Saturday, February 23, 2013 11:00:10 PM UTC+7, Gabriel - Iulian Dumbrava wrote:
How I would do it would be to have a special column (foreign key) in each table (model) called Company (company_id)

Yes , thats the plan
and change all default managers to filter on company_id = logged_in_user.company_id.

In this way you are sure tha users only see what belongs to their company.

Yes, it'll required.
Anyway, what you mean with 'default manager' ?

You would have to pass the company_id to models, probably with a middleware which gets it from the logged in user and saves it somewhere.

Kindly please give me more clue on this

Sincerely
-bino-

Bino Oetomo

unread,
Feb 24, 2013, 2:39:16 AM2/24/13
to django...@googlegroups.com
I think I'll take :
1. https://github.com/avidal/django-organizations , or
2. https://github.com/bennylope/django-organizations

as starting point.

But diferent from that two great solution, I want :
1. Use completely seperated user, group models
2. each user only bound to one organization

C/q : Delcio Torres, I Apologie if my posts bothering your thread.

Sincerely
-bino-

Frank Bieniek

unread,
Feb 25, 2013, 4:18:50 AM2/25/13
to django...@googlegroups.com
We achived the second level auth, by tying an extended group to a company,
all company members are part of this group, so we can leverage the
normal auth mechanismen.

Hope this gives you an idea.

Thanks
Frank

class CompanyManager(models.Manager):
filter_by_user_limit_field = None

def by_user(self, user):
"""
Extension for filtering organization objects (also related
objects) by
the groups of a user.
Avoiding that a user can touch other organization objects.
Superusers and
Partner Administrators are able to see all organizations.
"""
# if the user is not logged in - no data
if not user.is_authenticated():
return self.none()
# TODO: optimization: would be nice to find a way to make
by_user chainable like .filter(), ...
return self.limit_queryset_by_user(
self.get_query_set(),
user,
self.model.filter_by_user_limit_field
)

@staticmethod
def limit_queryset_by_user(qs, user, field_key):
if user.is_superuser.count()>0:
return qs
kwargs = {}
if field_key and user.groups.count() > 0:
kwargs[field_key] = [u['id'] for u in user.groups.values('id')]
return qs.filter(**kwargs)

And in the model

class Company(ExtendedModel):
name = models.CharField(max_length=64, unique=True)
slug = models.SlugField(unique=True)
is_active = models.BooleanField(null=False, blank=False, default=True)

filter_by_user_limit_field = "organizationgroup__in"
objects = CompanyManager()

class CompanyGroup(Group):
"""
User group of the Organization
"""
organization = models.OneToOneField(Organization)

Subodh Nijsure

unread,
Feb 25, 2013, 12:56:36 PM2/25/13
to django...@googlegroups.com
Could - Django multitenant cold possibly help you?

https://pypi.python.org/pypi/django-simple-multitenant


-Subodh

On Fri, Feb 22, 2013 at 7:43 PM, Delcio Torres <delcio...@gmail.com> wrote:
> Dear Sirs,
>
> Maybe this is a concept question, but here we go.
>
> I'm doing test development to learn django and using admin for everything.
>
> This is a Company/Employee/HeathInsurance CRUD system.
>
> The main ideia is that I want to provide this for different companies and
> still not allow them to see each others registers.
>
> A Django Admin user , should belong to Company or be associated with it
> somehow and only see the registers created by other members of the same
> company.
>
> My question is Django Admin Groups from Auth Model would do the task or not.
>
> I've thought about overriding save_mode and get the group to which the user
> belongs , then save it into some group field at HeathInsurance and Employee.
>
> Then on admin.py thought about overriding the queryset and use a filter so
> you would only see registers from your company.
>
> Is this feasible ? Is this the way?
>
> Thanks everyone!
>
> Best Regards,
>
> Delcio
>
> Here some model example
> ## models.py ##
> class Company(models.Model):
> name = models.CharField(max_length=200, null=False)
>
>
> class HeathInsurance(models.Model):
> nome = models.CharField(max_length=200, null=False)
>
>
> class Employee(models.Model):
> name = models.CharField(max_length=200, null=False)
> company = models.ForeignKey(Company)
> health_insurance = models.ForeignKey(HeathInsurance)
>
> --
> You received this message because you are subscribed to the Google Groups
> "Django users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to django-users...@googlegroups.com.
> To post to this group, send email to django...@googlegroups.com.
> Visit this group at http://groups.google.com/group/django-users?hl=en.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

Delcio Torres

unread,
Feb 26, 2013, 12:12:48 PM2/26/13
to django...@googlegroups.com
Hey Bino nevermind I'm learning here and will try to use the same approach, so far I already know that I need to get deep on manager, as I've never used it before. Keep going!

Thanks!

Delcio Torres

unread,
Feb 26, 2013, 12:22:45 PM2/26/13
to django...@googlegroups.com
A friend just sent me this:

https://pypi.python.org/pypi/django-simple-multitenant

and another, recommended this to prevent url tempering:

I will have a look also.

Delcio

Richard E. Cooke

unread,
May 22, 2013, 9:46:23 PM5/22/13
to django...@googlegroups.com
Frank!

You appear to have figured out what I spent most of today trying to figure out:  How to get access to the current logged in user from INSIDE a custom data manager!

Can you clarify something in your code?

In your custom manager you define "by_user", which takes "user" as an input.  But in your class you just name your custom data manager in place of the default "object" manager.

How do you ( a ) get the system to call your "by user" query?  And ( b ) how do you get the system to send in the current "user"?

I was thinking there might be a link through the site.model reference Managers get.  Or maybe a way to pull it from session, but I keep get stuck on the fact this isn't a view, so it has no obvious access to a "request" object????

Thanks in advance!

Frank Bieniek

unread,
May 23, 2013, 2:32:28 PM5/23/13
to django...@googlegroups.com
Hi Richard,


How do you ( a ) get the system to call your "by user" query? 
a) in your views you query manually - see below - organization_list


And ( b ) how do you get the system to send in the current "user"?
the magic is in the permalink.... get_slugged_organization_documents_url

in the delegation view you do some redirect, every organization has its own slug (model of organization):

----
def organization_list(request):
    """
    Function checks implicitly if this user has more than one
    organization. If not forward to the organization absolute url
    if it is a partner admin go to the list page
    """
    qs = Organization.objects.by_user(request.user)
    if qs.count() == 1:
        # a normal partner-admin / user won't see a list of organizations
        slug=qs[0].slug
        return HttpResponseRedirect(get_slugged_organization_documents_url(slug))
    else:
        return organization_list_partner_admin(request)

def get_slugged_organization_documents_url(slug):
    return ('organization_documents', (), {'organization_slug': slug})
get_slugged_organization_documents_url = permalink(get_slugged_organization_documents_url)

urls.py:
urlpatterns = patterns('',
    #no organization selected, redirects to user organization
    url(r'^$', organization_list, name='organization_list'),
    # this one is the default url without any command, but users organization
    url(r'^(?P<organization_slug>[-\w]+)/', include(patterns('',
        url(r'^$', organization_documents, name='organization_default'),
    .....
... and in the organizations_documents you check that the request.user is member of the slugged organization...

def organization_documents(request, organization_slug):
    qs = Organization.objects.by_user(request.user)
    try:
        organization = qs.get(slug=organization_slug)
    except ObjectDoesNotExist:
        return HttpResponseForbidden('You are not allowed to....')
   ..... normal code here
.....

hope this helps.
basically you have a slugged organization, and a delegation view - the delegation view does the magic.


here is another solution to your problem - classed based view mixins for multi account setups:
http://django-organizations.readthedocs.org

Welcome
Frank

Richard Cooke (Gmail)

unread,
May 27, 2013, 9:04:43 AM5/27/13
to django...@googlegroups.com
Thanks Frank!

Lots of great bed-time reading!!

Rich.
You received this message because you are subscribed to a topic in the Google Groups "Django users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-users/qlf_LOpWN60/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to django-users...@googlegroups.com.

To post to this group, send email to django...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 


-- 


Regards,
Richard Cooke
Reply all
Reply to author
Forward
0 new messages