Is it possible to have different views for different users on the same content type?

Hi all, Is it possible to have different views for different users on the same content type?
This is the scenario that I want:

  • UserA can login and be redirected to "istanceOfMyCT" which show ViewA (it can be even the default view);
  • UserB can login and be redirected to "istanceOfMyCT" (the same one istance used by UserA), but for this user show ViewB.

I already tryed to achieve this by using a specific role with a dedicated permission but this solution is not perfect:

  • The user with correct rights can see her dedicated view, but only him (not even "admin" can see the dedicated view);
  • The dedicate view is rendered whitout the any theme (I use the default, barcelloneta).
    Any suggestions?

Look at collective.onlogin addon for performing a login redirection after login. The implementation of the redirect switch based on some conditions is up to,you....and remember being „admin“ is like being god..god sees everything and there is no way to deny access to the superuser.

-aj

Sure: You define a view which delegates to different views depending on the user.
I.e., it may contain code like the following:

from AccessControl import getSecurityManager
class SwitchingView(BrowserView):
  ...
  def __call__(self):
     user = getSecurityManager().getUser()
     view_class = view_class1 if user == ... else
                            view_class2 if user == ... else
                            view_classn
     return view_class(self.context, self.request).__call__()
2 Likes

I think there are quite a few ways of doing this.

The lazy ways are probably using CSS and/or TAL and hide/show things or redirect to another view

The proper way is probably more like how plone link is doing it:

So, if it is possible, just make two (or more) templates.pt

probably, you dont need all the code in the link view, maybe just something like:

from plone import api

class SomeView(BrowserView):
    indexA = ViewPageTemplateFile('templateA.pt')
    indexB = ViewPageTemplateFile('templateB.pt')

    def __call__(self):
        if plone.api.group.get_roles contains 'something':
        return self.indexA()

        if something else:
              return self.indexB()

       … 
       else:

Thank you! This is what I'm searching.

For completeness: with at least 2 target classes, each with its template, it is necessary to remove the template declaration from configure.zcml

<browser:page
      name="switched_view"
      for="*"
      layer="zope.interface.Interface"
      class=".views.SwitchViewPerUser"
      permission="zope2.View"
      />

And write classes like this

class SwitchViewPerUser(DefaultView):
	...
	def __call__(self):

		user = getSecurityManager().getUser()
        	username = user.getUserName()
        
	        target_view_class = MyFirstView
        	if username == "userA":
        	    pass
        	elif username == "userB":
        	    target_view_class = MySecondView

		return target_view_class(self.context, self.request).__call__()




from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile

class MyFirstView(DefaultView):
	template = ViewPageTemplateFile('templates/first.pt')

	def __call__(self):
		
		...

		return self.template()


class MySecondView(DefaultView):
	""" Similar to MyFirstView """

obviously the user must have the rights to access the CT.
To redirect the user at login I followed the documentation and modified the postlogin.py.

You only need to (should) set the template one place: so only set it in ZCML if it it 'always the same'.

Without knowing much: Do you 'really need all this stuff'.
Unless you need to do 'a lot of stuff, you only need to change 'template'.
Even then, you can do thing like:

<div>${view/something1}</div>

in template one

and

<div>${view/something2}</div>

in template2

and define them in 'SwitchView' as

def something1(self):
     return 'something'

def something2(self):
      return 'something,too'

Then, you probably dont have to 'duplicate so much code'

Also: you can do a 'normal' redirect, like the link view does.

PS: it is also possible to have two views with the same class and define the templates in ZCML

<browser:page
  name="view1"
  class=".views.MyView"
  template="view1.pt'

<browser:page
  name="view2"
  class=".views.MyView"
  template="view2.pt'

I am responsible for the .__call__() suffix. It fact, it can be shortened to ().

The important thing for Fausto it to get different views for different users. You are right that it can be done in a template, too. However, logic is usually better in Python code than template code.

Yes: I need to have distinct "views", each one with her template.
And yes: I need to do 'a lot of stuff' :slight_smile: and so I prefer to do the great part of work in the business-logic with python.
Anyhow, I thanks every one for the precious advices.

I just made a 'user list' where (the two) 'Managers' can see 'all fields' while 'normal members' just sees a few fields.

I use a slightly different approach, please correct me if it is 'wrong'

If you only hide fields for particluar users, then use the Permission Setting like described in plone.autoforms