class Article(Page): translators = ParentalManyToManyField( "author.Author", related_name="translations_by_author", blank=True) strap = models.TextField(blank=True) content = RichTextField( blank=True, verbose_name="Content - Deprecated. Use 'MODULAR CONTENT' instead.") modular_content = StreamField([ ('paragraph', ParagraphBlock()), ('n_column_paragraph', NColumnParagraphBlock()), ('paragraph_with_map', ParagraphWithMapBlock()), ('paragraph_with_page', ParagraphWithPageBlock()), ('paragraph_with_quote', ParagraphWithBlockQuoteBlock()), ('full_width_quote', FullWidthBlockQuote()), ('video_with_quote', VideoWithQuoteBlock()), ('image_with_quote_and_paragraph', ImageWithQuoteAndParagraphBlock()), ('full_width_image', FullWidthImageBlock()), ('columnar_image_with_text', NColumnImageWithTextBlock()), ('full_width_embed', FullWidthEmbedBlock()), ('paragraph_with_embed', ParagraphWithEmbedBlock()), ('paragraph_with_raw_embed', ParagraphWithRawEmbedBlock()), ], null=True, blank=True) show_modular_content = models.BooleanField(default=False) language = models.CharField(max_length=7, choices=settings.LANGUAGES) original_published_date = models.DateField(null=True, blank=True) show_day = models.BooleanField(default=True) show_month = models.BooleanField(default=True) show_year = models.BooleanField(default=True) featured_image = models.ForeignKey('core.AffixImage', null=True, blank=True, on_delete=models.SET_NULL) show_featured_image = models.BooleanField(default=True) categories = ParentalManyToManyField("category.Category", related_name="articles_by_category") locations = ParentalManyToManyField("location.Location", related_name="articles_by_location", blank=True) content_panels = Page.content_panels + [ FieldPanel('strap'), InlinePanel('authors', label='Authors', min_num=1), M2MFieldPanel('translators'), FieldPanel('language'), MultiFieldPanel([ FieldPanel('original_published_date'), FieldRowPanel([ FieldPanel('show_day', classname="col4"), FieldPanel('show_month', classname="col4"), FieldPanel('show_year', classname="col4") ]) ], 'Date'), FieldPanel('content'), MultiFieldPanel([ ImageChooserPanel('featured_image'), FieldPanel('show_featured_image'), ], 'Cover Image'), FieldPanel('categories'), M2MFieldPanel('locations'), ] tags = ClusterTaggableManager(through=ArticleTag, blank=True) promote_panels = Page.promote_panels + [ FieldPanel('tags'), ] search_fields = Page.search_fields + [ index.SearchField('title', partial_match=True, boost=SearchBoost.TITLE), index.SearchField( 'get_authors', partial_match=True, boost=SearchBoost.AUTHOR), index.SearchField( 'get_translators', partial_match=True, boost=SearchBoost.AUTHOR), index.SearchField( 'strap', partial_match=True, boost=SearchBoost.DESCRIPTION), index.SearchField( 'content', partial_match=True, boost=SearchBoost.CONTENT), index.SearchField( 'modular_content', partial_match=True, boost=SearchBoost.CONTENT), index.SearchField('get_district_from_location', partial_match=True, boost=SearchBoost.LOCATION), index.SearchField('language', partial_match=True), index.FilterField('language'), index.FilterField('get_search_type'), index.FilterField('get_categories'), index.FilterField('get_minimal_locations'), index.FilterField('get_authors_or_photographers'), index.FilterField('title'), index.FilterField('get_state_from_locations') ] def __str__(self): return self.title def get_authors(self): return [ article_author.author.name for article_author in self.authors.all() ] def get_author_role_map(self, **kwargs): authors_with_role = kwargs['authors_with_role'] temp = defaultdict(list) for awr in authors_with_role: role = awr.role if role: temp[role.name].append(awr.author) else: temp['None'].append(awr.author) return dict((key, tuple(val)) for key, val in temp.items()) def beginning_authors_with_role(self): return self.get_author_role_map(authors_with_role=self.authors.filter( show_in_beginning=True).all()) def end_authors_with_role(self): return self.get_author_role_map(authors_with_role=self.authors.filter( show_in_end=True).all()) def get_translators(self): return [translator.name for translator in self.translators.all()] def get_authors_or_photographers(self): return self.get_authors() def get_district_from_location(self): return [location.address for location in self.locations.all()] def get_minimal_locations(self): return [location.minimal_address for location in self.locations.all()] def get_state_from_locations(self): return [location.state for location in self.locations.all()] def get_context(self, request, *args, **kwargs): try: site = Site.objects.get(hostname=request.get_host()) except Site.DoesNotExist: site = Site.objects.filter(is_default_site=True)[0] return { 'article': self, 'beginning_authors_with_role': self.beginning_authors_with_role(), 'end_authors_with_role': self.end_authors_with_role(), 'request': request, 'site': site } def get_absolute_url(self): name = "article-detail" return reverse(name, kwargs={"slug": self.slug}) def get_translation(self): return get_translations_for_page(self) # Elastic search related methods def get_search_type(self): categories = [category.name for category in self.categories.all()] if 'VideoZone' in categories: return 'video' elif 'AudioZone' in categories: return 'audio' else: return 'article' def get_categories(self): return [category.name for category in self.categories.all()] def related_articles(self): if not self.pk: # In preview mode return [] max_results = getattr(settings, "MAX_RELATED_RESULTS", 4) es_backend = get_search_backend() mapping = Elasticsearch6Mapping(self.__class__) minimal_locations = "" if (self.get_minimal_locations()): minimal_locations = self.get_minimal_locations() state_locations = "" if (self.get_state_from_locations()): state_locations = self.get_state_from_locations() authors_of_article = "" if self.authors: for article_author in self.authors.all(): authors_of_article += article_author.author.name query = { "track_scores": "true", "query": { "bool": { "must": [{ "multi_match": { "fields": ["*language_filter"], "query": self.language } }, { "term": { "live_filter": "true" } }], "must_not": [{ "term": { "title_filter": self.title } }], "should": [{ "multi_match": { "fields": ["*get_authors_or_photographers_filter"], "query": authors_of_article, "type": "cross_fields", "operator": "and" } }, { "multi_match": { "fields": ["*get_authors"], "query": authors_of_article, "type": "cross_fields", "operator": "and" } }, { "multi_match": { "fields": ["*get_minimal_locations_filter"], "query": ' '.join(minimal_locations), "type": "cross_fields", "operator": "and" } }, { "multi_match": { "fields": ["*get_state_from_locations_filter"], "query": ' '.join(state_locations), "type": "cross_fields", "operator": "and" } }, { "match": { "title": self.title } }], "minimum_should_match": 1 } }, "sort": [{ "_score": { "order": "desc" } }, { "article_article__get_authors_or_photographers_filter": { "order": "desc" } }, { "album_album__get_authors_or_photographers_filter": { "order": "desc" } }, { "face_face__get_authors_or_photographers_filter": { "order": "desc" } }, { "first_published_at_filter": "desc" }] } try: mlt = es_backend.es.search(doc_type=mapping.get_document_type(), body=query) except ConnectionError: return [] # Get pks from results pks = [hit['_source']['pk'] for hit in mlt['hits']['hits']][:max_results] # Initialise results dictionary results = dict((str(pk), None) for pk in pks) # Find objects in database and add them to dict queryset = self._meta.default_manager.filter(pk__in=pks) for obj in queryset: results[str(obj.pk)] = obj # Return results in order given by ElasticSearch return [results[str(pk)] for pk in pks if results[str(pk)]]
class Face(Page): image = models.ForeignKey("core.AffixImage", related_name="face_for_image", null=True, on_delete=models.SET_NULL) location = models.ForeignKey("location.Location", null=True, on_delete=models.SET_NULL, verbose_name="Place of Origin") additional_info = RichTextField(blank=True) language = models.CharField(max_length=7, choices=settings.LANGUAGES) occupation = models.CharField( max_length=100, null=True, blank=True, help_text="Enter the occupation of the person") occupation_of_parent = models.CharField(max_length=100, null=True, blank=True) adivasi = models.CharField(max_length=100, null=True, blank=True) quote = RichTextField(blank=True) child = models.BooleanField(default=False) age = models.IntegerField(null=True, blank=True) GENDER_CHOICES = ( ('F', 'Female'), ('M', 'Male'), ('T', 'Transgender'), ) gender = models.CharField(max_length=1, choices=GENDER_CHOICES, null=True, blank=True) def __str__(self): return "{0} {1}".format(self.title, self.location.district) @property def featured_image(self): return self.image @property def title_to_share(self): title = "Meet " + self.title title += ", " + self.occupation if self.occupation else "" title += " from " + self.location.district title += ", " + self.location.state return title @property def locations(self): return [self.location] @property def photographers(self): return self.image.photographers.all() def get_authors_or_photographers(self): return [photographer.name for photographer in self.photographers] search_fields = Page.search_fields + [ index.SearchField('title', partial_match=True, boost=SearchBoost.TITLE), index.FilterField('image'), index.SearchField( 'additional_info', partial_match=True, boost=SearchBoost.CONTENT), index.FilterField('location'), index.RelatedFields('location', [ index.SearchField('name'), index.SearchField('block'), index.SearchField('district'), index.SearchField('state'), index.SearchField('panchayat'), ]), index.SearchField('occupation'), index.SearchField('occupation_of_parent'), index.SearchField('quote'), index.SearchField('get_locations_index', partial_match=True, boost=SearchBoost.LOCATION), index.SearchField('get_photographers_index', partial_match=True, boost=SearchBoost.AUTHOR), index.SearchField('adivasi'), index.SearchField('language'), index.FilterField('get_search_type'), index.FilterField('language'), index.FilterField('get_minimal_locations'), index.FilterField('get_authors_or_photographers') ] def get_locations_index(self): return self.image.get_locations_index() def get_minimal_locations(self): return [self.location.minimal_address] def get_photographers_index(self): return self.image.get_all_photographers() def get_search_type(self): return self.__class__.__name__.lower() content_panels = Page.content_panels + [ ImageChooserPanel('image'), M2MFieldPanel('location'), FieldPanel('adivasi'), MultiFieldPanel([ FieldPanel('child'), FieldPanel('occupation'), FieldPanel('occupation_of_parent'), FieldPanel('age'), FieldPanel('gender'), ], heading="Personal details", classname="collapsible "), MultiFieldPanel([ FieldPanel('additional_info'), FieldPanel('language'), FieldPanel('quote'), ], heading="Additional details", classname="collapsible"), ] def get_absolute_url(self): name = "face-detail-single" return reverse(name, kwargs={ "alphabet": self.location.district[0].lower(), "slug": self.slug }) def get_context(self, request, *args, **kwargs): return { 'faces': [self], 'alphabet': self.location.district[0].lower(), 'request': request }
class Article(Page): authors = M2MField("author.Author", related_name="articles_by_author") translators = M2MField("author.Author", related_name="translations_by_author", blank=True) strap = models.TextField(blank=True) content = RichTextField() language = models.CharField(max_length=7, choices=settings.LANGUAGES) original_published_date = models.DateField(null=True, blank=True) featured_image = models.ForeignKey('core.AffixImage', null=True, blank=True, on_delete=models.SET_NULL) categories = M2MField("category.Category", related_name="articles_by_category") locations = M2MField("location.Location", related_name="articles_by_location") content_panels = Page.content_panels + [ FieldPanel('strap'), M2MFieldPanel('authors'), M2MFieldPanel('translators'), FieldPanel('language'), FieldPanel('original_published_date'), FieldPanel('content'), ImageChooserPanel('featured_image'), FieldPanel('categories'), M2MFieldPanel('locations'), ] search_fields = Page.search_fields + ( index.SearchField('title', partial_match=True), index.SearchField('authors', partial_match=True, boost=2), index.SearchField('translators', partial_match=True, boost=2), index.SearchField('strap', partial_match=True), index.SearchField('content', partial_match=True), index.FilterField('categories'), index.SearchField('locations', partial_match=True, boost=2), index.FilterField('language'), ) def __str__(self): return self.title def get_context(self, request, *args, **kwargs): try: site = Site.objects.get(hostname=request.get_host()) except Site.DoesNotExist: site = Site.objects.filter(is_default_site=True)[0] return {'article': self, 'request': request, 'site': site} def get_absolute_url(self): name = "article-detail" return reverse(name, kwargs={"slug": self.slug}) def related_articles(self): if not self.pk: # In preview mode return [] max_results = getattr(settings, "MAX_RELATED_RESULTS", 4) es_backend = get_search_backend() mapping = ElasticSearchMapping(self.__class__) search_fields = [] for ii in self.search_fields: if getattr(ii, "boost", None): search_fields.append("{0}^{1}".format(ii.field_name, ii.boost)) else: search_fields.append(ii.field_name) query = { "query": { "filtered": { "filter": { "term": { "live_filter": True } }, "query": { "more_like_this": { "docs": [{ "_id": mapping.get_document_id(self), "_type": mapping.get_document_type() }], "min_doc_freq": 1, "min_term_freq": 2, "max_query_terms": 500, "min_word_length": 4, "fields": search_fields } } } } } try: mlt = es_backend.es.search(index=es_backend.index_name, doc_type=mapping.get_document_type(), body=query) except ConnectionError: return [] # Get pks from results pks = [hit['_source']['pk'] for hit in mlt['hits']['hits']][:max_results] # Initialise results dictionary results = dict((str(pk), None) for pk in pks) # Find objects in database and add them to dict queryset = self._default_manager.filter(pk__in=pks) for obj in queryset: results[str(obj.pk)] = obj # Return results in order given by ElasticSearch return [results[str(pk)] for pk in pks if results[str(pk)]]