183 lines
6.4 KiB
Python
183 lines
6.4 KiB
Python
import random
|
||
from django.db import models
|
||
from django.utils.timezone import now, localtime
|
||
import datetime
|
||
from utils import const
|
||
import utils
|
||
|
||
|
||
class Recipe(models.Model):
|
||
name = models.CharField(max_length=128)
|
||
recipe_type = models.CharField(max_length=32, default=const.RECIPE_TYPE_MEAT)
|
||
note = models.TextField(null=True)
|
||
rate = models.IntegerField(default=0)
|
||
difficulty = models.IntegerField(default=0)
|
||
|
||
def serialize(self, verbose=False):
|
||
data = {'id': self.id, 'name': self.name, 'recipe_type': self.recipe_type}
|
||
if verbose:
|
||
data.update({'difficulty': self.difficulty, 'rate': self.rate, 'note': self.note})
|
||
|
||
return data
|
||
|
||
@classmethod
|
||
def create_from_str(cls, content):
|
||
content = content.strip()
|
||
if not content:
|
||
return
|
||
name, *data = content.split(' ')
|
||
recipe_type = rate = difficulty = None
|
||
keys = [recipe_type, rate, difficulty]
|
||
for x in range(len(data)):
|
||
keys[x] = data[x]
|
||
recipe_type, rate, difficulty = keys
|
||
|
||
if recipe_type == '肉':
|
||
recipe_type = const.RECIPE_TYPE_MEAT
|
||
elif recipe_type == '菜':
|
||
recipe_type = const.RECIPE_TYPE_VEGETABLE
|
||
elif recipe_type == '汤':
|
||
recipe_type = const.RECIPE_TYPE_SOUP
|
||
else:
|
||
recipe_type = const.RECIPE_TYPE_MEAT
|
||
if rate:
|
||
try:
|
||
rate = int(rate)
|
||
except:
|
||
rate = 0
|
||
else:
|
||
rate = 0
|
||
if difficulty:
|
||
try:
|
||
difficulty = int(difficulty)
|
||
except:
|
||
difficulty = 0
|
||
else:
|
||
difficulty = 0
|
||
recipe = cls.objects.create(name=name, recipe_type=recipe_type, rate=rate, difficulty=difficulty)
|
||
return recipe
|
||
|
||
@property
|
||
def display_recipe_type(self):
|
||
if self.recipe_type == const.RECIPE_TYPE_VEGETABLE:
|
||
return '菜'
|
||
elif self.recipe_type == const.RECIPE_TYPE_MEAT:
|
||
return '肉'
|
||
elif self.recipe_type == const.RECIPE_TYPE_SOUP:
|
||
return '汤'
|
||
return '肉'
|
||
|
||
@property
|
||
def display_rate(self):
|
||
return '🍚' * self.rate
|
||
|
||
@property
|
||
def display_difficult(self):
|
||
return '⭐️' * self.difficulty
|
||
|
||
def construct_lart_card(self):
|
||
|
||
data = {
|
||
"config": {"wide_screen_mode": True},
|
||
"header": {"title": {"tag": "plain_text", "content": self.name}, "template": "blue"},
|
||
"elements": [
|
||
{
|
||
"tag": "markdown",
|
||
"content": "**类型**:%s\n**评分**:%s\n**难度**:%s"
|
||
% (self.display_recipe_type, self.display_rate, self.display_difficult),
|
||
},
|
||
{
|
||
"tag": "action",
|
||
"actions": [
|
||
{
|
||
"tag": "button",
|
||
"text": {"tag": "plain_text", "content": "查看"},
|
||
"multi_url": {
|
||
"url": "https://recipe.tunpok.com/recipe/%s" % self.id,
|
||
"android_url": "https://recipe.tunpok.com/recipe-mobile/recipe/%s" % self.id,
|
||
"ios_url": "https://recipe.tunpok.com/recipe-mobile/recipe/%s" % self.id,
|
||
"pc_url": "https://recipe.tunpok.com/recipe/%s" % self.id,
|
||
},
|
||
"type": "primary",
|
||
},
|
||
{"tag": "button", "text": {"tag": "plain_text", "content": "删除"}, "type": "danger"},
|
||
],
|
||
},
|
||
],
|
||
}
|
||
return data
|
||
|
||
|
||
class DailyRecipe(models.Model):
|
||
recipes = models.ManyToManyField(Recipe)
|
||
date = models.DateField()
|
||
meal_type = models.CharField(max_length=32, default=const.DAILY_RECIPE_MEAL_TYPE_SUPPER)
|
||
|
||
def generate_recipe(self, prev_recipes=None, ignore_prev=False):
|
||
if not prev_recipes:
|
||
prev_recipes = []
|
||
if ignore_prev:
|
||
prev_recipes = []
|
||
|
||
recipes = []
|
||
retry = 5
|
||
|
||
# meat
|
||
for x in range(0, 2):
|
||
while True:
|
||
recipe = Recipe.objects.filter(recipe_type=const.RECIPE_TYPE_MEAT).order_by('?').first()
|
||
if recipe and recipe.id not in recipes and recipe.id not in prev_recipes:
|
||
recipes.append(recipe.id)
|
||
break
|
||
else:
|
||
retry -= 1
|
||
if retry <= 0:
|
||
retry = 5
|
||
break
|
||
|
||
# vegetable
|
||
for x in range(0, 1):
|
||
while True:
|
||
recipe = Recipe.objects.filter(recipe_type=const.RECIPE_TYPE_VEGETABLE).order_by('?').first()
|
||
if recipe and recipe.id not in recipes and recipe.id not in prev_recipes:
|
||
recipes.append(recipe.id)
|
||
break
|
||
else:
|
||
retry -= 1
|
||
if retry <= 0:
|
||
retry = 5
|
||
break
|
||
|
||
# soup
|
||
if random.randint(0, 2):
|
||
recipe = Recipe.objects.filter(recipe_type=const.RECIPE_TYPE_SOUP).order_by('?').first()
|
||
# if recipe not in recipes and recipe not in prev_recipes:
|
||
if recipe:
|
||
recipes.append(recipe.id)
|
||
|
||
self.recipes.set(Recipe.objects.filter(id__in=recipes))
|
||
|
||
def serialize(self):
|
||
data = {const.RECIPE_TYPE_MEAT: [], const.RECIPE_TYPE_VEGETABLE: [], const.RECIPE_TYPE_SOUP: []}
|
||
for key_, value_ in data.items():
|
||
for recipe in self.recipes.filter(recipe_type=key_).order_by('id'):
|
||
value_.append(recipe.serialize())
|
||
|
||
date = now()
|
||
date = date.replace(year=self.date.year, month=self.date.month, day=self.date.day, hour=0, minute=0)
|
||
data['date'] = utils.timestamp_of(utils.day_start(date))
|
||
data['id'] = self.id
|
||
return data
|
||
|
||
@classmethod
|
||
def get_week_recipe_data(cls):
|
||
today = localtime()
|
||
week_start = (today - datetime.timedelta(days=today.weekday())).date()
|
||
week_end = week_start + datetime.timedelta(days=6)
|
||
daily_recipes = cls.objects.filter(date__gte=week_start, date__lte=week_end).order_by('date')
|
||
data = [{}] * (7 - len(daily_recipes))
|
||
|
||
for daily_recipe in daily_recipes:
|
||
data.append(daily_recipe.serialize())
|
||
return data
|