Refer to User (a Foreign Key) to fill in argument's default value

时间:2016-10-20 13:18:27

标签: django

I have a structure similar to grocery shopping baskets. The user can have many baskets, and inside each basket, there are several bags holding fruits or other types of items.

I categorize each bag by item and color, that is, each bag only holds the same type of item with the same color. I keep track of how many of that item are there. So a bag may be: "3 Red Apples", another "60 Red Cherries"

Each user may choose a favorite color, and this is stored as a UserOption entry. I chose not to modify the built-in User model.

I want to simplify a function for computing the total number (quantity) of items of a given color in the desired basket. When no color is given, the favorite color is picked.

I have a working function, called get_total_default_none, that pulls the favorite color inside the function, but my question is:

Is it possible to retrieve the user's favorite color directly as the parameter's default (in the function signature), instead of running the query inside the function?

I think this (working) approach is ugly, needing to use the None as default, and then checking the UserOption.

When I try referring to user (as shown immediately below), and run the shell, I get django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.. I also tried (following advice in other questions) replacing User with django.conf.settings.AUTH_USER_MODEL. These did not work.

def get_total(self, color=UserOption.objects.filter(user=user)[0].favorite_color):
    # ...
    pass

My models are:

class Color(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=20)

    def __str__(self):
        return self.name

class UserOption(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    favorite_color = models.ForeignKey(Color, on_delete=models.CASCADE)

class Basket(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=30)

    # THIS FUNCTION WORKS BUT IS UGLY, I THINK
    def get_total_default_none(self, color=None):
        if color is None:
            try:
                color = UserOption.objects.filter(user=self.user)[0].favorite_color
            except IndexError:
                print("Could not retrieve user's favorite_color")

        total = 0
        bags = self.bag_set.filter(color=color)
        for bag in bags:
            total += bag.quantity
        return total

    # I HOPE TO GET SOMETHING LIKE THIS WORKING:    
    def get_total(self, color=UserOption.objects.filter(user=user)[0].favorite_color):
        # use code similar to above
        pass

    def __str__(self):
        return self.name

class Bag(models.Model):
    user      = models.ForeignKey(User, on_delete=models.CASCADE)
    item_name = models.CharField(max_length=30)
    color     = models.ForeignKey(Color, on_delete=models.CASCADE)
    quantity  = models.IntegerField()
    basket    = models.ForeignKey(Basket, on_delete=models.CASCADE)

    def __str__(self):
        return self.item_name

1 个答案:

答案 0 :(得分:0)

您可以直接访问该关系。

def get_total(self):
    color = self.user.useroption_set.first()
    if color:
        color = color.favorite_color
如果用户没有UserOptions,

first()将返回None。