def update(pk): if not pk.isdigit(): iname = normalize_tag(pk) if not iname: abort(404) tag = Tag.get(iname=iname) if not tag: abort(404) return redirect(url_for('admin_tags.update', pk=str(tag.id))) pk = int(pk) tag = Tag.get(id=pk) if not tag: abort(404) form = TagForm( data={ 'name': tag.name, 'category': tag.category.id if tag.category else 0, 'color': tag.color, 'description': tag.description, 'is_main_tag': tag.is_main_tag, 'is_alias_for': tag.is_alias_for.name if tag.is_alias_for else '', 'is_hidden_alias': tag.is_hidden_alias, 'reason_to_blacklist': tag.reason_to_blacklist, }) saved = False if form.validate_on_submit(): data = dict(form.data) if data.get('category') == 0: data['category'] = None try: tag.bl.update(current_user._get_current_object(), data) except ValidationError as exc: form.set_errors(exc.errors) else: saved = True tag_aliases = Tag.select(lambda x: x.is_alias_for == tag) visible_tag_aliases = [x for x in tag_aliases if not x.is_hidden_alias] hidden_tag_aliases = [x for x in tag_aliases if x.is_hidden_alias] return render_template( 'admin/tags/work.html', page_title=tag.name, tag=tag, visible_tag_aliases=visible_tag_aliases, hidden_tag_aliases=hidden_tag_aliases, form=form, edit=True, saved=saved, )
def update(pk): if not pk.isdigit(): iname = normalize_tag(pk) if not iname: abort(404) tag = Tag.get(iname=iname) if not tag: abort(404) return redirect(url_for('admin_tags.update', pk=str(tag.id))) pk = int(pk) tag = Tag.get(id=pk) if not tag: abort(404) form = TagForm(data={ 'name': tag.name, 'category': tag.category.id if tag.category else 0, 'color': tag.color, 'description': tag.description, 'is_main_tag': tag.is_main_tag, 'is_alias_for': tag.is_alias_for.name if tag.is_alias_for else '', 'is_hidden_alias': tag.is_hidden_alias, 'reason_to_blacklist': tag.reason_to_blacklist, }) saved = False if form.validate_on_submit(): data = dict(form.data) if data.get('category') == 0: data['category'] = None try: tag.bl.update(current_user._get_current_object(), data) except ValidationError as exc: form.set_errors(exc.errors) else: saved = True tag_aliases = Tag.select(lambda x: x.is_alias_for == tag) visible_tag_aliases = [x for x in tag_aliases if not x.is_hidden_alias] hidden_tag_aliases = [x for x in tag_aliases if x.is_hidden_alias] return render_template( 'admin/tags/work.html', page_title=tag.name, tag=tag, visible_tag_aliases=visible_tag_aliases, hidden_tag_aliases=hidden_tag_aliases, form=form, edit=True, saved=saved, )
def create(self, user, data): from mini_fiction.models import Tag, AdminLog if not user or not user.is_staff: raise ValueError('Not authorized') data = Validator(TAG).validated(data) errors = {} bad_reason = self.validate_tag_name(data['name']) if bad_reason: errors['name'] = [bad_reason] iname = normalize_tag(data['name']) if not bad_reason and Tag.get(iname=iname): errors['name'] = [lazy_gettext('Tag already exists')] canonical_tag = None if data.get('is_alias_for'): canonical_tag = Tag.get(iname=normalize_tag(data['is_alias_for'])) if not canonical_tag: errors['is_alias_for'] = [lazy_gettext('Tag not found')] if errors: raise ValidationError(errors) tag = Tag( name=data['name'], iname=iname, category=data.get('category'), color=data.get('color') or '', description=data.get('description') or '', is_main_tag=data.get('is_main_tag', False), created_by=user, is_alias_for=None, reason_to_blacklist='', ) tag.flush() AdminLog.bl.create(user=user, obj=tag, action=AdminLog.ADDITION) if data.get('reason_to_blacklist'): tag.bl.set_blacklist(user, data['reason_to_blacklist']) elif canonical_tag: tag.bl.make_alias_for(user, canonical_tag, hidden=data.get('is_hidden_alias', False)) return tag
def get_tags_with_categories(self, sort='name'): from mini_fiction.models import Tag categories_dict = {} tags = list(Tag.select(lambda x: not x.is_blacklisted and not x.is_alias).prefetch(Tag.category)) if sort == 'stories': tags.sort(key=lambda tag: tag.published_stories_count, reverse=True) elif sort == 'date': tags.sort(key=lambda tag: tag.created_at, reverse=True) elif sort == 'name': tags.sort(key=lambda tag: tag.iname) else: raise ValueError('Invalid tags sorting: {!r}'.format(sort)) categories_dict = {} others = {'category': None, 'tags': []} for tag in tags: if not tag.category: others['tags'].append(tag) continue if tag.category.id not in categories_dict: categories_dict[tag.category.id] = {'category': tag.category, 'tags': []} categories_dict[tag.category.id]['tags'].append(tag) result = sorted(categories_dict.values(), key=lambda x: x['category'].id) result.append(others) return result
def tag_index(tag_name, page): iname = normalize_tag(tag_name) if not iname: abort(404) tag = Tag.get(iname=iname) if tag and tag.is_alias_for is not None: if tag.is_alias_for.is_alias_for: raise RuntimeError('Tag alias {} refers to another alias {}!'.format(tag.id, tag.is_alias_for.id)) tag = tag.is_alias_for if not tag or tag.is_blacklisted: abort(404) if tag.iname != tag_name: return redirect(url_for('tags.tag_index', tag_name=tag.iname, page=page)) objects = Story.bl.select_by_tag(tag, user=current_user._get_current_object()) objects = objects.prefetch(Story.characters, Story.contributors, StoryContributor.user, Story.tags, StoryTag.tag, Tag.category) objects = objects.order_by(Story.first_published_at.desc(), Story.id.desc()) page_obj = Paginator(page, objects.count(), per_page=current_app.config['STORIES_COUNT']['stream']) objects = page_obj.slice_or_404(objects) return render_template( 'tags/tag_index.html', page_title=tag.name, tag=tag, aliases=[x.name for x in Tag.bl.get_aliases_for([tag])[tag.id]], category=tag.category, stories=objects, page_obj=page_obj, **cached_lists([x.id for x in objects]) )
def search_by_prefix(self, name, with_aliases=True, limit=20): from mini_fiction.models import Tag iname = normalize_tag(name) if not iname or limit < 1: return [] if limit > 100: limit = 100 result = [] # Ищем точное совпадение exact_tag = Tag.get(iname=iname, is_alias_for=None, reason_to_blacklist='') if exact_tag: result.append(exact_tag) elif with_aliases: tag_alias = exact_tag = Tag.get(iname=iname, reason_to_blacklist='') if tag_alias: exact_tag = tag_alias.is_alias_for assert exact_tag result.append(exact_tag) # Ищем остальные теги по префиксу if len(result) < limit: tags = set( Tag.select(lambda x: x.iname.startswith(iname) and not x. is_alias and not x.is_blacklisted).order_by( Tag.published_stories_count.desc()) [:limit + len(result)]) if with_aliases: # Подключаем синонимы, если разрешили # (отдельным запросом, чтоб были по порядку ниже несинонимов) tags = tags | set( Tag.select(lambda x: x.iname.startswith(iname) and x. is_alias and not x.is_blacklisted)) tags = sorted(tags, key=lambda x: x.published_stories_count, reverse=True) result.extend([x for x in tags if x not in result]) return result[:limit]
def get_all_tags(self, only_main=False, sort=False): from mini_fiction.models import Tag q = Tag.select() q = q.filter(lambda x: not x.is_blacklisted and not x.is_alias) if only_main: q = q.filter(lambda x: x.is_main_tag) q = q.prefetch(Tag.category) tags = list(q) if sort: tags.sort(key=lambda x: (x.category.id if x.category else 2 ** 31, x.iname)) return tags
def get_all_tags(self, only_main=False, sort=False): from mini_fiction.models import Tag q = Tag.select() q = q.filter(lambda x: not x.is_blacklisted and not x.is_alias) if only_main: q = q.filter(lambda x: x.is_main_tag) q = q.prefetch(Tag.category) tags = list(q) if sort: tags.sort(key=lambda x: (x.category.id if x.category else 2**31, x.iname)) return tags
def get_aliases_for(self, tags, hidden=False): from mini_fiction.models import Tag for x in tags: if x.is_alias or x.is_blacklisted: raise ValueError('Only valid canonical tags are allowed for get_aliases_for') result = {x.id: [] for x in tags} q = Tag.select(lambda x: x.is_alias_for in tags) if not hidden: q = q.filter(lambda x: not x.is_hidden_alias) for ts in q: result[ts.is_alias_for.id].append(ts) return result
def search_by_prefix(self, name, with_aliases=True, limit=20): from mini_fiction.models import Tag iname = normalize_tag(name) if not iname or limit < 1: return [] if limit > 100: limit = 100 result = [] # Ищем точное совпадение exact_tag = Tag.get(iname=iname, is_alias_for=None, reason_to_blacklist='') if exact_tag: result.append(exact_tag) elif with_aliases: tag_alias = exact_tag = Tag.get(iname=iname, reason_to_blacklist='') if tag_alias: exact_tag = tag_alias.is_alias_for assert exact_tag result.append(exact_tag) # Ищем остальные теги по префиксу if len(result) < limit: tags = set(Tag.select( lambda x: x.iname.startswith(iname) and not x.is_alias and not x.is_blacklisted ).order_by(Tag.published_stories_count.desc())[:limit + len(result)]) if with_aliases: # Подключаем синонимы, если разрешили # (отдельным запросом, чтоб были по порядку ниже несинонимов) tags = tags | set(Tag.select( lambda x: x.iname.startswith(iname) and x.is_alias and not x.is_blacklisted )) tags = sorted(tags, key=lambda x: x.published_stories_count, reverse=True) result.extend([x for x in tags if x not in result]) return result[:limit]
def check_tag_stories_count(verbosity=0, dry_run=False): last_id = None all_count = 0 changed_count = 0 while True: with orm.db_session: tags = Tag.select().order_by(Tag.id) if last_id is not None: tags = tags.filter(lambda x: x.id > last_id) tags = list(tags[:50]) if not tags: break last_id = tags[-1].id for tag in tags: all_count += 1 changed = False data = { 'stories_count': StoryTag.select(lambda x: x.tag == tag).count(), 'published_stories_count': StoryTag.select( lambda x: x.tag == tag and x.story.published).count(), } for k, v in data.items(): if verbosity >= 2 or (verbosity and v != getattr(tag, k)): print('Tag {} (id={}) {}: {} -> {}'.format( tag.name, tag.id, k, getattr(tag, k), v, ), file=sys.stderr) if v != getattr(tag, k): if not dry_run: setattr(tag, k, v) changed = True if changed: changed_count += 1 if verbosity >= 1: print('{} tags available, {} tags changed'.format( all_count, changed_count), file=sys.stderr)
def get_aliases_for(self, tags, hidden=False): from mini_fiction.models import Tag for x in tags: if x.is_alias or x.is_blacklisted: raise ValueError( 'Only valid canonical tags are allowed for get_aliases_for' ) result = {x.id: [] for x in tags} q = Tag.select(lambda x: x.is_alias_for in tags) if not hidden: q = q.filter(lambda x: not x.is_hidden_alias) for ts in q: result[ts.is_alias_for.id].append(ts) return result
def tag_index(tag_name, page): iname = normalize_tag(tag_name) if not iname: abort(404) tag = Tag.get(iname=iname) if tag and tag.is_alias_for is not None: if tag.is_alias_for.is_alias_for: raise RuntimeError( 'Tag alias {} refers to another alias {}!'.format( tag.id, tag.is_alias_for.id)) tag = tag.is_alias_for if not tag or tag.is_blacklisted: abort(404) if tag.iname != tag_name: return redirect( url_for('tags.tag_index', tag_name=tag.iname, page=page)) objects = Story.bl.select_by_tag(tag, user=current_user._get_current_object()) objects = objects.prefetch(Story.characters, Story.contributors, StoryContributor.user, Story.tags, StoryTag.tag, Tag.category) objects = objects.order_by(Story.first_published_at.desc(), Story.id.desc()) page_obj = Paginator( page, objects.count(), per_page=current_app.config['STORIES_COUNT']['stream']) objects = page_obj.slice_or_404(objects) return render_template( 'tags/tag_index.html', page_title=tag.name, tag=tag, aliases=[x.name for x in Tag.bl.get_aliases_for([tag])[tag.id]], category=tag.category, stories=objects, page_obj=page_obj, **cached_lists([x.id for x in objects]))
def check_tag_stories_count(verbosity=0, dry_run=False): last_id = None all_count = 0 changed_count = 0 while True: with orm.db_session: tags = Tag.select().order_by(Tag.id) if last_id is not None: tags = tags.filter(lambda x: x.id > last_id) tags = list(tags[:50]) if not tags: break last_id = tags[-1].id for tag in tags: all_count += 1 changed = False data = { 'stories_count': StoryTag.select(lambda x: x.tag == tag).count(), 'published_stories_count': StoryTag.select(lambda x: x.tag == tag and x.story.published).count(), } for k, v in data.items(): if verbosity >= 2 or (verbosity and v != getattr(tag, k)): print('Tag {} (id={}) {}: {} -> {}'.format( tag.name, tag.id, k, getattr(tag, k), v, ), file=sys.stderr) if v != getattr(tag, k): if not dry_run: setattr(tag, k, v) changed = True if changed: changed_count += 1 if verbosity >= 1: print('{} tags available, {} tags changed'.format(all_count, changed_count), file=sys.stderr)
def get_tags_with_categories(self, sort='name'): from mini_fiction.models import Tag categories_dict = {} tags = list( Tag.select( lambda x: not x.is_blacklisted and not x.is_alias).prefetch( Tag.category)) if sort == 'stories': tags.sort(key=lambda tag: tag.published_stories_count, reverse=True) elif sort == 'date': tags.sort(key=lambda tag: tag.created_at, reverse=True) elif sort == 'name': tags.sort(key=lambda tag: tag.iname) else: raise ValueError('Invalid tags sorting: {!r}'.format(sort)) categories_dict = {} others = {'category': None, 'tags': []} for tag in tags: if not tag.category: others['tags'].append(tag) continue if tag.category.id not in categories_dict: categories_dict[tag.category.id] = { 'category': tag.category, 'tags': [] } categories_dict[tag.category.id]['tags'].append(tag) result = sorted(categories_dict.values(), key=lambda x: x['category'].id) result.append(others) return result
def update(self, user, data): from mini_fiction.models import Tag, AdminLog if not user or not user.is_staff: raise ValueError('Not authorized') tag = self.model data = Validator(TAG).validated(data, update=True) changes = {} errors = {} if 'name' in data and data['name'] != tag.name: bad_reason = self.validate_tag_name(data['name']) if bad_reason: errors['name'] = [bad_reason] iname = normalize_tag(data['name']) if not bad_reason and iname != tag.iname and Tag.get(iname=iname): errors['name'] = [lazy_gettext('Tag already exists')] changes['name'] = data['name'] if iname != tag.iname: changes['iname'] = iname if 'category' in data: old_category_id = tag.category.id if tag.category else None if old_category_id != data['category']: changes['category'] = data['category'] for key in ('color', 'description', 'is_main_tag'): if key in data and data[key] != getattr(tag, key): changes[key] = data[key] canonical_tag = tag.is_alias_for if 'is_alias_for' in data: if data.get('is_alias_for'): canonical_tag = Tag.get(iname=normalize_tag(data['is_alias_for'])) if not canonical_tag: errors['is_alias_for'] = [lazy_gettext('Tag not found')] elif canonical_tag == tag or canonical_tag.is_alias_for and canonical_tag.is_alias_for == tag: errors['is_alias_for'] = [lazy_gettext('Tag cannot refer to itself')] else: canonical_tag = None if errors: raise ValidationError(errors) if changes: changes['updated_at'] = datetime.utcnow() tag.set(**changes) AdminLog.bl.create( user=user, obj=tag, action=AdminLog.CHANGE, fields=set(changes) - {'updated_at'}, ) if 'reason_to_blacklist' in data: self.set_blacklist(user, data['reason_to_blacklist']) if not tag.is_blacklisted and ('is_alias_for' in data or 'is_hidden_alias' in data): self.make_alias_for(user, canonical_tag, data.get('is_hidden_alias', tag.is_hidden_alias))
def get_tags_objects(self, tags, create=False, user=None, resolve_aliases=True, resolve_blacklisted=True, create_if_errors=False): """Принимает список объектов Tag или строк с названиями тегов (можно вперемешку) и возвращает словарь со следующими ключами: - success — True, если всё хорошо (в списке tags гарантированно отсутствуют None); - tags — список из объектов Tag, которые были успешно найдены (соответствует порядку исходному списку tags, вместо ненайденных тегов стоит None); - aliases — список тегов, оказавшихся алиасами и заменённых на каноничные теги (пуст при resolve_aliases=False); - blacklisted — список заблокированных тегов, не попавших в tags (пуст при resolve_blacklisted=False); - invalid — список строк, которые не являются синтаксически корректными тегами (например, пустая строка), и причин некорректности (кортежи из двух элементов); - created — список свежесозданных тегов, если они создавались (при create=True); - nonexisting — список из строк, для которых тегов не нашлось (при create=False). Если скормить несколько одинаковых тегов, то в списке tags могут появиться дубликаты. """ # FIXME: тут костыль с е/ё. Надо бы как-то заменить его на адекватное # юникодное сравнение для соответствия utf8mb4_general_ci from mini_fiction.validation.utils import safe_string_coerce from mini_fiction.models import Tag # Достаём список строк для поиска тегов tags_search = [x for x in tags if not isinstance(x, Tag)] tags_db = { x.iname.replace('ё', 'е'): x for x in tags if isinstance(x, Tag) } # Ищем недостающие теги в базе inames = [normalize_tag(x) for x in tags_search] inames = [x for x in inames if x] if inames: tags_db.update({ x.iname.replace('ё', 'е'): x for x in Tag.select(lambda t: t.iname in inames).prefetch( Tag.is_alias_for) }) result = { 'success': True, 'tags': [None] * len(tags), 'aliases': [], 'blacklisted': [], 'invalid': [], 'created': [], 'nonexisting': [], } create_tags = [] # [(index, name, iname), ...] # Анализируем каждый запрошенный тег for i, x in enumerate(tags): if isinstance(x, Tag): name = x.name iname = x.iname tag = x else: name = safe_string_coerce(x.strip()) iname = normalize_tag(name) tag = None if iname: tag = tags_db.get(iname.replace('ё', 'е')) assert iname == normalize_tag(x) if tag: # Если тег существует, проверяем, что его можно использовать if resolve_aliases and tag.is_alias_for: if tag.is_alias_for.is_alias_for: raise RuntimeError( 'Tag alias {} refers to another alias {}!'.format( tag.id, tag.is_alias_for.id)) result['aliases'].append(tag) tag = tag.is_alias_for if resolve_blacklisted and tag.is_blacklisted: result['blacklisted'].append(tag) result['success'] = False tag = None elif create: # Если не существует — создаём if not user or not user.is_authenticated: raise ValueError('Not authenticated') reason = self.validate_tag_name(name) if reason is not None: result['invalid'].append((x, reason)) result['success'] = False else: create_tags.append( (i, name, iname)) # Отложенное создание тегов else: result['nonexisting'].append(x) result['success'] = False if tag: result['tags'][i] = tag # Если нужно создать теги, то создаём их только при отсутствии других # ошибок, чтобы зазря не мусорить в базу данных (проверка отключается # опцией create_if_errors=True) if create_tags and (create_if_errors or result['success']): for i, name, iname in create_tags: if iname.replace('ё', 'е') in tags_db: # На случай, если пользователь пропихнул дублирующиеся теги result['tags'][i] = tags_db[iname.replace('ё', 'е')] continue tag = Tag(name=name, iname=iname, created_by=user) tag.flush() # получаем id у базы данных tags_db[tag.iname.replace( 'ё', 'е' )] = tag # На случай, если у следующего тега в цикле совпадёт iname result['created'].append(tag) result['tags'][i] = tag # see views/tags.py current_app.cache.delete('tags_autocomplete_default') return result
def update(self, user, data): from mini_fiction.models import Tag, AdminLog if not user or not user.is_staff: raise ValueError('Not authorized') tag = self.model data = Validator(TAG).validated(data, update=True) changes = {} errors = {} if 'name' in data and data['name'] != tag.name: bad_reason = self.validate_tag_name(data['name']) if bad_reason: errors['name'] = [bad_reason] iname = normalize_tag(data['name']) if not bad_reason and iname != tag.iname and Tag.get(iname=iname): errors['name'] = [lazy_gettext('Tag already exists')] changes['name'] = data['name'] if iname != tag.iname: changes['iname'] = iname if 'category' in data: old_category_id = tag.category.id if tag.category else None if old_category_id != data['category']: changes['category'] = data['category'] for key in ('color', 'description', 'is_main_tag'): if key in data and data[key] != getattr(tag, key): changes[key] = data[key] canonical_tag = tag.is_alias_for if 'is_alias_for' in data: if data.get('is_alias_for'): canonical_tag = Tag.get( iname=normalize_tag(data['is_alias_for'])) if not canonical_tag: errors['is_alias_for'] = [lazy_gettext('Tag not found')] elif canonical_tag == tag or canonical_tag.is_alias_for and canonical_tag.is_alias_for == tag: errors['is_alias_for'] = [ lazy_gettext('Tag cannot refer to itself') ] else: canonical_tag = None if errors: raise ValidationError(errors) if changes: changes['updated_at'] = datetime.utcnow() tag.set(**changes) AdminLog.bl.create( user=user, obj=tag, action=AdminLog.CHANGE, fields=set(changes) - {'updated_at'}, ) if 'reason_to_blacklist' in data: self.set_blacklist(user, data['reason_to_blacklist']) if not tag.is_blacklisted and ('is_alias_for' in data or 'is_hidden_alias' in data): self.make_alias_for( user, canonical_tag, data.get('is_hidden_alias', tag.is_hidden_alias))
def get_tags_objects( self, tags, create=False, user=None, resolve_aliases=True, resolve_blacklisted=True, create_if_errors=False ): """Принимает список объектов Tag или строк с названиями тегов (можно вперемешку) и возвращает словарь со следующими ключами: - success — True, если всё хорошо (в списке tags гарантированно отсутствуют None); - tags — список из объектов Tag, которые были успешно найдены (соответствует порядку исходному списку tags, вместо ненайденных тегов стоит None); - aliases — список тегов, оказавшихся алиасами и заменённых на каноничные теги (пуст при resolve_aliases=False); - blacklisted — список заблокированных тегов, не попавших в tags (пуст при resolve_blacklisted=False); - invalid — список строк, которые не являются синтаксически корректными тегами (например, пустая строка), и причин некорректности (кортежи из двух элементов); - created — список свежесозданных тегов, если они создавались (при create=True); - nonexisting — список из строк, для которых тегов не нашлось (при create=False). Если скормить несколько одинаковых тегов, то в списке tags могут появиться дубликаты. """ from mini_fiction.validation.utils import safe_string_coerce from mini_fiction.models import Tag # Достаём список строк для поиска тегов tags_search = [x for x in tags if not isinstance(x, Tag)] tags_db = {x.iname: x for x in tags if isinstance(x, Tag)} # Ищем недостающие теги в базе inames = [normalize_tag(x) for x in tags_search] inames = [x for x in inames if x] if inames: tags_db.update({x.iname: x for x in Tag.select(lambda t: t.iname in inames).prefetch(Tag.is_alias_for)}) result = { 'success': True, 'tags': [None] * len(tags), 'aliases': [], 'blacklisted': [], 'invalid': [], 'created': [], 'nonexisting': [], } create_tags = [] # [(index, name, iname), ...] # Анализируем каждый запрошенный тег for i, x in enumerate(tags): if isinstance(x, Tag): name = x.name iname = x.iname tag = x else: name = safe_string_coerce(x.strip()) iname = normalize_tag(name) tag = tags_db.get(iname) assert iname == normalize_tag(x) if tag: # Если тег существует, проверяем, что его можно использовать if resolve_aliases and tag.is_alias_for: if tag.is_alias_for.is_alias_for: raise RuntimeError('Tag alias {} refers to another alias {}!'.format(tag.id, tag.is_alias_for.id)) result['aliases'].append(tag) tag = tag.is_alias_for if resolve_blacklisted and tag.is_blacklisted: result['blacklisted'].append(tag) result['success'] = False tag = None elif create: # Если не существует — создаём if not user or not user.is_authenticated: raise ValueError('Not authenticated') reason = self.validate_tag_name(name) if reason is not None: result['invalid'].append((x, reason)) result['success'] = False else: create_tags.append((i, name, iname)) # Отложенное создание тегов else: result['nonexisting'].append(x) result['success'] = False if tag: result['tags'][i] = tag # Если нужно создать теги, то создаём их только при отсутствии других # ошибок, чтобы зазря не мусорить в базу данных (проверка отключается # опцией create_if_errors=True) if create_tags and (create_if_errors or result['success']): for i, name, iname in create_tags: if iname in tags_db: # На случай, если пользователь пропихнул дублирующиеся теги result['tags'][i] = tags_db[iname] continue tag = Tag(name=name, iname=iname, created_by=user) tag.flush() # получаем id у базы данных tags_db[tag.iname] = tag # На случай, если у следующего тега в цикле совпадёт iname result['created'].append(tag) result['tags'][i] = tag # see views/tags.py current_app.cache.delete('tags_autocomplete_default') return result
def index(page): objects = Tag.select().order_by(Tag.iname) args = { 'page': page, 'sorting': request.args.get('sorting') or 'iname', } if request.args.get('name'): iname = normalize_tag(request.args['name']) args['name'] = iname objects = objects.filter(lambda x: iname in x.iname) if request.args.get('category'): if request.args['category'] == '0': args['category'] = '0' objects = objects.filter(lambda x: x.category is None) elif request.args['category'].isdigit(): args['category'] = request.args['category'] cat_id = int(request.args['category']) objects = objects.filter(lambda x: x.category.id == cat_id) if request.args.get('is_blacklisted') == '0': args['is_blacklisted'] = '0' objects = objects.filter(lambda x: not x.is_blacklisted) elif request.args.get('is_blacklisted') == '1': args['is_blacklisted'] = '1' objects = objects.filter(lambda x: x.is_blacklisted) if request.args.get('is_alias') == '0': args['is_alias'] = '0' objects = objects.filter(lambda x: not x.is_alias) elif request.args.get('is_alias') == '1': args['is_alias'] = '1' objects = objects.filter(lambda x: x.is_alias) if request.args.get('is_main_tag') == '0': args['is_main_tag'] = '0' objects = objects.filter(lambda x: not x.is_main_tag) elif request.args.get('is_main_tag') == '1': args['is_main_tag'] = '1' objects = objects.filter(lambda x: x.is_main_tag) objects = objects.prefetch(Tag.is_alias_for, Tag.created_by, Tag.category) objects = admin_sort(args['sorting'], objects, { 'iname': Tag.iname, 'created_at': (Tag.created_at, Tag.id), 'stories_count': (Tag.stories_count, Tag.id), }, default='iname') page_obj = Paginator(page, objects.count(), per_page=100, endpoint=request.endpoint, view_args=args) return render_template( 'admin/tags/index.html', tags=page_obj.slice_or_404(objects), page_obj=page_obj, page_title=gettext('Tags'), endpoint=request.endpoint, args=args, tag_categories=list(TagCategory.select().order_by(TagCategory.id)), )