class Media(BaseModel): # base table containing all media entries title = peewee.CharField(unique=True) alt_title = peewee.CharField(null=True) series = peewee.ForeignKeyField(Series, backref='sequels', null=True) order = peewee.DecimalField( max_digits=2, null=True ) # the story's chronological order ex: Star Wars Ep. 1, 2, 3, 4, 5, 6 | NOT 4, 5, 6, 1, 2, 3 media_type = peewee.ForeignKeyField( MediaTypes, backref='media') # movie | tv show | etc animated = peewee.BooleanField() country = peewee.ForeignKeyField(Countries, backref='media') # USA | UK | Japan | etc language = peewee.ManyToManyField(Languages, backref='media') subtitles = peewee.BooleanField(null=True) year = peewee.IntegerField(constraints=[peewee.Check('year > 1900')], null=True) # release year genres = peewee.ManyToManyField(Genres, backref='media') director = peewee.ForeignKeyField(Directors, backref='media', null=True) studio = peewee.ForeignKeyField(Studios, backref='media', null=True) actors = peewee.ManyToManyField( Actors, backref='media') # ManyToManyField does not support null=True plot = peewee.CharField(null=True) rating = peewee.IntegerField(constraints=[ peewee.Check('rating >= 1 AND rating <=10') ], null=True) # 1 to 10 tags = peewee.ManyToManyField( Tags, backref='media') # ManyToManyField does not support null=True notes = peewee.CharField(null=True)
class Tag(peewee.Model): tagname = peewee.CharField() names = peewee.ManyToManyField(Name, backref="tags") class Meta: database = db db_table = "tags" # file name to path,no repeat
def ready(self): models = [ model for model in django.apps.apps.get_models() if not model._meta.proxy ] # resolve simple fields, bind "pw" field to django model for model in models: inner = self.get_peewee_class_inner(model) inner['django_model'] = model model.pw = type(self.get_klass_name(model), (ProxyModel, ), inner) self.PEEWEE_MODELS_CACHE[model] = model.pw # resolve deferred foreign keys, we use DeferredForeignKey, to avoid cycle foreign keys for model in models: DeferredForeignKey.resolve(model.pw) # resolve many_to_many fields for model in models: meta = model._meta for field in meta.many_to_many: peewee_model = self.PEEWEE_MODELS_CACHE[model] through_model = self.get_many_to_many_model( getattr(model, field.column)) peewee_model._meta.add_field( field.column, peewee.ManyToManyField( self.PEEWEE_MODELS_CACHE[field.related_model], through_model=through_model)) self.patch_database_required_functions()
class Note(BaseModel): model = pv.ForeignKeyField(Model, backref='notes') data = sqlite_ext.JSONField() # format = dict() constraint = ConstraintField(unique=True) # format = list() _tags = pv.ManyToManyField(Tag, backref='notes') created = pv.DateTimeField(constraints=[pv.SQL('DEFAULT CURRENT_TIMESTAMP')]) modified = pv.DateTimeField(constraints=[pv.SQL('DEFAULT CURRENT_TIMESTAMP')]) info = sqlite_ext.JSONField(default=dict) def to_dict(self): return super(Note, self).to_dict(manytomany=False, backrefs=False, exclude=['_tags'], extra_attrs=['tags']) @property def tags(self): return [t.name for t in self._tags] def mark(self, tag='marked'): Tag.get_or_create(name=tag)[0].notes.add(self) add_tag = mark def unmark(self, tag='marked'): Tag.get_or_create(name=tag)[0].notes.remove(self) remove_tag = unmark
class Note(components.BaseDocumentModel): title = peewee.TextField() content = peewee.TextField() is_archived = peewee.BooleanField(default=False) is_pinned = peewee.BooleanField(default=False) tags = peewee.ManyToManyField(Tag) category = peewee.ForeignKeyField(Category, null=True, default=None, backref="notes") due_date = peewee.DateTimeField(null=True, default=None, formats=["%s", "%Y-%m-%d"])
class Dish(peewee.Model): name = peewee.CharField() served_at = peewee.ForeignKeyField(Restaurant) price_in_cents = peewee.IntegerField() ingredients = peewee.ManyToManyField(Ingredient) class Meta: database = db
class Milestone(components.BaseDocumentModel): name = peewee.TextField() description = peewee.TextField() due_date = peewee.DateTimeField(null=True, default=None, formats=["%s", "%Y-%m-%d"]) tags = peewee.ManyToManyField(Tag) category = peewee.ForeignKeyField(Category, null=True, default=None) pass
class Chat(peewee.Model): name = peewee.CharField(max_length=20, unique=True) users = peewee.ManyToManyField(User, backref="users_list") admin = peewee.ForeignKeyField(User, backref="chats") class Meta: database = db table_name = "chats"
class Page(BaseModel): """Страница""" name = peewee.CharField(max_length=200) slug = peewee.CharField(unique=True) sequence = peewee.IntegerField() blocks = peewee.ManyToManyField(Block, backref='pages') class Meta: db_table = 'page'
class Clase(pwe.Model): class Meta: database = psql_db table_name = 'clases' id_clase = pwe.AutoField() nombre = pwe.CharField(max_length=100, null=False) horario = pwe.CharField(max_length=100, null=False) alumnos = pwe.ManyToManyField(model=Alumno, backref="clases", through_model=deferred_alumno_clase)
class OzonProduct(peewee.Model): id = peewee.AutoField() url = peewee.TextField() price = peewee.TextField() title = peewee.TextField() images = peewee.TextField() categories = peewee.ManyToManyField(OzonCategory, backref='goods') class Meta: database = psql_db db_table = "vasiliy_vanchuk__ozon_product"
class User(BaseModel): class Meta: table_name = "users" name = peewee.TextField(null=False, unique=True) password = peewee.TextField(null=False) display_name = peewee.TextField(null=True) created = peewee.DateTimeField(null=False, default=datetime.now, formats=["%s"]) edited = peewee.DateTimeField(null=False, default=datetime.now, index=True, formats=["%s"]) user_ref_id = peewee.UUIDField(null=False, unique=True, index=True, default=uuid4) is_deleted = peewee.BooleanField(null=False, default=False) is_active = peewee.BooleanField(null=False, default=False) permissions = peewee.ManyToManyField(Role, backref="users")
class Post(BaseModel): post_id = pw.TextField(index=True) image_uri = pw.TextField() description = pw.TextField() comments = pw.ManyToManyField(Comment, backref="post") date = pw.DateTimeField(default=datetime.datetime.now) hashtags = pw.TextField(default="") mentions = pw.TextField(default="") likes = pw.IntegerField(default=0) relevance = pw.FloatField(default=0.0) sentiment = pw.FloatField(default=0.0) comments_sentiment = pw.FloatField(default=0.0) comments_count = pw.IntegerField(default=0)
class Message(database.db.basemodel): user = peewee.ForeignKeyField(User, related_name='messages') #message = AESEncryptedField(conf.get_config("taemin").get("aes_password", "banane").encode("utf-8")) message = peewee.TextField() key = peewee.TextField(null=True) value = peewee.TextField(null=True) target = peewee.TextField(null=True) chan = peewee.ForeignKeyField(Chan, related_name='messages', null=True) link = peewee.ForeignKeyField(Link, related_name='messages', null=True, on_delete='SET NULL') highlights = peewee.ManyToManyField(User, backref='hl') created_at = peewee.DateTimeField(default=datetime.datetime.now)
class Model(BaseModel): name = pv.TextField(unique=True) css = pv.TextField(default='') js = pv.TextField(default='') fonts = pv.ManyToManyField(Media, backref='models') # templates @classmethod def clean(cls): i = 0 for db_model in cls.select(): if not db_model.templates: i += 1 db_model.delete_instance() return i @classmethod def add(cls, name, templates, css='', js=''): """ :param name: :param list templates: list of dict or list of TemplateMaker :param css: :param js: :return: """ with database.atomic(): db_model = cls.create(name=name, css=css, js=js) for template in templates: Template.create( model_id=db_model.id, name=template['name'], question=template['question'], answer=template['answer'] ) return db_model def __repr__(self): return f'<Model: "{self.name}">' def to_viewer(self): d = model_to_dict(self) d['fonts'] = [repr(f) for f in self.fonts] d['templates'] = [t.name for t in self.templates] return d
class Roles(BaseModel): title = peewee.CharField(max_length=32, verbose_name="角色名") permission = peewee.ManyToManyField(Permissions, backref="role_permission", on_delete="CASCADE") @classmethod def newData(cls, params): params = tuple(params) if params: return cls.select().where(*params) else: return cls.select() class Meta: table_name = "roles"
class Users(BaseModel): username = peewee.CharField(max_length=32, verbose_name="用户名") password = peewee.CharField(max_length=255, verbose_name="密码") is_staff = peewee.BooleanField(default=False, verbose_name="是否职员") is_superuser = peewee.BooleanField(default=False, verbose_name="是否管理员") is_lock = peewee.BooleanField(default=False, verbose_name="是否锁定") is_confirm = peewee.BooleanField(default=False, verbose_name="是否确定") role = peewee.ManyToManyField(Roles, backref="user_role", on_delete="CASCADE") @classmethod def newData(cls, params): params = tuple(params) if params: return cls.select().where(*params) else: return cls.select() class Meta: table_name = "users"
class Retailer(peewee.Model): name = peewee.CharField() description = peewee.CharField(null=True) picture = peewee.CharField(null=True) active = peewee.BooleanField(default=True) ad_model = peewee.CharField(null=True, verbose_name=u'c/a') #TODO: to choices legal_info = peewee.TextField(null=True) countries = peewee.ManyToManyField(Country, backref='retailers', through_model=DefferedThroughRetailer) currency = peewee.ForeignKeyField(Currency) sm_accounts_white = postgres_ext.ArrayField(peewee.IntegerField, null=True) sm_accounts_black = postgres_ext.ArrayField(peewee.IntegerField, null=True) #NOTE: deprecated, will be removed datafeed_url = peewee.CharField(null=True) index_key = peewee.CharField(max_length=3, default='rus') url_key_mode = peewee.CharField(max_length=1, default='F') datafeed_params = postgres_ext.BinaryJSONField(default={}) international = peewee.BooleanField(default=False) class Meta: database = db schema = 'store' table_alias = 'r' @property def feed(self): return self.feed_settings.first() @property def feeds(self): return [ fs for fs in self.feed_settings.where(FeedSettings.active == True) ]
class FlrMenu(BaseModel): name = pw.CharField() section_id = pw.ForeignKeyField(FlrMenuSection, backref="menus") groups = pw.ManyToManyField(Registry["FlrGroup"]) sequence = pw.IntegerField(default=1) @classmethod def get_menus(cls): user = Registry["FlrUser"].get_by_id(request.uid) user_groups = set([x.id for x in user.groups]) result = [] for section in FlrMenuSection.select().order_by( FlrMenuSection.sequence): section_obj = {'id': section.id, 'name': section.name, 'menus': []} for menu in section.menus.order_by(FlrMenu.sequence): menu_groups = [g.id for g in menu.groups] if not menu.groups or user_groups.intersection(menu_groups): section_obj["menus"].append({ "id": menu.id, "name": menu.name }) if section_obj["menus"]: result.append(section_obj) return result
class User(components.BaseUser): class Meta: table_name = "users" display_name = peewee.TextField(null=True) created = peewee.DateTimeField(null=False, default=datetime.now, formats=["%s"]) edited = peewee.DateTimeField(null=False, default=datetime.now, index=True, formats=["%s"]) user_ref_id = peewee.UUIDField(null=False, unique=True, index=True, default=uuid4) is_deleted = peewee.BooleanField(null=False, default=False) is_active = peewee.BooleanField(null=False, default=False) permissions = peewee.ManyToManyField(Role, backref="users") def changed(self): self.edited = datetime.now()
model_rule[ "perm_read"] = model_rule["perm_read"] or rule.perm_read model_rule["perm_update"] = model_rule[ "perm_update"] or rule.perm_update model_rule["perm_create"] = model_rule[ "perm_create"] or rule.perm_create model_rule["perm_delete"] = model_rule[ "perm_delete"] or rule.perm_delete return data class FlrGroup(BaseModel): name = pw.CharField(help_text="Nombre") FlrUser._meta.add_field("groups", pw.ManyToManyField(FlrGroup)) FlrUser.r() FlrGroup.r() FlrUserFlrGroup = FlrUser.groups.get_through_model() class FlrACL(BaseModel): group_id = pw.ForeignKeyField(FlrGroup, help_text="Group", backref="acls") model = pw.CharField(help_text="Model") perm_read = pw.BooleanField(help_text="Read permission", null=True, default=False) perm_update = pw.BooleanField(help_text="Update permission", null=True, default=False)
class Image(BaseModel): file_id = pv.IntegerField(null=True) filename = pv.TextField(null=False) checksum = pv.TextField(null=False) image_hash = ImageHashField(null=True) tags = pv.ManyToManyField(Tag, backref='images') @classmethod def from_bytes_io(cls, im_bytes_io, filename=None, tags=None): """ :param im_bytes_io: :param str filename: :param str|list|tuple tags: :return: """ if tags is None: tags = list() elif isinstance(tags, str): tags = [tags] if not filename or filename == 'image.png': filename = slugify('-'.join(tags)) + str(uuid4())[:8] + '.png' filename = nonrepeat_filename(filename, root=str(config['blob_folder'])) filename = str(config['blob_folder'].joinpath(filename)) checksum = get_checksum(im_bytes_io) im = PIL.Image.open(im_bytes_io) image_hash = get_image_hash(im) im.save(filename) db_image = cls.create(file_id=os.stat(filename).st_ino, filename=filename, checksum=checksum, image_hash=image_hash) for tag in set(tags): db_image.tags.add(Tag.get_or_create(name=tag)[0]) return db_image @classmethod def from_existing(cls, filename, tags=None): if tags is None: tags = list() filename = str(filename) db_image = cls.create(file_id=os.stat(filename).st_ino, filename=filename, checksum=get_checksum(filename), image_hash=get_image_hash(filename)) for tag in tags: db_image.tags.add(Tag.get_or_create(name=tag)[0]) db_image.path = filename return db_image @classmethod def similar_images(cls, im): image_hash = get_image_hash(im) if config['hash_difference_threshold']: for db_image in cls.select(): if db_image.image_hash - image_hash < config[ 'hash_difference_threshold']: yield db_image else: return cls.select().where(cls.image_hash == image_hash) def get_image(self, max_width=800, max_height=800): url = self.url if url: return f'<img src="{url}" style="max-width: {max_width}px; max-height: {max_height}px;" />' def _repr_html_(self): return self.get_image(800, 800) def _repr_json_(self): result = self.to_json() result['image'] = self.filename return result @property def url(self): if not urlparse(self.filename).netloc: return 'http://{}:{}/images?filename={}'.format( config['host'], config['port'], quote(str(self.filename), safe='')) else: return self.filename def to_json(self): return dict(id=self.id, image=self.get_image(400, 400), filename=self.filename, notes=[n.data for n in self.notes], tags=[t.name for t in self.tags]) handsontable_config = { 'renderers': { 'image': 'html' }, 'config': { 'colWidths': { 'image': 400 } } }
class Card(BaseModel): item = pv.TextField(unique=True) info = sqlite_ext.JSONField(null=True) srs_level = pv.IntegerField(null=True) next_review = pv.DateTimeField(null=True) tags = pv.ManyToManyField(Tag, backref='cards', on_delete='cascade') backup = None def __repr__(self): return self.item def _repr_markdown_(self): type_ = Settings.get().type_ if type_ == 'markdown': return self.item def _repr_html_(self): type_ = Settings.get().type_ if type_ == 'html': return self.item def mark(self, tag='marked'): Tag.get_or_create(name=tag)[0].notes.add(self) def unmark(self, tag='marked'): Tag.get_or_create(name=tag)[0].notes.remove(self) def right(self): if not self.backup: self.backup = model_to_dict(self) if not self.srs_level: self.srs_level = 0 else: self.srs_level = self.srs_level + 1 srs = Settings.get()['srs'] try: self.next_review = datetime.now() + srs[self.srs_level] except IndexError: self.next_review = None self.save() correct = next_srs = right def wrong(self, next_review=timedelta(minutes=10)): if not self.backup: self.backup = model_to_dict(self) if self.srs_level and self.srs_level > 0: self.srs_level = self.srs_level - 1 self.bury(next_review) incorrect = previous_srs = wrong def bury(self, next_review=timedelta(hours=4)): if not self.backup: self.backup = model_to_dict(self) if isinstance(next_review, timedelta): self.next_review = datetime.now() + next_review else: self.next_review = next_review self.save() def undo(self): if self.backup: dict_to_model(Card, self.backup).save() @classmethod def iter_quiz(cls, **kwargs): db_cards = list(cls.search(**kwargs)) random.shuffle(db_cards) return iter(db_cards) @classmethod def iter_due(cls, **kwargs): return cls.iter_quiz(due=True, **kwargs) @classmethod def search(cls, tags=None, due=Any, offset=0, limit=None): query = cls.select() if due is True: query = query.where(Card.next_review < datetime.now()) elif due is False: query = query.where(Card.next_review >= datetime.now()) elif due is None: query = query.where(Card.next_review.is_null(True)) elif isinstance(due, timedelta): query = query.where(Card.next_review < datetime.now() + due) elif isinstance(due, datetime): query = query.where(Card.next_review < due) if tags: for tag in tags: query = query.join(CardTag).join(Tag).where(Tag.name.contains(tag)) query = query.order_by(cls.next_review.desc()) if offset: query = query.offset(offset) if limit: query = query.limit(limit) return query def to_dict(self): return model_to_dict(self, manytomany=True) @classmethod def add(cls, item, tags, **kwargs): with database.atomic(): db_card = cls.create(item=item, info=kwargs) for tag in tags: Tag.get_or_create(name=tag)[0].cards.add(db_card) return db_card
class Evaluacion(BaseModel): examen = peewee.ForeignKeyField(Examen, backref='evaluaciones',null = True) #una evaluacion con examen null es para cargar notas de practicos preguntas = peewee.ManyToManyField(Pregunta, backref='evaluaciones') cursada = peewee.ForeignKeyField(Cursada, backref='evaluaciones') titulo = peewee.CharField() fecha = peewee.DateTimeField()
class Cursada(BaseModel): curso = peewee.ForeignKeyField(Curso, backref='cursadas') nombre = peewee.CharField() profesores = peewee.ManyToManyField(Usuario,through_model= ProfesorThroughDeferred, backref='cursadasEnLasQueEsProfesor') alumnos = peewee.ManyToManyField(Usuario,through_model= AlumnoThroughDeferred, backref='cursadasEnLasQueEsAlumno') inicio = peewee.DateTimeField()
class Attachment(BaseModel): rawmsg = pw.ManyToManyField(RawMsg, backref='attachments') file_checksum = pw.CharField(help_text='Checksum of the file on disk') original_filename = pw.CharField(help_text='Original filename') content_type = pw.CharField(help_text='Original content type')
class Card(BaseModel): template = pv.ForeignKeyField(Template, backref='cards') note = pv.ForeignKeyField(Note, backref='cards') _front = pv.TextField(unique=True) srs_level = pv.IntegerField(null=True) next_review = pv.DateTimeField(null=True) _decks = pv.ManyToManyField(Deck, backref='cards') last_review = pv.DateTimeField(constraints=[pv.SQL('DEFAULT CURRENT_TIMESTAMP')]) info = sqlite_ext.JSONField(default=dict) backup = None def to_dict(self, max_depth=2, **kwargs): d = super(Card, self).to_dict(manytomany=False, backrefs=False, exclude=['_decks', '_front', 'note'], extra_attrs=['decks', 'front', 'back']) d['note'] = self.note.to_dict() return d @property def decks(self): return [d.name for d in self._decks] @property def front(self): text = self.template.front for k, v in self.note.data.items(): text = text.replace('{{%s}}' % k, str(v)) return text @property def back(self): text = self.template.back if not text: return '\n'.join(' ' * 4 + line for line in json.dumps( self.note.data, indent=2, ensure_ascii=False ).split('\n')) for k, v in self.note.data.items(): text = text.replace('{{%s}}' % k, str(v)) return text def __repr__(self): return self.front @property def data(self): return self.note.data def add_deck(self, deck_name): Deck.get_or_create(name=deck_name)[0].cards.add(self) def remove_deck(self, deck_name): Deck.get_or_create(name=deck_name)[0].cards.remove(self) def mark(self, tag='marked'): return self.note.mark(tag) def unmark(self, tag='marked'): return self.note.unmark(tag) def right(self, step=1): self.undo() if not self.backup: self.backup = model_to_dict(self) print(self.srs_level) if self.srs_level is None: self.srs_level = 0 else: self.srs_level = self.srs_level + step srs = Settings.get().srs try: self.next_review = datetime.now() + srs[self.srs_level] except IndexError: self.next_review = None assert isinstance(self.info, dict) self.info['lapse'] = 0 self.info['streak'] = self.info.get('streak', 0) + 1 self.info['total_right'] = self.info.get('total_right', 0) + 1 self.save() correct = next_srs = right def easy(self, max_srs_level_enabled=3): if self.srs_level < max_srs_level_enabled: return self.right(step=2) else: raise ValueError def wrong(self, next_review=timedelta(minutes=10)): self.undo() if not self.backup: self.backup = model_to_dict(self) if self.srs_level is not None and self.srs_level > 0: self.srs_level = self.srs_level - 1 assert isinstance(self.info, dict) self.info['streak'] = 0 self.info['lapse'] = self.info.get('lapse', 0) + 1 self.info['total_wrong'] = self.info.get('total_wrong', 0) + 1 self.bury(next_review) incorrect = previous_srs = wrong def bury(self, next_review=timedelta(hours=4)): if not self.backup: self.backup = model_to_dict(self) if isinstance(next_review, timedelta): self.next_review = datetime.now() + next_review else: self.next_review = next_review self.save() def reset(self): self.srs_level = None self.next_review = None self.save() def undo(self): if self.backup: dict_to_model(Card, self.backup).save() @classmethod def iter_quiz(cls, **kwargs): db_cards = list(cls.search(**kwargs)) random.shuffle(db_cards) return iter(db_cards) @classmethod def iter_due(cls, **kwargs): return cls.iter_quiz(due=True, **kwargs) @classmethod def search(cls, q_str='', deck=None, tags=None, due=None, offset=0, limit=None): """ :param q_str: :param deck: :param tags: :param bool|None|timedelta|datetime due: :param offset: :param limit: :return: """ query = cls.select() due_is_set = False note_keys = None result = parse_query(q_str) if result: for seg in result: if len(seg) == 1: if note_keys is None: note_keys = set() for srs_note in Note.select(Note.data): note_keys.update(srs_note.data.keys()) note_keys = tuple(note_keys) q_note = Note.data[note_keys[0]].contains(seg[0]) for k in note_keys[1:]: q_note |= Note.data[k].contains(seg[0]) query = query.switch(cls).join(Note).where(q_note) else: if seg[0] == 'due': due_is_set = True if seg[2].lower() == 'true': query = query.switch(cls).where(cls.next_review < datetime.now()) elif seg[2].lower() == 'false': query = query.switch(cls).where(cls.next_review.is_null(True)) else: dur_sec = pytimeparse.parse(seg[2]) if dur_sec: _due = datetime.now() + timedelta(seconds=dur_sec) else: _due = dateutil.parser.parse(seg[2]) query = query.switch(cls).where(cls.next_review < _due) elif seg[0] == 'deck': deck_q = (Deck.name == seg[2]) if seg[1] != '=': deck_q = (deck_q | Deck.name.startswith(seg[2] + '::')) query = query.switch(cls).join(CardDeck).join(Deck).where(deck_q) elif seg[0] == 'tag': if seg[1] == '=': query = query.switch(cls).join(Note).join(NoteTag).join(Tag)\ .where(Tag.name == seg[2]) else: query = query.switch(cls).join(Note).join(NoteTag).join(Tag)\ .where(Tag.name.contains(seg[2])) else: if seg[1] == '=': query = query.switch(cls).join(Note).where(Note.data[seg[0]] == seg[2]) elif seg[1] == '>': query = query.switch(cls).join(Note).where(Note.data[seg[0]] > seg[2]) elif seg[1] == '<': query = query.switch(cls).join(Note).where(Note.data[seg[0]] < seg[2]) else: query = query.switch(cls).join(Note).where(Note.data[seg[0]].contains(seg[2])) if due is True: query = query.switch(cls).where(cls.next_review < datetime.now()) elif due is False: query = query.switch(cls).where(cls.next_review.is_null(True)) elif isinstance(due, timedelta): query = query.switch(cls).where(cls.next_review < datetime.now() + due) elif isinstance(due, datetime): query = query.switch(cls).where(cls.next_review < due) else: if not due_is_set: query = query.where((cls.next_review < datetime.now()) | cls.next_review.is_null(True)) if deck: query = query.switch(cls).join(CardDeck).join(Deck).where(Deck.name.startswith(deck + '::') | (Deck.name == deck)) if tags: for tag in tags: query = query.switch(cls).join(Note).join(NoteTag).join(Tag).where(Tag.name.contains(tag)) query = query.order_by(cls.next_review.desc()) if offset: query = query.offset(offset) if limit: query = query.limit(limit) return query
class Product(BaseModel): product_name = peewee.CharField() description = peewee.CharField() tags = peewee.ManyToManyField(Tag) price = peewee.DecimalField() quantity = peewee.IntegerField()
class User(Base): hobbies = pw.ManyToManyField(Hobby, backref='users')
class Note(BaseModel): data = sqlite_ext.JSONField() model = pv.ForeignKeyField(Model, backref='notes') media = pv.ManyToManyField(Media, backref='notes', on_delete='cascade') tags = pv.ManyToManyField(Tag, backref='notes', on_delete='cascade') h = pv.TextField(unique=True) def mark(self, tag): Tag.get_or_create(name=tag)[0].notes.add(self) def unmark(self, tag): Tag.get_or_create(name=tag)[0].notes.remove(self) def rename_field(self, old_name, new_name): for db_note in Note.select(Note.data, Note.model_id).where(model_id=self.model_id): if old_name in db_note.data.keys(): db_note.data[new_name] = db_note.data.pop(old_name) db_note.save() @classmethod def add(cls, data, model, card_to_decks: dict, media: dict=None, tags: list=None): if media is None: media = dict() if tags is None: tags = list() with database.atomic(): if isinstance(model, int) or (isinstance(model, str) and model.isdigit()): db_model = Model.get(id=int(model)) elif isinstance(model, Model): db_model = model else: db_model = Model.get(name=model) db_note = cls.create( data=data, model_id=db_model.id ) for template, deck in card_to_decks.items(): if isinstance(deck, int) or (isinstance(deck, str) and deck.isdigit()): db_deck = Deck.get(id=int(deck)) elif isinstance(deck, Deck): db_deck = deck else: db_deck = Deck.get_or_create(name=deck)[0] if isinstance(template, int) or (isinstance(template, str) and template.isdigit()): db_template = Template.get(id=int(template)) elif isinstance(template, Template): db_template = template else: db_template = Template.get(model_id=db_model.id, name=template) Card.create( note_id=db_note.id, deck_id=db_deck.id, template_id=db_template.id ) for media_name, media_path in media.items(): type_ = { 'audio': MediaType.audio, 'font': MediaType.font }.get(magic.from_file(media_path, mime=True).split('/')[0], MediaType.image) with open(media_path, 'rb') as f: Media.create( name=media_name, data=f.read(), type_=type_ ) for tag_name in tags: Tag.get_or_create(name=tag_name)[0].notes.add(db_note) return db_note @classmethod def search(cls, model_name=None, deck_name=None, tags=None, data=None, **kwargs): db_query = cls.select() if deck_name: db_query = db_query \ .join(Card).join(Deck) \ .where(Deck.name.contains(deck_name)) db_query = cls._build_query(db_query, model_name=model_name, tags=tags, data=data, **kwargs) return db_query @classmethod def _build_query(cls, db_query, model_name=None, tags=None, data=None, **kwargs): if data is None: data = dict() data.update(kwargs) db_query = db_query.switch(cls) if data: for k, v in data.items(): db_query = db_query.where(cls.data[k].contains(v)) if model_name: db_query = db_query \ .join(Model) \ .where(Model.name.contains(model_name)) if tags: db_query = db_query\ .join(NoteTag).join(Tag)\ .where(~Tag.name.not_in(tags)) return db_query def to_viewer(self): d = model_to_dict(self) d['cards'] = '<br/>'.join(c.html for c in self.cards) d['tags'] = [t.name for t in self.tags] return d viewer_config = { 'renderer': { 'cards': 'html' }, 'colWidth': { 'cards': 400 } }