class Event(index.Indexed, ClusterableModel): title = models.CharField(max_length=300) date_created = models.DateTimeField(default=timezone.now) last_modified = models.DateTimeField(auto_now=True) summary = models.CharField(max_length=500, blank=True) description = MarkdownField() early_registration_deadline = models.DateTimeField(null=True, blank=True) registration_deadline = models.DateTimeField(null=True, blank=True) submission_deadline = models.DateTimeField(null=True, blank=True) start_date = models.DateTimeField() end_date = models.DateTimeField(null=True, blank=True) location = models.CharField(max_length=300) tags = ClusterTaggableManager(through=EventTag, blank=True) external_url = models.URLField(blank=True) objects = EventQuerySet.as_manager() submitter = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET(get_sentinel_user)) search_fields = [ index.SearchField('title', partial_match=True, boost=10), index.SearchField('description', partial_match=True), index.FilterField('date_created'), index.FilterField('start_date'), index.FilterField('end_date'), index.FilterField('last_modified'), index.FilterField('submission_deadline'), index.FilterField('early_registration_deadline'), index.FilterField('registration_deadline'), index.SearchField('location', partial_match=True), index.RelatedFields('tags', [ index.SearchField('name'), ]), index.RelatedFields('submitter', [ index.SearchField('username'), index.SearchField('email', partial_match=True), index.SearchField('get_full_name', partial_match=True), ]), ] @property def live(self): return True def get_absolute_url(self): return reverse('home:event-detail', kwargs={'pk': self.pk}) @classmethod def get_list_url(cls): return reverse('home:event-list') def __str__(self): return "{0} posted by {1} on {2}".format( self.title, self.submitter.username, self.date_created.strftime('%c'))
class Job(index.Indexed, ClusterableModel): title = models.CharField(max_length=300, help_text=_('Job posting title')) date_created = models.DateTimeField(default=timezone.now) application_deadline = models.DateField( blank=True, null=True, help_text=_('Optional deadline for applications')) last_modified = models.DateTimeField(auto_now=True) summary = models.CharField(max_length=500, blank=True, help_text=_('Brief summary of job posting.')) description = MarkdownField() tags = ClusterTaggableManager(through=JobTag, blank=True) external_url = models.URLField(blank=True) submitter = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='jobs', on_delete=models.SET(get_sentinel_user)) objects = JobQuerySet.as_manager() search_fields = [ index.SearchField('title', partial_match=True, boost=10), index.SearchField('description', partial_match=True), index.FilterField('date_created'), index.FilterField('last_modified'), index.FilterField('application_deadline'), index.RelatedFields('tags', [ index.SearchField('name'), ]), index.RelatedFields('submitter', [ index.SearchField('username'), index.SearchField('email', partial_match=True), index.SearchField('get_full_name', partial_match=True), ]), ] @property def live(self): return True def get_absolute_url(self): return reverse('home:job-detail', kwargs={'pk': self.pk}) @classmethod def get_list_url(cls): return reverse('home:job-list') def __str__(self): return "{0} posted by {1} on {2}".format( self.title, self.submitter.username, self.date_created.strftime('%c')) @property def owner(self): return self.submitter
def test_select_on_queryset_with_reverse_foreign_key(self): fields = index.RelatedFields( "categories", [index.RelatedFields("category", [index.SearchField("name")])]) queryset = fields.select_on_queryset(ManyToManyBlogPage.objects.all()) # reverse ForeignKey should be prefetch_related self.assertIn("categories", queryset._prefetch_related_lookups) self.assertFalse(queryset.query.select_related)
class Book(index.Indexed, models.Model): title = models.CharField(max_length=255) authors = models.ManyToManyField(Author, related_name="books") publication_date = models.DateField() number_of_pages = models.IntegerField() tags = TaggableManager() search_fields = [ index.SearchField("title", partial_match=True, boost=2.0), index.AutocompleteField("title"), index.FilterField("title"), index.FilterField("authors"), index.RelatedFields("authors", Author.search_fields), index.FilterField("publication_date"), index.FilterField("number_of_pages"), index.RelatedFields( "tags", [ index.SearchField("name"), index.FilterField("slug"), ], ), index.FilterField("tags"), ] @classmethod def get_indexed_objects(cls): indexed_objects = super(Book, cls).get_indexed_objects() # Don't index books using Book class that they have a more specific type if cls is Book: indexed_objects = indexed_objects.exclude( id__in=Novel.objects.values_list("book_ptr_id", flat=True)) indexed_objects = indexed_objects.exclude( id__in=ProgrammingGuide.objects.values_list("book_ptr_id", flat=True)) # Exclude Books that have the title "Don't index me!" indexed_objects = indexed_objects.exclude(title="Don't index me!") return indexed_objects def get_indexed_instance(self): # Check if this object is a Novel or ProgrammingGuide and return the specific object novel = Novel.objects.filter(book_ptr_id=self.id).first() programming_guide = ProgrammingGuide.objects.filter( book_ptr_id=self.id).first() # Return the novel/programming guide object if there is one, otherwise return self return novel or programming_guide or self def __str__(self): return self.title
class EventHost(index.Indexed, models.Model): """ Meetup Event Host """ event_page = ParentalKey(EventPage, on_delete=models.CASCADE, related_name="event_hosts") host_count = models.IntegerField(blank=True, null=True) member = models.ForeignKey(Member, on_delete=models.SET_NULL, blank=True, null=True, related_name="+") intro = models.TextField(blank=True, null=True) join_date = models.DateTimeField(blank=True, null=True) name = models.CharField(max_length=255, blank=True, null=True) photo = models.ForeignKey(Photo, on_delete=models.SET_NULL, blank=True, null=True, related_name="+") panels = [ FieldPanel("name"), FieldPanel("member"), FieldPanel("host_count"), FieldPanel("intro"), FieldPanel("join_date"), FieldPanel("photo"), ] # Search index configuration search_fields = [ index.RelatedFields("event_page", EventPage.search_fields), index.SearchField("host_count"), index.SearchField("member"), index.SearchField("intro"), index.SearchField("join_date"), index.SearchField("name"), index.RelatedFields("photo", Photo.search_fields), ] # api fields api_fields = [ APIField("host_count"), APIField("member_id"), APIField("intro"), APIField("time"), APIField("name"), APIField("photo"), ]
class Novel(Book): setting = models.CharField(max_length=255) protagonist = models.OneToOneField(Character, related_name='+', null=True, on_delete=models.SET_NULL) search_fields = Book.search_fields + [ index.SearchField('setting', partial_match=True), index.RelatedFields('characters', [ index.SearchField('name', boost=0.25), ]), index.RelatedFields('protagonist', [ index.SearchField('name', boost=0.5), ]), ]
class Lap(index.Indexed, models.Model): racer = models.ForeignKey(Racer, on_delete=models.CASCADE) group = models.ForeignKey(Group, on_delete=models.CASCADE) raceclass = models.ForeignKey(RaceClass, on_delete=models.CASCADE) car = models.ForeignKey(Car, blank=True,on_delete=models.CASCADE) event = models.ForeignKey(Event,null=True,blank=True, on_delete=models.CASCADE) region = models.ForeignKey(Region,null=True,blank=True, on_delete=models.CASCADE) track = models.ForeignKey(Track, on_delete=models.CASCADE) time = models.FloatField() lap_date = models.DateField("Lap date") best = models.BooleanField("Is Best?") @property def key(self): return "%s_%s_%s_%s_%s" % (self.racer.name, self.group.short_name, self.raceclass.short_name, self.track.short_name, self.lap_date) search_fields = [ index.FilterField('best'), index.FilterField('lap_date'), index.RelatedFields('racer', [ index.SearchField('name', partial_match=True), ]), index.RelatedFields('raceclass', [ index.SearchField('name', partial_match=True), ]), index.RelatedFields('track', [ index.SearchField('name', partial_match=True), ]), ] panels = [ FieldPanel('region', widget=forms.Select), FieldPanel('racer', widget=forms.Select), FieldPanel('raceclass', widget=forms.Select), FieldPanel('car', widget=forms.Select), FieldPanel('group', widget=forms.Select), FieldPanel('event', widget=forms.Select), FieldPanel('track', widget=forms.Select), FieldPanel('time'), FieldPanel('lap_date'), FieldPanel('best'), ] def __str__(self): return str(self.key) class Meta: verbose_name_plural = 'laps'
class Facet(index.Indexed, ClusterableModel): facet_type = models.ForeignKey(FacetType, blank=True, null=True, on_delete=models.CASCADE) title = models.CharField(max_length=64) api_fields = [APIField('facet_type'), APIField('title')] panels = [FieldPanel('facet_type'), FieldPanel('title', 'full')] search_fields = [ index.RelatedFields('facet_type', [index.SearchField('title')]), index.SearchField('title') ] objects = FacetManager() class Meta: ordering = ['title'] unique_together = [['facet_type', 'title']] def __str__(self): return '{}: {}'.format(self.facet_type, self.title) def natural_key(self): return self.facet_type.natural_key() + (self.title, )
class Composition(index.Indexed, models.Model): # Note: calling unescape on the title below is only ok because the input is # being sanitized by the RichTextField. title = RichTextField(features=['bold', 'italic']) composer = models.ForeignKey('Person', null=True, blank=False, on_delete=models.SET_NULL, related_name='+') def __str__(self): return unescape(strip_tags(self.title)) def display_title(self): return str(self) def autocomplete_label(self): return "{} - {}".format(unescape(strip_tags(self.title)), self.composer) panels = [ FieldPanel('title'), AutocompletePanel('composer', target_model='main.Person') ] search_fields = [ index.SearchField('title', partial_match=True), index.RelatedFields('composer', [ index.SearchField('first_name', partial_match=True), index.SearchField('last_name', partial_match=True), ]), ]
class OperatorPage(BasePage): pseudonym = models.TextField() full_name = models.TextField(null=True, blank=True) bio = models.TextField(null=True, blank=True) tags = ClusterTaggableManager(through=OperatorPageTag, blank=True) portrait = StreamField([('image', PlainImageBlock(icon='picture')), ]) portfolio = StreamField([('image', PlainImageBlock(icon='picture')), ], null=True, blank=True) companies = ParentalManyToManyField(CompanyPage, null=True, blank=True) reviews = StreamField([('review', ReviewBlock(icon='group')), ], null=True, blank=True) search_fields = Page.search_fields + [ # Inherit search_fields from Page index.SearchField('full_name'), index.SearchField('reviews'), index.RelatedFields('tags', [ index.SearchField('name') ]), ] content_panels = BasePage.content_panels + [ StreamFieldPanel('portrait'), FieldPanel('pseudonym'), FieldPanel('full_name'), FieldPanel('bio'), FieldPanel('tags'), StreamFieldPanel('portfolio'), FieldPanel('companies'), StreamFieldPanel('reviews'), ] parent_page_types = ['Operators'] subpage_types = [] template = 'generic_page.html'
class TagCaption(index.Indexed, ClusterableModel): tags = TaggableManager('Теги', through=TagCaptionTag, blank=True) raw_content = RichTextField('Текст') @property def content(self): return richtext(self.raw_content) paneles = [FieldPanel('tags'), FieldPanel('content')] def __str__(self): return ' / '.join(self.tags.all().values_list('name', flat=True)) search_fields = [ index.SearchField('tags'), index.RelatedFields('tags', [ index.SearchField('slug'), index.FilterField('slug'), ]), ] api_fields = [ APIField('tags', serializer=serializers.TagSerializer()), APIField('content') ] class Meta: verbose_name = 'Примечание' verbose_name_plural = 'Примечания'
class PeopleIndexPage(BaseIndexPage): api_fields = BaseIndexPage.api_fields + [ APIField("peopleindex_person_relationship") ] content_panels = BaseIndexPage.content_panels + [ InlinePanel("peopleindex_person_relationship", label="People", panels=None, min_num=1) ] search_fields = BaseIndexPage.search_fields + [ index.RelatedFields("peopleindex_person_relationship", [index.SearchField("person")]) ] def people(self): return self.peopleindex_person_relationship.all().select_related( "person") def get_context(self, request): context = super().get_context(request) context["people"] = self.people() return context
class Journal(index.Indexed, ClusterableModel): name = models.CharField(max_length=255) url = models.URLField() issn = models.CharField(max_length=16, blank=True, help_text=_("Linking ISSN-L for this Journal")) description = MarkdownField() tags = TaggableManager(through=JournalTag, blank=True) panels = [ FieldPanel('name'), FieldPanel('url'), FieldPanel('issn'), FieldPanel('description', widget=forms.Textarea), FieldPanel('tags'), ] search_fields = [ index.SearchField('name', partial_match=True), index.SearchField('description', partial_match=True), index.SearchField('issn'), index.RelatedFields('tags', [ index.SearchField('name', partial_match=True), ]), ] def __lt__(self, other): if isinstance(other, Journal): return self.name < other.name raise TypeError("Unorderable types: {0} < {1}".format( Journal, type(other))) def __str__(self): return "{0} {1} {2}".format(self.name, self.url, self.issn)
class ContentPage(Page): parent_page_types = ['content.ContentIndexPage'] subpage_types = [] body = RichTextField( verbose_name=_('Body'), help_text=_('Content body'), ) category = ParentalKey('ContentCategory', null=True, on_delete=models.SET_NULL, verbose_name=_('Category'), help_text=_('Content category')) tags = ClusterTaggableManager(through='ContentPageTag', blank=True) # categories = ParentalManyToManyField('ContentCategory', blank=True, verbose_name=_('Categories'), # help_text=_('Content categories')) search_fields = Page.search_fields + [ index.SearchField('body', partial_match=True), index.SearchField('tags', partial_match=True), index.RelatedFields('category', [ index.SearchField('name', partial_match=True), ]), # index.RelatedFields('categories', [ # index.SearchField('name'), # ]), ] content_panels = Page.content_panels + [ MultiFieldPanel( [ FieldPanel('tags'), # FieldPanel('categories', widget=forms.CheckboxSelectMultiple), FieldPanel('category'), ], heading=_('Content information'), help_text=_('Content base information')), FieldPanel('body', classname="full"), InlinePanel('gallery_images', label="Gallery images", help_text=_('Content images')), ] api_fields = [ APIField('last_published_at'), APIField('body'), APIField('category'), APIField('tags'), APIField('gallery_images'), ] class Meta: verbose_name_plural = _('Content pages') verbose_name = _('Content page') permissions = (('import_content', _('Can import content')), )
def test_select_on_queryset_with_many_to_many(self): fields = index.RelatedFields('adverts', [ index.SearchField('title'), ]) queryset = fields.select_on_queryset(ManyToManyBlogPage.objects.all()) # ManyToManyField should be prefetch_related self.assertIn('adverts', queryset._prefetch_related_lookups) self.assertFalse(queryset.query.select_related)
def test_select_on_queryset_with_foreign_key(self): fields = index.RelatedFields('protagonist', [ index.SearchField('name'), ]) queryset = fields.select_on_queryset(Novel.objects.all()) # ForeignKey should be select_related self.assertFalse(queryset._prefetch_related_lookups) self.assertIn('protagonist', queryset.query.select_related)
def test_select_on_queryset_with_taggable_manager(self): fields = index.RelatedFields('tags', [ index.SearchField('name'), ]) queryset = fields.select_on_queryset(Novel.objects.all()) # Tags should be prefetch_related self.assertIn('tags', queryset._prefetch_related_lookups) self.assertFalse(queryset.query.select_related)
def test_select_on_queryset_with_reverse_many_to_many(self): fields = index.RelatedFields('manytomanyblogpage', [ index.SearchField('title'), ]) queryset = fields.select_on_queryset(Advert.objects.all()) # reverse ManyToManyField should be prefetch_related self.assertIn('manytomanyblogpage', queryset._prefetch_related_lookups) self.assertFalse(queryset.query.select_related)
def test_select_on_queryset_with_reverse_one_to_one(self): fields = index.RelatedFields('novel', [ index.SearchField('subtitle'), ]) queryset = fields.select_on_queryset(Book.objects.all()) # reverse OneToOneField should be select_related self.assertFalse(queryset._prefetch_related_lookups) self.assertIn('novel', queryset.query.select_related)
class AbstractDocument(CollectionMember, index.Indexed, models.Model): title = models.CharField(max_length=255, verbose_name=_('title')) file = models.FileField(upload_to='documents', verbose_name=_('file')) created_at = models.DateTimeField(verbose_name=_('created at'), auto_now_add=True) uploaded_by_user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_('uploaded by user'), null=True, blank=True, editable=False, on_delete=models.SET_NULL) tags = TaggableManager(help_text=None, blank=True, verbose_name=_('tags')) objects = DocumentQuerySet.as_manager() search_fields = CollectionMember.search_fields + [ index.SearchField('title', partial_match=True, boost=10), index.FilterField('title'), index.RelatedFields('tags', [ index.SearchField('name', partial_match=True, boost=10), ]), index.FilterField('uploaded_by_user'), ] def __str__(self): return self.title @property def filename(self): return os.path.basename(self.file.name) @property def file_extension(self): return os.path.splitext(self.filename)[1][1:] @property def url(self): return reverse('wagtaildocs_serve', args=[self.id, self.filename]) def get_usage(self): return get_object_usage(self) @property def usage_url(self): return reverse('wagtaildocs:document_usage', args=(self.id, )) def is_editable_by_user(self, user): from wagtail.documents.permissions import permission_policy return permission_policy.user_has_permission_for_instance( user, 'change', self) class Meta: abstract = True verbose_name = _('document')
class JanisBasePage(Page): parent_page_types = ['base.HomePage'] subpage_types = [] search_fields = Page.search_fields + [ index.RelatedFields('owner', [ index.SearchField('last_name', partial_match=True), index.FilterField('last_name'), ]) ] created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) author_notes = RichTextField( # max_length=DEFAULT_MAX_LENGTH, features=['ul', 'ol', 'link'], blank=True, verbose_name='Notes for authors (Not visible on the resident facing site)' ) def janis_url(self): url_page_type = self.janis_url_page_type page_slug = self.slug # TODO: Add other languages return os.environ["JANIS_URL"] + "/en/" + url_page_type + "/" + page_slug def janis_preview_url(self): revision = self.get_latest_revision() url_page_type = self.janis_url_page_type global_id = graphene.Node.to_global_id('PageRevisionNode', revision.id) return os.environ["JANIS_URL"] + "/en/preview/" + url_page_type + "/" + global_id # Default preview_url before janis_preview_url gets set def fallback_preview_url(self): return "https://alpha.austin.gov" # data needed to construct preview URLs for any language # [janis_url_base]/[lang]/preview/[url_page_type]/[global_id] # ex: http://localhost:3000/es/preview/information/UGFnZVJldmlzaW9uTm9kZToyMjg= def preview_url_data(self): revision = self.get_latest_revision() global_id = graphene.Node.to_global_id('PageRevisionNode', revision.id) return { "janis_url_base": os.environ["JANIS_URL"], "url_page_type": self.janis_url_page_type, "global_id": global_id } class Meta: abstract = True
class PersonPage(BasePage): person = models.ForeignKey(PersonModel, related_name="pages", on_delete=models.PROTECT) api_fields = BasePage.api_fields + [APIField("person")] content_panels = BasePage.content_panels + [SnippetChooserPanel("person")] search_fields = BasePage.search_fields + [ index.RelatedFields("person", Person.search_fields) ]
def test_select_on_queryset_with_one_to_one(self): fields = index.RelatedFields( "book_ptr", [ index.SearchField("title"), ], ) queryset = fields.select_on_queryset(Novel.objects.all()) # OneToOneField should be select_related self.assertFalse(queryset._prefetch_related_lookups) self.assertIn("book_ptr", queryset.query.select_related)
class PostPage(Page): body = MarkdownField() date = models.DateTimeField(verbose_name="Post date", default=datetime.datetime.today) excerpt = MarkdownField( verbose_name='excerpt', blank=True, ) header_image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+', ) categories = ParentalManyToManyField('marcas.MarcasCategory', blank=True) tags = ClusterTaggableManager(through='marcas.MarcasPageTag', blank=True) content_panels = Page.content_panels + [ ImageChooserPanel('header_image'), MarkdownPanel("body"), MarkdownPanel("excerpt"), FieldPanel('categories', widget=forms.CheckboxSelectMultiple), FieldPanel('tags'), ] search_fields = Page.search_fields + [ # Inherit search_fields from Page index.SearchField('body', partial_match=True), index.SearchField('excerpt', partial_match=True), index.FilterField('date'), index.RelatedFields('categories', [ index.SearchField('name'), ]), ] settings_panels = Page.settings_panels + [ FieldPanel('date'), ] @property def marcas_page(self): return self.get_parent().specific def get_context(self, request, *args, **kwargs): context = super(PostPage, self).get_context(request, *args, **kwargs) context['marcas_page'] = self.marcas_page context['post'] = self return context
class Platform(index.Indexed, ClusterableModel): name = models.CharField(max_length=255) active = models.BooleanField(default=True) description = MarkdownField(max_length=1024) date_created = models.DateTimeField(default=timezone.now) # last_updated = models.DateField(blank=True, null=True, help_text=_("Date of last update for the ABM platform itself.")) last_modified = models.DateTimeField(auto_now=True) open_source = models.BooleanField(default=False) featured = models.BooleanField(default=False) url = models.URLField(blank=True) repository_url = models.URLField(blank=True) tags = ClusterTaggableManager(through=PlatformTag, blank=True) @staticmethod def _upload_path(instance, filename): # FIXME: base in MEDIA_ROOT? return pathlib.Path('platforms', instance.platform.name, filename) panels = [ FieldPanel('name'), FieldPanel('url'), FieldPanel('description'), FieldPanel('active'), FieldPanel('open_source'), FieldPanel('featured'), FieldPanel('tags'), ] def get_all_tags(self): return ' '.join(self.tags.all().values_list('name', flat=True)) search_fields = [ index.SearchField('name', partial_match=True), index.SearchField('description', partial_match=True), index.FilterField('active'), index.FilterField('open_source'), index.RelatedFields('tags', [ index.SearchField('name'), ]), ] def __str__(self): return self.name def __lt__(self, other): if isinstance(other, Platform): return self.name < other.name raise TypeError("Unorderable types: {0} < {1}".format( Platform, type(other)))
class Definition(index.Indexed, ClusterableModel): glossary = models.ForeignKey(Glossary, on_delete=models.CASCADE, related_name="definitions") definition = models.TextField(blank=True) search_fields = [ index.FilterField("glossary"), index.RelatedFields("glossary", [ index.FilterField("locale"), ]), index.RelatedFields("terms", [ index.SearchField("term"), index.AutocompleteField("term"), ]), ] panels = [ FieldPanel("glossary"), InlinePanel("terms", label="Terms"), FieldPanel("definition"), ] def __str__(self): terms = self.terms.all().values_list("term", flat=True)[:5] return f"{', '.join(terms)}"
class Novel(Book): setting = models.CharField(max_length=255) protagonist = models.OneToOneField(Character, related_name="+", null=True, on_delete=models.SET_NULL) search_fields = Book.search_fields + [ index.SearchField("setting", partial_match=True), index.RelatedFields( "characters", [ index.SearchField("name", boost=0.25), ], ), index.RelatedFields( "protagonist", [ index.SearchField("name", boost=0.5), index.FilterField("novel"), ], ), index.FilterField("protagonist"), ]
class RteiDocument(AbstractDocument, index.Indexed): '''A custom Document adding fields needed by RTEI Resource items.''' year = models.CharField(validators=[ RegexValidator(regex='^\d{4}$', message=_('Must be 4 numbers'), code='nomatch') ], help_text='e.g. 1999', max_length=4, blank=True) file = models.FileField( upload_to='documents', verbose_name=_('file'), blank=True, null=True, default='empty.txt', help_text="Use this to upload a file and list it as a resource") external_url = models.CharField( validators=[URLValidator(message=_('Must be a valid URL'))], blank=True, max_length=1000, verbose_name=_('External Link'), help_text="Use this to add an external website as a listed resource") country = models.CharField(max_length=256, blank=True) is_resource = models.BooleanField(default=True, help_text="Determines whether document " "appears on the Resources page.") description = RichTextField(blank=True) admin_form_fields = ('title', 'description', 'file', 'external_url', 'collection', 'country', 'year', 'is_resource', 'tags') search_fields = AbstractDocument.search_fields + [ index.SearchField('title'), index.SearchField('description'), index.SearchField('country'), index.SearchField('year'), index.RelatedFields('tags', [ index.SearchField('name'), ]) ] class Meta: get_latest_by = "created_at"
class ProductAbstract(models.Model, index.Indexed): model = models.TextField(verbose_name=_('model'), null=False, blank=False, default=None) brand = models.ForeignKey('Brand', null=True, blank=False, on_delete=models.SET_NULL, related_name='brand') image = models.ForeignKey(get_image_model_string(), null=True, blank=True, on_delete=models.SET_NULL, related_name='+', verbose_name=_('product image')) panels = [ MultiFieldPanel([ FieldPanel('model', classname='title'), ImageChooserPanel('image', classname='col6'), SnippetChooserPanel('brand', classname='col6'), ], heading=_('General Product Information'), classname='collapsible collapsed') ] api_fields = [ APIField('model'), APIField('image'), APIField('brand', serializer=BrandSerializer()), ] search_fields = [ index.SearchField('model', boost=10, partial_match=True), index.RelatedFields('brand', [index.SearchField('name', partial_match=True)]) ] def __str__(self) -> str: return f'{self.brand} - {self.model}' class Meta: abstract = True
class StudentGroup(index.Indexed, models.Model): name = models.CharField(max_length=255) created_at = models.DateTimeField(auto_now_add=True) is_prospective = models.BooleanField(default=False) description = models.TextField(default='', blank=True) logo = models.ForeignKey(MatteImage, null=True, blank=True, on_delete=models.SET_NULL) link = models.CharField(default='', max_length=255, blank=True) slug = models.CharField(default=None, max_length=255, blank=True, null=True, unique=True) search_fields = [ index.SearchField('name', partial_match=True, boost=10), index.SearchField('description'), index.FilterField('id'), index.FilterField('last_sync'), index.RelatedFields('msl_group', [ index.FilterField('last_sync'), ]) ] class Meta: ordering = ['name'] def __str__(self): return self.name @classmethod def get_by_msl_id(cls, msl_group_id): try: msl_group = MSLStudentGroup.objects.get(msl_group_id=msl_group_id) except MSLStudentGroup.DoesNotExist: return None if msl_group is not None: return msl_group.group return None