# coding=utf8 from __future__ import unicode_literals, absolute_import, print_function import json import random import datetime from collections import defaultdict from django.conf import settings from django.db.models import Count, Max, Q, Sum from django.utils.html import escape from gm_types.gaia import DIARY_ORDER_TYPE from gm_types.gaia import DIARY_CONTENT_LEVEL from gm_types.gaia import TAG_TYPE from gm_types.gaia import SERVICE_COMMENT_OPTION from gm_types.error import ERROR as CODES from gm_rpcd.all import bind from utils.rpc import gen, rpc_client, logging_exception, assert_uint, get_current_user from talos.statistic import diary_view_increase_num, topic_view_increase_num from talos.rpc import bind_context from talos.decorators import list_interface from talos.cache.base import hospital_topics_num_cache, diary_base_info_cache from talos.libs.datetime_utils import get_datetime from talos.libs.datetime_utils import get_timestamp from talos.manager.diary import diary_list_manager from talos.models.diary import Diary, DiaryExtra, MAX_STICK_PRIORITY, DEFAULT_STICK_PRIORITY, DiaryVote from talos.models.topic import Problem from talos.services import GoodsService, UserService from talos.services import TagService from talos.services import get_location_tag_id_by_city_id from talos.services import get_user_from_context from talos.libs.image_utils import get_full_path def _get_topic_pageview(id): return Problem.get_view_amount_of_id(id) # @bind_context('talos/diaries') @bind_context('diary/list') @list_interface(offset_name='start_num', limit_name='count', element_model=Diary, element_func_list=[Diary.get_diary_info, ]) def get_diary_list( ctx, count=10, start_num=0, target_user_id=None, service_id=None, hospital_ids=None, doctor_id=None, hospital_id=None, province_id='nationwide', order_by=None, is_pc=False, filter_tag_ids=None, area_id=None, wiki_id=None, body_part_id=None, sub_item_id=None, has_before_cover=False, has_after_cover=False, need_service=True, ): """话题列表 count: 每次请求记录条数, 默认为10 start_num: 起始条数, 默认为0 service_id: 福利相关日记本筛选 query: 日记本搜索, 从标题和内容中进行搜索 doctor_id: 医生筛选 hospital_id: 机构筛选 province_id: 省份筛选, 默认为全国 NOTE: wiki_id=None, body_part_id=None, sub_item_id=None for compatible only v 7.6.25 新加参数 bool类型 has_before_cover 判断封面 是否有 before 图片 has_after_cover 判断封面 是否有 after 图片 """ user = get_user_from_context(ctx) if order_by is None: if doctor_id or hospital_id: order_by = DIARY_ORDER_TYPE.CREATE_TIME else: order_by = DIARY_ORDER_TYPE.LAST_UPDATE_TIME filters = {} if province_id and province_id != 'nationwide': filters['province_tag_id'] = province_id if area_id: filters['area_tag_id'] = area_id if 'province_tag_id' in filters: del filters['province_tag_id'] if doctor_id: filters['doctor_id'] = doctor_id if hospital_id: filters['hospital_id'] = hospital_id if hospital_ids: filters['hospital_ids'] = [hospital_ids] if target_user_id: filters['user_id'] = target_user_id if service_id: filters['service_id'] = service_id filters['service_id'] = assert_uint(filters['service_id']) tag_ids = [] if filter_tag_ids: if not isinstance(filter_tag_ids, list): filter_tag_ids = [filter_tag_ids] tag_ids.extend(filter_tag_ids) if tag_ids: filters['tag_ids'] = tag_ids if has_before_cover: filters["has_before_cover"] = True if has_after_cover: filters["has_after_cover"] = True diary_ids = rpc_client['api/diary/filter_diary'](offset=start_num, size=count, sort_type=order_by, filters=filters).unwrap() ids = diary_ids["diary_ids"] topic_ids = [] result = diary_list_manager.get_diary_list_by_diary_ids_with_doctor_hospital_name( ids=ids, viewer_user_id=user.id, is_online=True, need_service=need_service ) for r in result: topic_ids.append(r['latest_topic_id']) topic_view_increase_num(topic_ids) diary_view_increase_num(ids) return result @bind_context('diary/list_v2') @list_interface( offset_name='start_num', limit_name='count', element_model=Diary, element_func_list=[Diary.get_diary_info, ] ) def diary_filter_list(ctx, start_num=0, count=10, service_id=None, doctor_id=None, exclude_user=[], sort_type=DIARY_ORDER_TYPE.SERVICE_RELATED): """ 获取美购相关的医生的所有日记 当前美购相关的排在前面 start_num 起始位置 count 数量 service_id 相关联美购id(int) exclude_user 需要排除的用户 """ filters = {} user = get_user_from_context(ctx) if doctor_id: filters['doctor_id'] = doctor_id if service_id: filters['service_id'] = service_id result = rpc_client['api/diary/filter_diary']( offset=start_num, size=count, sort_type=sort_type, filters=filters, nfilters={ 'user_ids': exclude_user, }, sort_params={ 'service_id': service_id, }, expose_total=True).unwrap() ids = result['diary_ids'] resp = { 'diaries': [], 'total': result['total'], } result = diary_list_manager.get_diary_list_by_diary_ids(ids=ids, viewer_user_id=user.id) diary_ids = list(map(lambda x: x['id'], result)) diary_view_increase_num(diary_ids) resp['diaries'] = result return resp @bind_context('diary/service_detail_list') @list_interface( offset_name='start_num', limit_name='count', element_model=Diary, element_func_list=[Diary.get_diary_info, ] ) def diary_filter4service_detail(ctx, start_num=0, count=10, service_id=None): """美购详情页相关日记本 """ resp = { 'diaries': [], 'total': 0, } service = GoodsService.get_service_doctor_info_by_id(id=service_id) if not service: return resp elif not (service['doctor_id'] and service['doctor_user_id']): return resp target_bodypart_id, target_tags_ids = TagService.get_filter_options_for_filter_service_diaries(service_id) if target_bodypart_id is None: return resp # 筛选一级tag相同的 filters = { 'tag_ids': [target_bodypart_id], 'service.doctor_id': service['doctor_id'], } nfilters = {'user_ids': [service['doctor_user_id']]} result = rpc_client['api/diary/filter_diary']( offset=start_num, size=count, sort_type=DIARY_ORDER_TYPE.SERVICE_DETAIL, filters=filters, nfilters=nfilters, sort_params={'same_tag_ids_count': target_tags_ids}, expose_total=True).unwrap() ids = result['diary_ids'] resp['total'] = result['total'] if ids: diary_view_increase_num(ids) user = get_user_from_context(ctx) result = diary_list_manager.get_diary_list_by_diary_ids(ids=ids, viewer_user_id=user.id) resp['diaries'] = result return resp @bind('diary/list/related') @list_interface( offset_name='start_num', limit_name='count', element_model=Diary, element_func_list=[Diary.get_diary_info, ] ) def diary_related(diary_id, count=3, start_num=0, exclude_user=[]): """ 当前日记本tag,任意选取一个(第一个),其它日记本有此tag的,即为相关日记 排除自己的日记 :param diary_id: :param count: :param start_num: :return: 相关日记本列表 """ try: diary = Diary.objects.get(id=diary_id) except Diary.DoesNotExist: return None tags = list(filter(lambda x: x.tag_type in [TAG_TYPE.ITEM_WIKI, TAG_TYPE.BODY_PART_SUB_ITEM], diary.tags)) tag = tags and tags[0] if not tag: return None _es_fetch_count = int(count * 1.6) diary_ids = rpc_client['api/diary/filter_diary']( offset=start_num, size=_es_fetch_count, sort_type=DIARY_ORDER_TYPE.YOU_MAY_LIKE, filters={ 'tag_ids': [tag.id, ], 'has_cover': True, }, nfilters={ 'id': diary_id, 'user_ids': exclude_user, }).unwrap() ids = diary_ids["diary_ids"] result = diary_list_manager.get_diary_list_by_diary_ids(ids=ids) result = { 'diaries': result[:count], } return result @bind_context("diary/filter") @list_interface(offset_name='offset', limit_name='limit', element_model=Diary, element_func_list=[Diary.get_diary_info]) def api_filter_diary(ctx, order_by=DIARY_ORDER_TYPE.LAST_UPDATE_TIME, filters={}, offset=0, limit=10, simple=True, with_count=False, need_service_item_info=False): diary_ids = rpc_client['api/diary/filter_diary']( offset=offset, size=limit, sort_type=order_by, filters=filters, expose_total=with_count ).unwrap() ids = diary_ids["diary_ids"] diary_view_increase_num(ids) user = get_user_from_context(ctx) result = diary_list_manager.get_diary_list_by_diary_ids( ids=ids, viewer_user_id=user.id, need_service_item_info=need_service_item_info ) if not with_count: return result return { 'diaries': result, 'total_count': diary_ids['total'], } @bind_context("diary/index") @list_interface(offset_name='offset', limit_name='limit', element_model=Diary) def diary_index( ctx, offset=0, limit=10, filters={'is_headline': True}, sort_type=DIARY_ORDER_TYPE.LAST_UPDATE_TIME, current_city_id=None ): """get diary list for index page. TODO: cache this page """ user = get_user_from_context(ctx) _, city_tagid = get_location_tag_id_by_city_id(current_city_id) if city_tagid is not None: sort_params = {'user_city_tag_id': city_tagid} else: sort_params = None result = {} result["diaries"] = [] filters['has_cover'] = True diary_ids = rpc_client['api/diary/filter_diary']( offset=offset * 2, size=limit * 2, filters=filters, sort_params=sort_params, sort_type=sort_type ).unwrap()['diary_ids'] random.shuffle(diary_ids) diary_ids = diary_ids[:limit] diary_info = diary_list_manager.get_diary_list_by_diary_ids(diary_ids, user.id) result['diaries'] = diary_info diary_view_increase_num(diary_ids) return result @bind_context("diary/index/mix") @list_interface(offset_name='offset', limit_name='limit', element_model=Diary) def diary_index_mix(ctx, offset=0, limit=10, filters={}, current_city_id=None, sort_type=None, **kwargs): """get diary list for index page. TODO: cache this page """ user = get_user_from_context(ctx) user_city_tag_id = user.city_tag_id page = kwargs.get("page") scale = settings.DIARY_RANDOM_SCALE.get(current_city_id, 2) if user_city_tag_id: user_city_tag_id = assert_uint(user_city_tag_id) country_tagid, city_tagid = get_location_tag_id_by_city_id(current_city_id) user_city_tag_id = city_tagid and city_tagid or user_city_tag_id if user_city_tag_id is not None: sort_params = {'user_city_tag_id': user_city_tag_id} else: sort_params = None result = {} result["diaries"] = [] # 先保留原逻辑代码,防止产品改回相似逻辑 # diary_ids_1 = filter_diary( # offset=offset, # size=limit, # sort_params=sort_params, # sort_type=DIARY_ORDER_TYPE.INDEX # )['diary_ids'] # # diary_ids_2 = filter_diary( # offset=offset + 50, # size=60, # sort_params=sort_params, # sort_type=DIARY_ORDER_TYPE.INDEX # )['diary_ids'] # random.shuffle(diary_ids_1) # random.shuffle(diary_ids_2) # # limit_1 = int(0.5 * limit) # limit_2 = limit - limit_1 # diary_ids = diary_ids_1[:limit_1] + diary_ids_2[:limit_2] # random.shuffle(diary_ids) # diary_ids = diary_ids[:limit] ###################### if page is not None: offset = page * 20 size = 20 else: offset *= scale size = limit * scale diary_ids = rpc_client['api/diary/filter_diary_index_mix']( offset=offset, size=size, filters={'city_id': current_city_id, 'content_level_is_good': True}, sort_params=sort_params, ).unwrap() random.shuffle(diary_ids) diary_ids = diary_ids[:limit] diary_info = diary_list_manager.get_diary_list_by_diary_ids(diary_ids, user.id) result['diaries'] = diary_info diary_view_increase_num(diary_ids) return result def get_my_diary_list_common_func(user, start_num, count, topics_is_null): """ 获取我的日记本列表公共方法 :param user: :param start_num: :param count: :param topics_is_null: :return: """ query = Q(user_id=user.id, is_online=True) if not topics_is_null: query &= Q(topics__isnull=False) diaries = Diary.objects.filter(query) diaries = diaries.distinct() diaries = diaries.order_by('-last_modified') if not topics_is_null: diaries = list(filter(lambda d: d.topics.filter(is_online=True).filter(flag='n').exists(), diaries)) diaries = diaries[start_num: start_num + count] return diaries @bind("diary/my") @list_interface(offset_name='start_num', limit_name='count', element_model=Diary) def my_diary_list(start_num=0, count=10, topics_is_null=False): """ 我的日记本列表 :param ctx: :param start_num: :param count: :param topics_is_null: whether add the empty diaries :return: """ user = get_current_user() if not user: return gen(CODES.LOGIN_REQUIRED) diaries = get_my_diary_list_common_func(user, start_num, count, topics_is_null) result = diary_list_manager.get_diary_list_by_diary_objs(diaries, viewer_user_id=user.id) diary_ids = [d.id for d in diaries] diary_view_increase_num(diary_ids) return {'diaries': result} @bind("diary/my_v2") @list_interface(offset_name='start_num', limit_name='count', element_model=Diary) def my_diary_list_v2(start_num=0, count=10, topics_is_null=False): """ 我的日记本列表 新接口,主要是上个接口返回的数据太多了……严重影响性能!!!! :param start_num: :param count: :param topics_is_null: :return: """ user = get_current_user() if not user: return gen(CODES.LOGIN_REQUIRED) diaries = get_my_diary_list_common_func(user, start_num, count, topics_is_null) result = diary_list_manager.get_simple_diary_list_by_diary_objs(diaries) diary_ids = [d.id for d in diaries] diary_view_increase_num(diary_ids) return {'diaries': result} def _get_topic_image(topic): image = topic.post_operation_image if not image: image = topic.pre_operation_image return image @bind("diary/recent") @list_interface(offset_name='start_num', limit_name='count') def diary_recent(start_num=0, count=50, is_page=False): """v5.3.0 我的日记本列表 """ def handle_cover(diary): if diary.post_operation_image: return diary.post_operation_image newest_cover = diary.newest_cover() if newest_cover == settings.DIARY_COVER_DEFAULT: return '' else: return newest_cover def handle_doctor_city(diary): # TODO CR 需要通知产品修改逻辑 if diary.hospital_id and diary.hospital.city: # TODO city return diary.hospital.city.name # TODO city for tag in diary.tags: if tag.tag_type == TAG_TYPE.CITY: return tag.name return '' def handle_titles(diaries): service_ids = list(map(lambda x: x.service_id, diaries)) services = GoodsService.get_service_by_service_ids(service_ids) services_dict = {s['id']: s for s in services} result = {} for d in diaries: if d.service_id: service = services_dict.get(d.service_id, None) result[d.id] = service and service['name'] else: tags = [ tag.name for tag in d.tags if tag.tag_type in [TAG_TYPE.ITEM_WIKI, TAG_TYPE.BODY_PART_SUB_ITEM] ][:MAX_TAGS_COUNT] result[d.id] = tags and tags[0] or d.title or u'我的更美日记' return result def handle_subtitles(diaries): """ title: 美购所属地和医院(医生)(优先取医院), 无美购关联返回空 """ service_ids = list(map(lambda x: x.service_id, diaries)) diary_show_info = GoodsService.get_diary_show_info_by_service_ids(service_ids) result = {} for diary in diaries: if not diary.service_id: result[diary.id] = u'' else: info = diary_show_info[diary.service_id] city_name = info['city_name'] hospital_name = info['hospital_name'] doctor_name = info['doctor_name'] if city_name and (hospital_name or doctor_name): result[diary.id] = u'{}@{}'.format(city_name, doctor_name or hospital_name) else: result[diary.id] = u'' return result user = get_current_user() if not user: return gen(CODES.LOGIN_REQUIRED) MAX_TAGS_COUNT = 3 all_diaries = Diary.objects.filter(user_id=user.id, is_online=True) service_diaries = all_diaries.filter(service_id__isnull=False).order_by('-last_modified', '-id') normal_diaries = all_diaries.filter(service_id__isnull=True).order_by('-last_modified', '-id') service_diaries_num = service_diaries.count() if is_page: service_diaries = service_diaries[start_num:start_num + count] if service_diaries.count() == 0: start_num = start_num - service_diaries_num normal_diaries = normal_diaries[start_num:start_num + count] elif service_diaries.count() < count: count = count - service_diaries.count() normal_diaries = normal_diaries[0:count] else: normal_diaries = [] else: # NOTE: return 50 diaries at most service_diaries = service_diaries[start_num:start_num + count] # NOTE: return 50 diaries at most normal_diaries = normal_diaries[start_num:start_num + count] diary_set = list(service_diaries) + list(normal_diaries) diaries = [] diary_titles = handle_titles(diary_set) diary_subtitles = handle_subtitles(diary_set) for diary in diary_set: tags = [ tag.name for tag in diary.tags if tag.tag_type in [TAG_TYPE.ITEM_WIKI, TAG_TYPE.BODY_PART_SUB_ITEM] ][:MAX_TAGS_COUNT] diaries.append( { 'is_service_diary': True if diary.service_id else False, 'id': diary.id, 'topics_num': diary.topic_num, 'tags': tags, 'title': diary_titles[diary.id], 'subtitle': diary_subtitles[diary.id], # Add since v6.9.5 'like_num': diary.like_num, 'image': handle_cover(diary), 'created_time': get_timestamp(diary.created_time), 'last_modified': get_timestamp(diary.last_modified), 'operation_time': get_timestamp(diary.operation_time), # 用户选择的治疗时间 'comment_count': ( diary.rate_count if diary.order_id else 0 ), } ) return {'result': diaries} @bind('diary/list_for_doctor') @list_interface(offset_name='start_num', limit_name='count', element_model=Diary) def diary_list(start_num=0, count=10, doctor_id=None): """ 医生的日记本列表(案例列表) """ user = get_current_user() if not user: return gen(CODES.LOGIN_REQUIRED) diary_queryset = Diary.objects.filter( doctor_id=doctor_id, is_online=True, topics__isnull=False, topics__flag='n', topics__is_online=True ).distinct().order_by('-sticky_post', '-id').values_list('id', flat=True) diary_ids = list(diary_queryset) result = {'total_count': len(diary_ids), 'diaries': []} sliced_diary_ids = diary_ids[start_num: start_num + count] diary_data = diary_list_manager.get_diary_list_by_diary_ids_with_doctor_hospital_name( sliced_diary_ids, viewer_user_id=user.id ) result['diaries'] = diary_data return result @bind('diary/list_for_bz_backend') def list_for_bz_backend(service_ids, start_num=0, count=10, created_time_gte=None, created_time_lt=None, order_by=None, is_stick_priority=None, diary_or_user_ids=None, is_import=None): init_query = query = Q(service_id__in=service_ids) & \ Q(extra_info__isnull=False) if created_time_gte: created_time_gte = get_datetime(created_time_gte) query &= Q(created_time__gte=created_time_gte) if created_time_lt: created_time_lt = get_datetime(created_time_lt) query &= Q(created_time__lt=created_time_lt) if is_stick_priority == 0: query &= Q(stick_priority=DEFAULT_STICK_PRIORITY) elif is_stick_priority == 1: query &= Q(stick_priority__lte=MAX_STICK_PRIORITY) if is_import == 0: query &= Q(is_import=False) elif is_import == 1: query &= Q(is_import=True) if diary_or_user_ids and isinstance(diary_or_user_ids, list): query &= (Q(id__in=diary_or_user_ids) | Q(user_id__in=diary_or_user_ids)) # 排序 # diary.topic_num/view_num/vote_num/reply_num # extra_info__topic_count/reply_count/vote_count/total_pv # 针对统计表中的字段排序 diary_extra_order = { DIARY_ORDER_TYPE.TOPIC_COUNT: ('', "topic_count"), DIARY_ORDER_TYPE.TOPIC_COUNT_DESC: ('-', "topic_count"), DIARY_ORDER_TYPE.VOTE_COUNT: ('', "vote_count"), DIARY_ORDER_TYPE.VOTE_COUNT_DESC: ('-', "vote_count"), DIARY_ORDER_TYPE.TOTAL_PV: ('', "total_pv"), DIARY_ORDER_TYPE.TOTAL_PV_DESC: ('-', "total_pv"), } # 针对diary表中的字段排序 diary_order = { DIARY_ORDER_TYPE.REPLY_COUNT: ('', "reply_num"), DIARY_ORDER_TYPE.REPLY_COUNT_DESC: ('-', "reply_num"), DIARY_ORDER_TYPE.CONCONTENT_LEVEL: ('', "content_level"), DIARY_ORDER_TYPE.CONCONTENT_LEVEL_DESC: ('-', "content_level"), } order_by = str(order_by) if order_by and isinstance(order_by, int) else None order_type, order_field = diary_extra_order.get(order_by, (None, None)) if order_field: diaries = Diary.objects.filter(query). \ order_by("%sextra_info__%s" % (order_type, order_field)) else: order_type, order_field = diary_order.get(order_by, (None, None)) if order_field: diaries = Diary.objects.filter(query). \ order_by("%s%s" % (order_type, order_field)) else: diaries = Diary.objects.filter(query) # 返回置顶信息 stick_info_list = [] stick_map = {} stick_info = list(Diary.objects.filter(init_query).filter(stick_priority__lte=MAX_STICK_PRIORITY).values('stick_priority', 'service_id').all()) [stick_map.setdefault(item['service_id'], []).append(item['stick_priority']) for item in stick_info] for k,v in stick_map.items(): stick_info_list.append({ 'service_id':k, 'stick_priorities': sorted(list(set(v))) }) total = diaries.count() diaries = diaries[start_num: start_num + count] result = diary_list_manager.get_diary_list_by_diary_objs(diaries) return { 'diaries': result, 'count': total, 'stick_info': stick_info_list } @bind('diary/diary_info_by_service_ids') def diary_info_by_service_ids(service_ids, count_only=False, other_query={}): query = Q() #Query是针对DiaryCheck的 if "content_level" in other_query: query = Q(content_level__in=other_query.get("content_level", [])) if count_only: diaries = Diary.objects.filter( # refer api.models.Service.diaries_count service_id__in=service_ids, is_online=True, topics__isnull=False, topics__flag='n', topics__is_online=True ) # with topics joined result = { service_id: { 'service_id': service_id, 'diary_count': 0, 'diaries': [] } for service_id in service_ids } q = diaries.values('service_id').annotate(diary_count=Count('id', distinct=True)) for dcnt in q: result[dcnt['service_id']]['diary_count'] = dcnt['diary_count'] return list(result.values()) else: diaries = Diary.objects.filter( # refer api.models.Service.diaries_count query, service_id__in=service_ids, is_online=True, ) result, temp_save = [], [] #每一个日记帖就返回一个数据, temp_save过滤重复数据 for item in diaries: if item.id not in temp_save: result.append({ "diary_id": item.id, "diary_title": item.title, }) temp_save.append(item.id) return result @bind_context('diary/list_data_get_by_ids') def talos_diary_list_data_get_by_ids(ctx, ids): assert len(ids) <= 100, 'too many diary_ids' user = get_user_from_context(ctx) result = diary_list_manager.get_diary_list_by_diary_ids(ids, viewer_user_id=user.id) diary_view_increase_num(ids) return {'diaries': result} @bind('diary/get_service_case_list') def talos_service_case(service_id, get_detail=True): diaries = Diary.objects.filter( service_id=service_id, is_online=True, topics__isnull=False, topics__flag='n', topics__is_online=True ).distinct() count = diaries.count() diaries = [] if get_detail: diaries = Diary.objects.filter( service_id=service_id, is_online=True, topics__isnull=False, topics__flag='n', topics__is_online=True ).distinct().order_by('-last_topic_add_time') ids = [] for diary in diaries: if len(ids) < 10: if diary.vote_num > 30: if diary.post_operation_image: ids.append(diary.id) diaries = diary_list_manager.get_diary_list_for_service_case(ids) return { 'count': count, 'diaries': diaries } @bind('diary/get_service_image') def talos_service_diary_image(service_id, start_num, count): ids = Diary.objects.filter( service_id=service_id, is_online=True ).exclude(post_operation_image='').order_by('-last_modified').values_list( 'id', flat=True )[start_num:start_num + count] result = diary_list_manager.get_diary_image_list_by_diary(ids) return result @bind('diary/special_recommend_list') @list_interface(offset_name='start_num', limit_name='count') def get_special_recommend_diaries(special_id, start_num, count): try: diary_ids = rpc_client['doris/search/get_diaries_by_special_id']( special_id=special_id, offset=start_num, size=count ).unwrap() except Exception as e: print(e) logging_exception() return [] diary_ids = diary_ids.get('diaries', []) result = [] if diary_ids: topic_ids = [] result = diary_list_manager.get_diary_list_by_diary_ids_with_doctor_hospital_name( ids=diary_ids ) for r in result: topic_ids.append(r['latest_topic_id']) topic_view_increase_num(topic_ids) diary_view_increase_num(diary_ids) return result @bind_context('diary/diary_list_for_index') def talos_diary_list_for_index(ctx, diary_ids, get_last_video=False): assert len(diary_ids) <= 100, 'too many diary_ids' user = get_user_from_context(ctx) diary_info = diary_list_manager.get_diary_list_by_diary_ids(diary_ids, user.id, get_last_video) diary_view_increase_num(diary_ids) return diary_info @bind_context('diary/simple_diary_list') def simple_diary_list(ctx, diary_ids, index=False): if not diary_ids: diary_ids = [] user = get_current_user() user_id = user and user.id or None diaries_info = diary_list_manager.list_diary_by_ids( diary_ids, user_id, index=index ) diary_view_increase_num(diary_ids) return diaries_info @bind('diary/list_diary_info') def list_diary_info(diary_ids): if not diary_ids: return [] cache_result_list = diary_base_info_cache.mget(list(map(lambda i: str(i), diary_ids))) result_dict, miss_ids = {}, [] for index, result_id in enumerate(diary_ids): result_string = cache_result_list[index] if result_string is not None: if type(result_string) == bytes: try: result_string = result_string.decode() except Exception: pass result_dict[result_id] = json.loads(result_string) else: miss_ids.append(result_id) if not miss_ids: return list(result_dict.values()) diary_objs = diary_list_manager._get_diaries_by_ids(miss_ids, is_online=True) diaries_info = diary_list_manager.list_diary_by_objs(diary_objs) diary_base_info_cache.mset({str(item["id"]): json.dumps(item) for item in diaries_info}) diaries_info.extend(result_dict) diary_view_increase_num(diary_ids) return diaries_info @bind('diary/get_comment_mixed') def get_diary_and_comment_mix(service_id, comment_option=None, sort_type=DIARY_ORDER_TYPE.SUGGEST, count=10, start_num=0, need_total_count=False): ''' 美购日记本和美购评价混合,http://wiki.wanmeizhensuo.com/pages/viewpage.action?pageId=4440205 :param service_id: :param comment_option: :param sort_type: :param count: :param start_num: :param need_total_count: :return: ''' order_ids = [] diary_dict, diary_list = {}, [] all_topic_count = 0 filters = {'service_id': service_id} if need_total_count: # for 美购详情页外显日记,必需5星,术前后图存在 all_diaries = Diary.objects.select_related('extra_info').filter(service_id=service_id, is_online=True).iterator() for diary in all_diaries: if hasattr(diary, 'extra_info'): all_topic_count += diary.extra_info.topic_count filters["has_before_cover"] = True filters["has_after_cover"] = True filters["vote_num_gt"] = 30 if comment_option == SERVICE_COMMENT_OPTION.WITHIMAGE: # 有图,筛选的是有图的日记本, added in 7.6.35 filters['has_cover'] = True if not comment_option or comment_option == SERVICE_COMMENT_OPTION.WITHIMAGE: # 1 全部和有图,通过日记本信息获取相应评论信息 filter_result = rpc_client['api/diary/filter_diary']( offset=start_num, size=count, sort_type=sort_type, filters=filters ).unwrap() if filter_result['diary_ids']: diary_list = Diary.objects.filter(id__in=filter_result['diary_ids']) index_dict = {k: i for i, k in enumerate(filter_result['diary_ids'])} # 将数据库查询出来的结果按照原有排序 diary_list = sorted(diary_list, key=lambda x: index_dict[x.id]) diary_dict = {item.order_id: item for item in diary_list if item.order_id} order_ids = list(diary_dict.keys()) start_num = 0 # 通过订单去查询评论,start_num 从0, try: comment_list = rpc_client['api/service/comment_list']( comment_option=comment_option, service_id=service_id, start_num=start_num, count=count, order_ids=order_ids, ).unwrap() except: logging_exception() comment_list = [] comment_order_id_dict = {comment['order_id']: comment for comment in comment_list} query_order_ids = list(comment_order_id_dict.keys()) if comment_option and comment_list: # 除以上1的情况,其他筛选需要通过评论来获取相应日记本信息 diary_obj = Diary.objects.filter(order_id__in=query_order_ids, is_online=True, topics__isnull=False, topics__flag='n', topics__is_online=True) diary_dict = {item.order_id: item for item in diary_obj if item.order_id} result_data = [] if not comment_option or comment_option == SERVICE_COMMENT_OPTION.WITHIMAGE: # 全部展示的是日记,只是关联上评论的评分和星星; # 有图,筛选的是有图的日记本, added in 7.6.35 for diary_obj in diary_list: data = { 'id': '', 'author': {}, 'comment_type': 1, # 日记本类型 'comment_data': { 'evaluate_point': diary_obj.rating, # 评论分值 'content': diary_obj.latest_topic and escape(diary_obj.latest_topic.answer) or '', # 评价内容 'post_date': diary_obj.last_modified.strftime("%Y-%m-%d"), 'imgs': diary_obj.cover, 'tags': diary_obj.tags_new_era, 'view_count': diary_obj.view_num, # 浏览量 'reply_count': diary_obj.reply_num, # 回复量 'vote_count': diary_obj.vote_num, # 点赞量 'diary_id': diary_obj.id, 'topic_count': diary_obj.extra_info.topic_count if hasattr(diary_obj, 'extra_info') else 0 # 日记帖数量 } } comment_item = comment_order_id_dict.get(diary_obj.order_id) if comment_item: data['id'] = comment_item['id'] data['author'] = comment_item['user_info'] data['comment_data']['evaluate_point'] = float('{0:.1f}'.format(comment_item['rating'])) if comment_item['rating'] else 0.0 data['comment_data']['post_date'] = comment_item['create_time'] if not comment_item['content_original_none']: # 评价内容/默认好评 > 日记帖内容 > 此用户没有填写评价 data['comment_data']['content'] = comment_item['content'] else: if not data['comment_data']['content']: data['comment_data']['content'] = comment_item['content'] if not data['comment_data']['imgs'] and comment_item['images']: data['comment_data']['imgs'] = [ { 'image_half': get_full_path(comment_item['images'][0], '-half'), 'desc': 'After', } ] else: diary_item_info = diary_obj.get_simple_diary() data['author'] = { 'user_id': diary_item_info['user_id'], 'last_name': diary_item_info['user_nickname'], 'user_portrait': diary_item_info['user_portrait'] } if comment_option == SERVICE_COMMENT_OPTION.WITHIMAGE: if data['comment_data']['imgs']: result_data.append(data) else: result_data.append(data) else: # 有筛选条件时,筛选的是评论,存在日记本,然后关联上日记本 for comment in comment_list: data = { 'id': comment['id'], 'author': comment['user_info'], 'comment_type': 0, # 评论类型 'comment_data': { 'evaluate_point': float('{0:.1f}'.format(comment['rating'])) if comment['rating'] else 0.0, # 评论分值 'content': comment['content'], # 评价内容 'post_date': comment['create_time'], 'imgs': [], 'tags': [], 'view_count': 0, # 浏览量 'reply_count': 0, # 回复量 'vote_count': 0, # 点赞量 'diary_id': '', 'topic_count': 0 # 日记帖数量 } } diary_item = diary_dict.get(comment['order_id']) if diary_item: data['comment_type'] = 1 data['comment_data']['imgs'] = diary_item.cover data['comment_data']['tags'] = diary_item.tags_new_era data['comment_data']['view_count'] = diary_item.view_num # 浏览量 data['comment_data']['reply_count'] = diary_item.reply_num # 回复量 data['comment_data']['vote_count'] = diary_item.vote_num # 点赞量 data['comment_data']['diary_id'] = diary_item.id data['comment_data']['topic_count'] = diary_item.extra_info.topic_count if hasattr(diary_item, 'extra_info') else 0 if comment['content_original_none'] and diary_item: # 无评价内容 latest_topic = diary_item.latest_topic content = latest_topic and escape(latest_topic.answer) or '' data['comment_data']['content'] = content if not data['comment_data']['imgs'] and comment['images']: data['comment_data']['imgs'] = [ { 'image_half': get_full_path(comment['images'][0], '-half'), 'desc': 'After', } ] result_data.append(data) return {'diary_and_comment': result_data, 'total': all_topic_count} @bind('diary/diary_filter_info') def talos_diary_get_filter_info(service_id=None, hospital_id=None, doctor_id=None, has_cover=False, need_topic_count=False): """ v 7.6.35 增加 目的: 获取美购,医生,医院等 相关的日记本下所有帖子的总数; 目前支持类型:美购,医院,医生;如有其他项目,请完善此接口 :param service_id: 美购id :param hospital_id: 医院id :param doctor_id: 医生id :param need_topic_count: 获取所有日记本下的帖子总数 :return: {} 字典类型 返回 日记本总数,日记本相关的帖子总数 """ filters = {} topic_count = None query = Q() result = { "diary_count": 0, "topic_count": 0, } if doctor_id: filters['doctor_id'] = doctor_id if hospital_id: filters['hospital_id'] = hospital_id topic_count = hospital_topics_num_cache.get(hospital_id) if service_id: filters['service_id'] = service_id query |= Q(service_id=service_id) if has_cover: filters['has_cover'] = has_cover diary_info = rpc_client['api/diary/filter_diary'](filters=filters, expose_total=True, sort_type=DIARY_ORDER_TYPE.LAST_UPDATE_TIME).unwrap() if need_topic_count: query &= Q(is_online=True) diary_ids = list(Diary.objects.filter(query).values_list("id", flat=True)) _counts = DiaryExtra.objects.filter(diary_id__in=diary_ids).aggregate(topic_count=Sum("topic_count")) topic_count = _counts.get("topic_count") result["diary_count"] = diary_info and diary_info.get("total", 0) or 0 result["topic_count"] = topic_count and int(topic_count) or 0 return result @bind('diary/get_diary_count') def get_diary_count(service_id=None, doctor_id=None, rating__gt=False, exclude_rating=False, exclude_post_img=False, is_online=False): if not service_id and not doctor_id: return {'count': 103} query = Q() if service_id: query &= Q(service_id=service_id) if is_online: query &= Q(is_online=is_online) if doctor_id: query &= Q(doctor_id=doctor_id) if rating__gt: query &= Q(rating__gt=0) not_query = Q() if exclude_rating: not_query &= Q(rating=0) if exclude_post_img: not_query &= Q(post_operation_image='') try: diary_obj = Diary.objects.filter(query) if not_query: diary_obj = diary_obj.exclude(not_query) re_count = diary_obj.distinct().count() except: logging_exception() re_count = 0 return {'count': re_count} @bind_context('diary/diary_list_for_darens') def diary_list_for_darens(ctx, daren_ids): # assert len(diary_ids) <= 100, 'too many diary_ids' result = dict.fromkeys(daren_ids, {}) try: diary_info = Diary.objects.filter(user_id__in=daren_ids, is_online=True).values('user_id').annotate(Max('id')) diary_ids = [diary['id__max'] for diary in diary_info] except: logging_exception() diary_ids = [] diaries = diary_list_manager.get_diary_list_for_pc_index_by_diary_ids(diary_ids) for diary in diaries: if diary['operation_time']: days = (datetime.datetime.now() - diary['operation_time']).days else: days = 0 result[str(diary['user_id'])] = { 'id': diary['id'], 'days': days, 'images': diary['images'], 'tag': diary['tags'][0] if diary['tags'] else {}, 'service_name': diary['service_name'] } return result def _get_topic_count_by_query(query, *fields): """ 该函数是接口: diary/get_topic_count 内部的公共方法,其他接口使用请先检查调取逻辑是否一致 通过query 获取数据,item 代表要查询的哪个字段 :param query: :param item: :return: """ query &= Q(is_online=True) diary_info = Diary.objects.filter(query).values_list(*fields) _data = dict() for info in diary_info: diary_id, item_id = info if item_id not in _data: _data[item_id] = [] _data[item_id].append(diary_id) diary_ids = [] for _, v in _data.items(): diary_ids.extend(v) _counts = DiaryExtra.objects.filter(diary_id__in=diary_ids).values_list("diary_id", "topic_count") topic_count_dic = {info[0]: info[1] for info in _counts} result = {} for k, v in _data.items(): result[str(k)] = sum(topic_count_dic.get(did, 0) for did in v) return result @bind("diary/get_topic_count") def get_topic_count(service_ids=None): """ 为满足需求:批量计算日记贴数而新增的接口,目前先支持美购,后续需要再增加。 PS: 完善接口或调用,一定要注意,该接口的设计,仅支持单一条件的查询!!! :param service_ids: list :return: """ result = { "services": {}, } status = dict() # 数据的状态 _ids = set() data_slice = 5 # 数据切片,先写成5条 fields = ["id", ] # 数据获取字段 if not service_ids: return result if service_ids: _ids = list(set(service_ids)) status["service"] = True fields.append("service_id") for i in range(0, len(_ids), data_slice): if status.get("service", False): service_ids = _ids[i: i + data_slice] query = Q(service_id__in=service_ids) result["services"].update(_get_topic_count_by_query(query, *fields)) return result @bind("diary/get_user_already_related_order_ids") def get_user_already_related_order_ids(need_filter_ids): """ 筛选出已关联日记本的订单id :return: """ order_ids = [] if need_filter_ids: filter_order_ids = list(Diary.objects.using(settings.SLAVE_DB_NAME).filter( order_id__in=need_filter_ids).values_list("order_id", flat=True)) order_ids.extend(filter_order_ids) return { "user_order_ids": order_ids, } @bind_context("diary/get_comment_mixed_v2") def get_diary_list_for_service_detail(ctx, diary_ids=None, order_ids=None): """ 美购详情页日记本卡片新版逻辑展示,仅提供数据接口 :param ctx: :param diary_ids: :param order_ids: :return: """ query = Q(is_online=True) if diary_ids: assert len(diary_ids) <= 100, 'too many diary_ids' query &= Q(id__in=diary_ids) elif order_ids: assert len(order_ids) <= 100, 'too many order_ids' query &= Q(order_id__in=order_ids, topics__isnull=False, topics__flag='n', topics__is_online=True) else: return gen(CODES.PARAMS_INCOMPLETE) diary_objs = Diary.objects.filter(query).distinct() diary_info_list = diary_objs.values("id", "operation_time", "created_time") if diary_ids: diary_objs = sorted(diary_objs, key=lambda item_obj: diary_ids.index(item_obj.id)) elif order_ids: diary_objs = sorted(diary_objs, key=lambda item_obj: order_ids.index(item_obj.order_id)) user = get_user_from_context(ctx) result = diary_list_manager.get_new_service_case_by_diary_objs(diary_objs, diary_info_list, viewer_user_id=user.id) return result @bind_context("diary/my_page/list") def get_my_page_diary(ctx, user_id, offset=0, count=10): user = get_user_from_context(ctx) assert int(count) <= 100, 'too many diary_ids' end_num = offset + count diary_ids = list(Diary.objects.filter(user_id=user_id).order_by('-id')[offset:end_num].values_list('id', flat=True)) diary_view_increase_num(diary_ids) diary_info = diary_list_manager.get_diary_list_by_diary_ids(diary_ids, viewer_user_id=user.id) return diary_info @bind("diary/list_data_get_by_ids_v2") def get_diary_list_data_by_ids_v2(diary_ids): """ 获取日记本信息 :param diary_ids: :return: """ assert len(diary_ids) <= 100, 'too many diary_ids' user = get_current_user() _curent_user_id = user and user.id or 0 result = diary_list_manager.get_diary_list_by_ids_v2(diary_ids, viewer_user_id=_curent_user_id) diary_view_increase_num(result.get("valid_diary_ids", [])) return { 'diaries': result.get("diary_list", []), } @bind('diary/topic_remark/by_service_ids') def get_diaries_remark(service_ids): """ 获取美购关联日记本日记帖的精选评论 """ assert len(service_ids) <= 10, 'too many service_ids' if not service_ids: return {} service_map, user_ids = defaultdict(), set() valid_levels = [DIARY_CONTENT_LEVEL.FINE, DIARY_CONTENT_LEVEL.EXCELLENT, DIARY_CONTENT_LEVEL.OUTSTANDING] topics = Problem.objects.using(settings.SLAVE_DB_NAME).select_related('diary').filter( diary__service_id__in=service_ids, diary__content_level__in=valid_levels, diary__is_online=True, ).values_list('diary_id', 'user_id', 'diary__service_id', 'remark').order_by('-diary__content_level', '-created_time') for diary_id, user_id, service_id, remark in topics.iterator(): if not remark or service_map.get(str(service_id)): continue user_ids.add(user_id) service_map[str(service_id)] = {'remark': remark, 'user_id': user_id} users = UserService.get_users_by_user_ids(user_ids) for service_id, item in service_map.items(): user = users.get(item['user_id']) if not user: del service_map[str(service_id)] item.update({ 'nickname': user.nickname, 'portrait': user.portrait, }) return dict(service_map)