【问题标题】:Resolving urls to different views for different types of user profiles in Django在 Django 中为不同类型的用户配置文件解析不同视图的 url
【发布时间】:2011-07-09 11:41:10
【问题描述】:

我正在向网站添加一种新类型的用户个人资料,这种新类型的用户(比如 new_type)应该无法像现有用户一样访问相同的视图。

我的问题是:如何根据用户类型使用相同的请求路径使用不同类型的视图,而无需更改现有视图代码,例如添加

if user.profile_type == 'blah':
    do_this 
else: 
    do_that 

每个视图?

详细说明:

我想为这两种类型的用户使用“http://mysite.com/path/”,运行不同的逻辑并返回不同的显示而不会对现有视图产生差异(因为有很多视图需要修改) .

我正在考虑为新类型添加不同的视图组,然后覆盖 urls 逻辑以解析到相关视图的请求路径,例如:

if user is of new_type 
    resolve path to related_view_for_new_type
else
    resolve as usual 

作为一个简单的例子:从同一个登录 url 登录 admin 和普通用户,如果用户是 admin,则运行 admin 的相关视图并将 django admin 显示返回给她,如果是普通用户,则运行普通视图并将正常的网站视图返回给她,而无需重写或更改他们请求的 url。 (例如 /index/)

是否可以在 Django 中以这种方式扩展 url,如果可以,或者我应该放弃重载相同的请求路径并将 '/new_type/' 添加到 url (http://mysite.com/new_type/path /)对于 new_type 用户?

谢谢

【问题讨论】:

    标签: django django-views django-urls extending


    【解决方案1】:

    首先,拥有不同类型的用户意味着什么?一种非常简单的方法是将属性存储在用户身上。这样,给定一个user 对象,您可以查看这个额外的属性来确定用户是否属于特殊类型。 Django 有一个标准机制来存储这样的附加属性,您可以阅读有关 here 的信息。

    一旦您有了确定用户类型的方法,您就可以创建一个装饰器并将其应用于需要按照您所描述的方式运行的任何视图。装饰器是将额外条件或行为应用于现有函数的好方法。装饰器中的逻辑在现有函数之前和/或之后开始工作,因此它可以很容易地完成一些事情,比如根据用户的类型显示不同的模板。

    当你第一次遇到装饰器函数时,它们看起来很奇怪,但仔细阅读它,你很快就会明白。装饰器本身就是一个函数,你给它你想要装饰的函数。它会返回一个 new 函数,这是你的旧函数,包含额外的逻辑。

    我在下面编写了一些未经测试的示例代码。

    def template_based_on_user_type(special_template, ordinary_template):
        def decorator(your_view_function):
            def inner_decorator(request, *args, **kwargs):
                # this is the logic that checks the user type before 
                # every invocation of this view:
                if request.user.type == 'special_type':
                    template = special_template
                else:
                    template = ordinary_template
    
                # this is the invocation of the view function, with
                # a custom template selected:
                return your_view_function(request, template)
            return inner_decorator
        return decorator
    
    @template_based_on_user_type('my-special-template.html', 'ordinary-template.html')
    def my_view_function(request, template='default.html'):
        # Do what you need to do here
        render_to_response(template, data, RequestContext(request)
    

    应用装饰器的语法是“@”符号,后跟装饰器函数。使用指定的模板名称自定义装饰器。

    【讨论】:

    • 感谢您的详细回答。看来我的问题有点模棱两可。我希望这两种用户类型都能够访问 mysite.com/path/ 但看到不同逻辑的不同结果,其中逻辑不需要有任何相似之处。我正在用更多细节更新问题。
    • 我假设您有一个现有的视图函数,并且您想显示不同的内容而不编写另一个视图函数。
    【解决方案2】:

    RTFM 照常 :)

    这是一个可能的解决方案的链接: method_splitter@http://www.djangobook.com/en/2.0/chapter08/

    new_type 相关视图的名称会从原始视图中派生出来,方法是在名称开头添加 new_type_,例如 index->​​ new_type_index

    然后我将通过简单地检查 request.user.is_new_type 属性来确定要返回的视图。丑陋,但比修改无数的观点要好。

    【讨论】:

      【解决方案3】:

      我在 urls.py 中使用装饰器解决了这个问题:

      def dispatch_by_user(staff_view, external_user_view):
          def get_view(request, **kwargs):
              if (is_staff_user(request.user)):
                  return staff_view(request, **kwargs)
              else:
                  return external_user_view(request, **kwargs)
          return login_required(get_view)
      
      def is_staff_user(user):
          return user.groups.filter(name="privileged-group").exists()
      

      所以模式设置如下:

      urlpatterns = [
          url(r'^$',
              dispatch_by_user(
                      views.StaffHomeView.as_view(),  
                      views.ExternalUserClientView.as_view()),
              name='index'),
           # ...
      ]
      

      【讨论】:

        猜你喜欢
        • 2011-10-03
        • 1970-01-01
        • 2010-10-15
        • 1970-01-01
        • 2018-03-12
        • 2020-08-03
        • 1970-01-01
        • 2020-07-16
        • 2016-03-03
        相关资源
        最近更新 更多