class History(models.Model, GetByUniqueMixin): class Meta: app_label = 'webooks' db_table = 'webooks_history' verbose_name = verbose_name_plural = _('阅读历史') ordering = ["datetime"] account = models.ForeignKey(Account, verbose_name=_("账号")) book = models.ForeignKey(Book, verbose_name=_("书")) chapter = models.ForeignKey(Chapter, verbose_name=_("章节"), blank=True, null=True) datetime = models.DateTimeField(_("阅读时间"), default=now, blank=True, null=True) def __unicode__(self): return "%s: %s" %(self.book.name, self.chapter.title) @classmethod def update_or_create(cls, account_id, book_id, chapter_id=""): queries = { "account_id": account_id, "book_id": book_id } item = cls.get_by_queries(**queries) if not item: item = cls(account_id=account_id, book_id=book_id, chapter_id=chapter_id) else: item.chapter_id = chapter_id item.datetime = now() item.save()
class Collect(models.Model): class Meta: app_label = 'webooks' db_table = 'webooks_collect' verbose_name = verbose_name_plural = _('收藏') account = models.ForeignKey(Account, verbose_name=_("用户id")) book = models.ForeignKey(Book, verbose_name=_("书")) datetime = models.DateTimeField(_("收藏时间"), default=now)
class Strategy(models.Model, GetByUniqueMixin): class Meta: app_label = 'webooks' db_table = 'webooks_strategy' verbose_name = verbose_name_plural = _('更新策略') name = models.CharField(_('名字'), max_length=const.DB_NAME_LENGTH, blank=True, null=True) type = models.SmallIntegerField(_('更新策略'), choices=const.UPDATE_STRATEGY_CHOICES, default=const.UPDATE_BY_TIME, blank=True, null=True) data = models.CharField(_('具体策略'), max_length=const.DB_MIDDLE_LENGTH, blank=True, null=True) def __unicode__(self): return "%s : %s" % (self.name, self.data) @classmethod def get_times(cls, time=now().time()): """ 目前先做小时级别的更新,通过data做模糊匹配,取出strategy_id, 反查需要更新的books """ hour = time.strftime("%H") result = "%s:00" % hour return [ result, ] @classmethod def get_time_strategies(cls, times): query = Q(type=const.UPDATE_BY_TIME) for time in times: query |= Q(data__icontains=time) return cls.objects.all().filter(query)
class Tag(models.Model): class Meta: app_label = 'webooks' db_table = "webooks_tag" verbose_name = verbose_name_plural = _('标签') name = models.CharField(_(u'名字'), max_length=const.DB_NAME_LENGTH, unique=True) def __unicode__(self): return self.name
class Account(models.Model): class Meta: app_label = 'webooks' verbose_name = verbose_name_plural = _('账号') unique_together = ("id", "src_from") id = models.CharField(_("账号id"), max_length=const.DB_NAME_LENGTH, primary_key=True) src_from = models.SmallIntegerField(_("来源"), choices=const.THIRD_FROM_CHOICES, default=const.FROM_LOCAL_KEY) def __unicode__(self): return u"%s: %s" % (self.get_src_from_display(), self.src_from) @property def third(self): third_from_display = self.get_src_from_display() if third_from_display == "local": return None else: return getattr(self, third_from_display)
class Meta: app_label = 'webooks' verbose_name = verbose_name_plural = _('微信账号')
class Meta: app_label = 'webooks' verbose_name = verbose_name_plural = _('账号') unique_together = ("id", "src_from")
class Meta: app_label = 'webooks' db_table = "webooks_tag" verbose_name = verbose_name_plural = _('标签')
class Meta: app_label = 'webooks' db_table = 'webooks_history' verbose_name = verbose_name_plural = _('阅读历史') ordering = ["datetime"]
class Meta: app_label = 'webooks' db_table = 'webooks_collect' verbose_name = verbose_name_plural = _('收藏')
class Meta: app_label = 'webooks' db_table = 'webooks_book' verbose_name = verbose_name_plural = _('书') ordering = ['id', 'score']
class Book(models.Model, GetByUniqueMixin): class Meta: app_label = 'webooks' db_table = 'webooks_book' verbose_name = verbose_name_plural = _('书') ordering = ['id', 'score'] name = models.CharField(_(u'书名'), max_length=const.DB_NAME_LENGTH) tags = models.ManyToManyField(Tag, verbose_name=_('标签'), blank=True, null=True, through='BookTagShip', related_name='books') is_over = models.BooleanField(_(u'是否完结'), default=False) author = models.CharField(_(u'作者'), max_length=const.DB_NAME_LENGTH, default="", blank=True, null=True) description = models.CharField(_(u'描述'), max_length=const.DB_DESCRIPTION_LENGTH, default="", blank=True, null=True) score = models.BigIntegerField(_(u'评分'), default=0, blank=True, null=True) lock = models.BooleanField(_(u'锁定'), default=False) src_name = models.CharField(_(u'来源名'), max_length=const.DB_SHORT_LENGTH, blank=True, null=True, default="") src_id = models.CharField(_(u'来源id'), max_length=const.DB_MIDDLE_LENGTH, blank=True, null=True, default="") src_url = models.CharField(_(u'来源URL'), max_length=const.DB_URL_LENGTH, blank=True, null=True, default="") strategy = models.ForeignKey(Strategy, verbose_name=_(u'更新策略'), blank=True, null=True) def __unicode__(self): return self.name @property def chapters(self): chapters = self.chapter_set.all() if chapters: return chapters if settings.CHAPTER_LAZY_LOADING: self.lazy_loading() return self.chapter_set.all() @permalink def get_absolute_url(self): return ('book_detail', [self.id, ]) @permalink def get_api_url(self): return ('api_book_detail', [self.id, ]) @property def absolute_url(self): return settings.DOMAIN + self.get_absolute_url() @property def api_url(self): return self.get_api_url() @classmethod def get_or_create(cls, name, **kwargs): item = cls.get_by_unique(name=name) if not item: item = cls(name=name, **kwargs) item.save() return item def to_txt(self, path): if not path.endswith("txt"): path = "%s.txt" % path file_handle = open(path, "w") chapters = self.chapter_set.all() for chapter in chapters: pages = chapter.page_set.all() title = unicode(chapter).encode('utf-8') file_handle.write(title) for page in pages: content = page.content file_handle.write(content.encode('utf-8')) file_handle.close() def lazy_loading(self): from webooks.middles import SourceFactory src = self.src_name source = SourceFactory.get_source(src) def check_book(): if any([self.author, self.description, self.score]): return False else: return True need_load = check_book() if need_load: source.get_book_detail(self) source.get_chapters(self)
class Meta: app_label = 'webooks' db_table = 'webooks_chapter' verbose_name = verbose_name_plural = _('章节') ordering = ['number']
class Chapter(models.Model, GetByUniqueMixin): class Meta: app_label = 'webooks' db_table = 'webooks_chapter' verbose_name = verbose_name_plural = _('章节') ordering = ['number'] title = models.CharField(_(u'章节名'), max_length=const.DB_NAME_LENGTH, default="", blank=True, null=True) number = models.IntegerField(_(u'章节号'), default=const.DB_NUMBER_DEFAULT) book = models.ForeignKey(Book, verbose_name=_('书')) lock = models.BooleanField(_(u'锁定'), default=False) content = models.TextField(_(u'内容'), default="", max_length=const.DB_CONTENT_LENGTH) src_url = models.CharField(_(u'来源URL'), max_length=const.DB_URL_LENGTH, blank=True, null=True, default="") def __unicode__(self): return "%s" %self.title @property def full_content(self): if self.content: return self.content else: if settings.CONTENT_LAZY_LOADING: self.lazy_loading() return self.content @permalink def get_api_url(self): return ('api_chapter_detail', [str(self.book_id), str(self.id)]) @property def before(self): queries = { "book_id": self.book_id, "number": self.number-1 } chapter = Chapter.get_by_queries(**queries) return chapter @property def after(self): queries = { "book_id": self.book_id, "number": self.number+1 } chapter = Chapter.get_by_queries(**queries) return chapter @classmethod def get_or_create(cls, book, number, **kwargs): item = cls.get_by_queries(book=book, number=number) if not item: item = cls(book=book, number=number, **kwargs) item.save() return item def lazy_loading(self): from webooks.middles import SourceFactory src = self.book.src_name source = SourceFactory.get_source(src) source.get_chapter_content(self)
class Meta: app_label = "webooks" db_table = "webooks_book_tag_ship" verbose_name = verbose_name_plural = _('书与标签')
class Meta: app_label = 'webooks' db_table = 'webooks_strategy' verbose_name = verbose_name_plural = _('更新策略')