有效的Django数据库建模

时间:2014-03-09 19:22:04

标签: django django-models django-templates

我想为以下应用程序建模:所有者拥有不同的商店,每个商店都有一些客户和一些为该商店工作的员工;同一个员工可以在属于同一所有者的不同商店工作,也可以在属于不同所有者的商店工作。 只有所有者和员工才能登录系统,客户无法登录。 我创建了以下模型并将用户添加到不同的组(使用Django Auth系统和允许自定义用户模型的1.6.2版本),但我关注应用程序正在执行的查询数量,我真的不确定关于建模。 最大的困难是,如果业主有各种商店,当业主登录系统时,他需要选择哪个商店正在使用,也可以添加相关的员工和客户(只有商店的所有者可以添加员工和客户)

from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin

class CustomUser(AbstractBaseUser, PermissionsMixin):

    email = models.CharField(max_length=254,
        unique=True)
    firstname = models.CharField(max_length=64)
    lastname = models.CharField(max_length=64)
    ...
    objects = CustomUserManager()

    USERNAME_FIELD = 'email'
    ...        

class Shop(models.Model):
    name = models.CharField(...)
    city = ...
    address = ...

class Customer(models.Model):
    shop = models.ForeignKey(Shop)
    ...

class Employee(CustomUser):
    shops = models.ManyToManyField(Shop)
    ...

class Owner(CustomUser):
    shops = models.ManyToManyField(Shop)
    ...

现在,当员工或所有者使用他的电子邮件登录系统时,应用程序需要显示包含可用商店的选择框,并且用户的选择需要传递到应用程序的每个视图:如何操作我这样做?我想不能是POST,因为我在应用程序中有其他表单,应该是GET请求,但是我需要验证的每个请求都是Shop属于所有者或员工(增加查询数量) 。我已经开发了应用程序的一个重要部分(例如订单)但我回到了开头;我不知道我所做的所有模型是否应与商店或所有者相关。 任何建议表示赞赏。感谢。

2 个答案:

答案 0 :(得分:0)

我现在我的例子可能不完美,但我认为它将澄清你应该如何使用Django。 (另请阅读:https://docs.djangoproject.com/en/1.6/topics/db/managers/

class ShopsUser(AbstractBaseUser, PermissionsMixin):

    email = models.CharField(max_length=254,
        unique=True)
    firstname = models.CharField(max_length=64)
    lastname = models.CharField(max_length=64)
    ...
    objects = CustomUserManager()

    USERNAME_FIELD = 'email'
    ...
    priviledge_flag = models.CharField(choices=(('o', 'owner'), ('e', 'employe'), ('c', 'customer'))

class Customer(models.Model):
    shop = models.ForeignKey(Shop)

class Shop(models.Model):
    customers = models.ForeignKey(Customer, related_name='shops')
    admins = models.ManyToMany(ShopsUser, related_name='managed_shops')

现在,您可以使用已登录的用户(使用会话)查看所有数据:

class SomeView(View):
    def get(self, *args, **kwargs):
        admin = self.request.user
        all_singed_in_admin_shops = admin.managed_shops.all()
        first_shop = all_singed_in_admin_shops[0]
        first_shop_customers = first_shop.customers.all()

答案 1 :(得分:0)

我使用基于Django认证中间件的会话和自定义中间件解决了类似的问题:

shop/middleware.py

from django.utils.functional import SimpleLazyObject
from <appname> import shop

def get_shop(request):
    if not hasattr(request, '_cached_shop'):
        request._cached_shop = shop.get_shop(request)
    return request._cached_shop


class ShopMiddleware(object):
    def process_request(self, request):
        assert hasattr(request, 'session'), "The Shop middleware requires session middleware to be installed. Edit your MIDDLEWARE_CLASSES setting to insert 'django.contrib.sessions.middleware.SessionMiddleware'."

        request.shop = SimpleLazyObject(lambda: get_shop(request))

shop/__init__.py

from django.core.exceptions import ObjectDoesNotExist
from <appname>.shop.models import Shop

SHOP_SESSION_KEY = '_session_shop_id'

def get_shop(request):
    try:
        shop_id = request.session[SHOP_SESSION_KEY]
        shop = Shop.objects.get(id=shop_id)
        return shop
    except (KeyError, ObjectDoesNotExist):
        return None

def switch_shop(request, shop):
    if not isinstance(request.user, CustomUser):
        request.session[SHOP_SESSION_KEY] = None
    if request.user.shops.filter(id=shop.id).exists():
        request.session[SHOP_SESSION_KEY] = shop.id

然后只需将ShopMiddleware添加到您的中间件类中,request.shop将始终指向当前商店(如果选择了一个)。

在我的情况下,我还编写了一个类似于login_required的视图包装器,它重定向到一个页面,允许在需要时选择商店而不选择商店。看看login_required的{​​{3}},找到正确方向的好指针。

编辑:您仍需要选择商店,因此请撰写一个向用户显示正确选项的视图,并让其调用switch_shop(request, shop)。如果商店是当前用户的有效商店,则会话将被设置为该商店,直到它被更改或用户退出为止。