class HomePage(Page): subpage_types = ['content.ContentPage'] template = 'home.html' # Content fields subtitle = TextField(max_length=250, blank=True, default='') button_text = CharField(max_length=30, blank=True, default='') button_url = CharField(max_length=2048, blank=True, default='') image = ForeignKey( 'mozimages.MozImage', null=True, blank=True, on_delete=SET_NULL, related_name='+' ) featured = StreamField( StreamBlock([ ('article', PageChooserBlock(required=False, target_model=( 'articles.Article', 'externalcontent.ExternalArticle', ))), ('external_page', FeaturedExternalBlock()), ], min_num=0, max_num=4), null=True, blank=True, ) about_title = TextField(max_length=250, blank=True, default='') about_subtitle = TextField(max_length=250, blank=True, default='') about_button_text = CharField(max_length=30, blank=True, default='') about_button_url = URLField(max_length=140, blank=True, default='') # Card fields card_title = CharField('Title', max_length=140, blank=True, default='') card_description = TextField('Description', max_length=140, blank=True, default='') card_image = ForeignKey( 'mozimages.MozImage', null=True, blank=True, on_delete=SET_NULL, related_name='+', verbose_name='Image', ) # Meta fields keywords = ClusterTaggableManager(through=HomePageTag, blank=True) # Editor panel configuration content_panels = Page.content_panels + [ MultiFieldPanel( [ FieldPanel('subtitle'), FieldPanel('button_text'), FieldPanel('button_url'), ], heading="Header section", ), ImageChooserPanel('image'), StreamFieldPanel('featured'), MultiFieldPanel( [ FieldPanel('about_title'), FieldPanel('about_subtitle'), FieldPanel('about_button_text'), FieldPanel('about_button_url'), ], heading="About section", ) ] # Card panels card_panels = [ FieldPanel('card_title'), FieldPanel('card_description'), ImageChooserPanel('card_image'), ] # Meta panels meta_panels = [ MultiFieldPanel([ FieldPanel('seo_title'), FieldPanel('search_description'), FieldPanel('keywords'), ], heading='SEO'), ] # Settings panels settings_panels = [ FieldPanel('slug'), ] # Tabs edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(card_panels, heading='Card'), ObjectList(meta_panels, heading='Meta'), ObjectList(settings_panels, heading='Settings', classname='settings'), ]) @property def primary_topics(self): """The site’s top-level topics, i.e. topics without a parent topic.""" from ..topics.models import Topic return Topic.objects.filter(parent_topics__isnull=True).live().public().order_by('title')
class Event(Page): resource_type = 'event' parent_page_types = ['events.Events'] subpage_types = [] template = 'event.html' # Content fields description = TextField( blank=True, default='', help_text='Optional short text description, max. 400 characters', max_length=400, ) image = ForeignKey( 'mozimages.MozImage', null=True, blank=True, on_delete=SET_NULL, related_name='+', ) body = CustomStreamField( blank=True, null=True, help_text= ('Optional body content. Supports rich text, images, embed via URL, embed via HTML, and inline code snippets' )) agenda = StreamField( StreamBlock([ ('agenda_item', AgendaItemBlock()), ], required=False), blank=True, null=True, help_text='Optional list of agenda items for this event', ) speakers = StreamField( StreamBlock([ ('speaker', PageChooserBlock(target_model='people.Person')), ('external_speaker', ExternalSpeakerBlock()), ], required=False), blank=True, null=True, help_text='Optional list of speakers for this event', ) # Card fields card_title = CharField('Title', max_length=140, blank=True, default='') card_description = TextField('Description', max_length=400, blank=True, default='') card_image = ForeignKey( 'mozimages.MozImage', null=True, blank=True, on_delete=SET_NULL, related_name='+', verbose_name='Image', ) # Meta fields start_date = DateField(default=datetime.date.today) end_date = DateField(blank=True, null=True) latitude = FloatField(blank=True, null=True) longitude = FloatField(blank=True, null=True) register_url = URLField('Register URL', blank=True, null=True) venue_name = CharField(max_length=100, blank=True, default='') venue_url = URLField('Venue URL', max_length=100, blank=True, default='') address_line_1 = CharField(max_length=100, blank=True, default='') address_line_2 = CharField(max_length=100, blank=True, default='') address_line_3 = CharField(max_length=100, blank=True, default='') city = CharField(max_length=100, blank=True, default='') state = CharField('State/Province/Region', max_length=100, blank=True, default='') zip_code = CharField('Zip/Postal code', max_length=100, blank=True, default='') country = CountryField(blank=True, default='') keywords = ClusterTaggableManager(through=EventTag, blank=True) # Content panels content_panels = Page.content_panels + [ FieldPanel('description'), MultiFieldPanel( [ ImageChooserPanel('image'), ], heading='Image', help_text= ('Optional header image. If not specified a fallback will be used. This image is also shown when sharing ' 'this page via social media')), StreamFieldPanel('body'), StreamFieldPanel('agenda'), StreamFieldPanel('speakers'), ] # Card panels card_panels = [ FieldPanel('card_title'), FieldPanel('card_description'), ImageChooserPanel('card_image'), ] # Meta panels meta_panels = [ MultiFieldPanel( [ FieldPanel('start_date'), FieldPanel('end_date'), FieldPanel('latitude'), FieldPanel('longitude'), FieldPanel('register_url'), ], heading='Event details', classname='collapsible', help_text=mark_safe( 'Optional time and location information for this event. Latitude and longitude are used to show a map ' 'of the event’s location. For more information on finding these values for a given location, ' '<a href="https://support.google.com/maps/answer/18539">see this article</a>' )), MultiFieldPanel( [ FieldPanel('venue_name'), FieldPanel('venue_url'), FieldPanel('address_line_1'), FieldPanel('address_line_2'), FieldPanel('address_line_3'), FieldPanel('city'), FieldPanel('state'), FieldPanel('zip_code'), FieldPanel('country'), ], heading='Event address', classname='collapsible', help_text= 'Optional address fields. The city and country are also shown on event cards' ), MultiFieldPanel( [ InlinePanel('topics'), ], heading='Topics', help_text= ('These are the topic pages the event will appear on. The first topic in the list will be treated as the ' 'primary topic and will be shown in the page’s related content.' )), MultiFieldPanel( [ FieldPanel('seo_title'), FieldPanel('search_description'), FieldPanel('keywords'), ], heading='SEO', help_text= 'Optional fields to override the default title and description for SEO purposes' ), ] # Settings panels settings_panels = [ FieldPanel('slug'), ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(card_panels, heading='Card'), ObjectList(meta_panels, heading='Meta'), ObjectList(settings_panels, heading='Settings', classname='settings'), ]) @property def is_upcoming(self): """Returns whether an event is in the future.""" return self.start_date > datetime.date.today() @property def primary_topic(self): """Return the first (primary) topic specified for the event.""" article_topic = self.topics.first() return article_topic.topic if article_topic else None @property def month_group(self): return self.start_date.replace(day=1) @property def event_dates(self): """Return a formatted string of the event start and end dates""" event_dates = self.start_date.strftime("%b %-d") if self.end_date: event_dates += " – " start_month = self.start_date.strftime("%m") if self.end_date.strftime("%m") == start_month: event_dates += self.end_date.strftime("%-d") else: event_dates += self.end_date.strftime("%b %-d") return event_dates @property def event_dates_full(self): """Return a formatted string of the event start and end dates, including the year""" return self.event_dates + self.start_date.strftime(", %Y") def has_speaker(self, person): for speaker in self.speakers: # pylint: disable=not-an-iterable if (speaker.block_type == 'speaker' and str(speaker.value) == str(person.title)): return True return False
class FormSubmit(Model): user_agent = TextField("Client's user agent", null = True) ip_address = CharField("Client's IP address", max_length = 45, null = True) referer = URLField("HTTP referer", null = True) query_string = TextField("Query string") query = TextField("The 'q' parameter in the query")
class Person(ClusterableModel, index.Indexed): user = OneToOneField(User, null=True, blank=True, on_delete=CASCADE, related_name='profile') first_name = CharField(max_length=255) middle_name = CharField(max_length=255, null=True, blank=True) last_name = CharField(max_length=255) bio = RichTextField(blank=True) photo = ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=SET_NULL, related_name='+') position = CharField(max_length=140, blank=True) term = CharField(blank=True, max_length=9, help_text="Format:YYYY-YYYY") linked_in = URLField(blank=True) blog_url = URLField(blank=True) osf_profile = URLField(blank=True) google_plus = URLField(blank=True) github = URLField(blank=True) twitter = URLField(blank=True) phone_number = CharField(max_length=12, blank=True, help_text="Format:XXX-XXX-XXXX") email_address = EmailField(blank=True) favorite_food = CharField(max_length=140, blank=True) tags = TaggableManager(through='common.PersonTag', blank=True) search_fields = [ index.SearchField('first_name', partial_match=True), index.SearchField('last_name', partial_match=True), index.SearchField('middle_name', partial_match=True), ] panels = [ MultiFieldPanel([ FieldPanel('user'), FieldPanel('first_name'), FieldPanel('middle_name'), FieldPanel('last_name'), FieldPanel('bio'), FieldPanel('tags'), FieldPanel('position'), FieldPanel('term'), FieldPanel('linked_in'), FieldPanel('blog_url'), FieldPanel('osf_profile'), FieldPanel('google_plus'), FieldPanel('github'), FieldPanel('twitter'), FieldPanel('phone_number'), FieldPanel('email_address'), FieldPanel('favorite_food'), ], heading='Basic Information'), ImageChooserPanel('photo'), ] class Meta: verbose_name_plural = "People" ordering = ['last_name'] def __str__(self): return '{self.last_name}, {self.first_name}'.format(self=self)
class Source(AutoriteModel): parent = ForeignKey( 'self', related_name='children', verbose_name=_('parent'), null=True, blank=True, on_delete=CASCADE, help_text=_( 'À remplir par exemple si la source est une page d’un recueil ' 'déjà existant ou un tome d’une série.'), ) position = PositiveIntegerField( _('position'), null=True, blank=True, help_text=_('Position au sein de son parent.')) est_promu = BooleanField(_('est dans la bibliothèque'), default=False) type = ForeignKey('TypeDeSource', related_name='sources', help_text=ex(_('compte rendu')), verbose_name=_('type'), on_delete=PROTECT) titre = CharField(_('titre'), max_length=200, blank=True, db_index=True, help_text=ex(_('Journal de Rouen'))) legende = CharField(_('légende'), max_length=600, blank=True, help_text=_('Recommandée pour les images.')) ancrage = AncrageSpatioTemporel(has_heure=False, has_lieu=False) numero = NumberCharField( _('numéro'), max_length=50, blank=True, db_index=True, help_text=_('Sans « № ». Exemple : « 52 »'), ) folio = CharField(_('folio'), max_length=15, blank=True, help_text=_('Sans « f. ». Exemple : « 3 ».')) page = CharField(_('page'), max_length=15, blank=True, db_index=True, help_text=_('Sans « p. ». Exemple : « 3 »')) lieu_conservation = CharField(_('lieu de conservation'), max_length=75, blank=True, db_index=True) cote = CharField(_('cote'), max_length=60, blank=True, db_index=True) url = URLField(_('URL'), blank=True, help_text=_('Uniquement un permalien extérieur à Dezède.')) transcription = HTMLField( _('transcription'), blank=True, help_text=_('Recopier la source ou un extrait en suivant les règles ' 'définies dans ' # FIXME: Don’t hardcode the URL. '<a href="/examens/source">le didacticiel.</a>'), ) fichier = FileField(_('fichier'), upload_to='files/', blank=True) TYPES = ( (FileAnalyzer.OTHER, _('autre')), (FileAnalyzer.IMAGE, _('image')), (FileAnalyzer.AUDIO, _('audio')), (FileAnalyzer.VIDEO, _('vidéo')), ) type_fichier = PositiveSmallIntegerField( choices=TYPES, null=True, blank=True, editable=False, db_index=True, ) telechargement_autorise = BooleanField( _('téléchargement autorisé'), default=True, ) evenements = ManyToManyField('Evenement', through='SourceEvenement', related_name='sources', verbose_name=_('événements')) oeuvres = ManyToManyField('Oeuvre', through='SourceOeuvre', related_name='sources', verbose_name=_('œuvres')) individus = ManyToManyField('Individu', through='SourceIndividu', related_name='sources', verbose_name=_('individus')) ensembles = ManyToManyField('Ensemble', through='SourceEnsemble', related_name='sources', verbose_name=_('ensembles')) lieux = ManyToManyField('Lieu', through='SourceLieu', related_name='sources', verbose_name=_('lieux')) parties = ManyToManyField('Partie', through='SourcePartie', related_name='sources', verbose_name=_('sources')) # # Dossier # # Métadonnées editeurs_scientifiques = ManyToManyField( 'accounts.HierarchicUser', related_name='sources_editees', verbose_name=_('éditeurs scientifiques'), blank=True, ) date_publication = DateField(_('date de publication'), default=datetime.datetime.now) publications = TextField(_('publication(s) associée(s)'), blank=True) developpements = TextField(_('développements envisagés'), blank=True) # Article presentation = TextField(_('présentation'), blank=True) contexte = TextField(_('contexte historique'), blank=True) sources_et_protocole = TextField(_('sources et protocole'), blank=True) bibliographie = TextField(_('bibliographie indicative'), blank=True) objects = SourceManager() class Meta: verbose_name = _('source') verbose_name_plural = _('sources') ordering = ( 'date', 'titre', 'numero', 'parent__date', 'parent__titre', 'parent__numero', 'position', 'page', 'lieu_conservation', 'cote', ) permissions = (('can_change_status', _('Peut changer l’état')), ) def __str__(self): return strip_tags(self.html(False)) def has_presentation_tab(self): def iterator(): yield self.editeurs_scientifiques.exists() yield self.publications yield self.developpements yield self.presentation yield self.contexte yield self.sources_et_protocole yield self.bibliographie return any(iterator()) def has_index_tab(self): def iterator(): yield self.parent yield self.auteurs_html() yield self.nested_individus() yield self.nested_oeuvres() yield self.nested_parties() yield self.nested_evenements() yield self.nested_ensembles() yield self.notes_publiques return any(iterator()) @cached_property def specific(self): if self.type_fichier == FileAnalyzer.AUDIO: return Audio.objects.get(pk=self.pk) if self.type_fichier == FileAnalyzer.VIDEO: return Video.objects.get(pk=self.pk) return self @permalink def get_absolute_url(self): return 'source_permanent_detail', (self.pk, ) @permalink def get_change_url(self): meta = self.specific._meta return f'admin:{meta.app_label}_{meta.model_name}_change', (self.pk, ) def permalien(self): return self.get_absolute_url() def link(self): return self.html() link.short_description = _('Lien') link.allow_tags = True def auteurs_html(self, tags=True): return self.auteurs.html(tags) def no(self): return ugettext('n° %s') % self.numero def f(self): return ugettext('f. %s') % self.folio def p(self): return ugettext('p. %s') % self.page def html(self, tags=True, pretty_title=False, link=True): url = None if not tags else self.get_absolute_url() conservation = hlp(self.lieu_conservation, ugettext('Lieu de conservation'), tags) if self.ancrage.date or self.ancrage.date_approx: ancrage = hlp(self.ancrage.html(tags, caps=False), ugettext('date')) else: ancrage = None if self.cote: conservation += f", {hlp(self.cote, 'cote', tags)}" if self.titre: l = [cite(self.titre, tags)] if self.numero: l.append(self.no()) if ancrage is not None: l.append(ancrage) if self.lieu_conservation: l[-1] += f' ({conservation})' else: l = [conservation] if ancrage is not None: l.append(ancrage) if self.folio: l.append(hlp(self.f(), ugettext('folio'), tags)) if self.page: l.append(hlp(self.p(), ugettext('page'), tags)) if self.parent is not None: l.insert( 0, self.parent.html(tags=tags, pretty_title=pretty_title, link=pretty_title)) l = (l[0], small(str_list(l[1:]), tags=tags)) if pretty_title else l out = str_list(l) if link: return mark_safe(href(url, out, tags)) return out html.short_description = _('rendu HTML') html.allow_tags = True def pretty_title(self): return self.html(pretty_title=True, link=False) def has_events(self): if hasattr(self, '_has_events'): return self._has_events return self.evenements.exists() has_events.short_description = _('événements') has_events.boolean = True has_events.admin_order_field = 'evenements' def has_program(self): if hasattr(self, '_has_program'): return self._has_program return self.evenements.with_program().exists() has_program.short_description = _('programme') has_program.boolean = True def is_other(self): return self.type_fichier == FileAnalyzer.OTHER def is_pdf(self): return self.is_other() and self.fichier.name.endswith('.pdf') def is_image(self): return self.type_fichier == FileAnalyzer.IMAGE def is_audio(self): return self.type_fichier == FileAnalyzer.AUDIO def is_video(self): return self.type_fichier == FileAnalyzer.VIDEO def has_children_images(self): return self.children.filter(type_fichier=FileAnalyzer.IMAGE).exists() def has_images(self): return (self.type_fichier == FileAnalyzer.IMAGE or self.has_children_images()) def has_fichiers(self): return (self.is_other() or self.is_audio() or self.is_video() or self.has_images()) def images_iterator(self): if self.is_image(): yield self for child in Source.objects.filter( Q(parent=self) | Q(parent__parent=self), type_fichier=FileAnalyzer.IMAGE, ).order_by('position', 'page'): yield child @cached_property def images(self): return list(self.images_iterator()) @cached_property def preview_image(self): return next(self.images_iterator()) @cached_property def is_collection(self): return Source.objects.filter(parent__parent=self).exists() def is_empty(self): return not (self.transcription or self.url or self.has_fichiers()) DATA_TYPES = ('video', 'audio', 'image', 'other', 'text', 'link') VIDEO, AUDIO, IMAGE, OTHER, TEXT, LINK = DATA_TYPES @property def data_types(self): data_types = [] if self.is_video(): data_types.append(self.VIDEO) if self.is_audio(): data_types.append(self.AUDIO) if self.has_images(): data_types.append(self.IMAGE) if self.is_other(): data_types.append(self.OTHER) if self.transcription: data_types.append(self.TEXT) if self.url: data_types.append(self.LINK) return data_types ICONS = { VIDEO: '<i class="fa fa-fw fa-video-camera"></i>', AUDIO: '<i class="fa fa-fw fa-volume-up"></i>', IMAGE: '<i class="fa fa-fw fa-photo"></i>', OTHER: '<i class="fa fa-fw fa-paperclip"></i>', TEXT: '<i class="fa fa-fw fa-file-text-o"></i>', LINK: '<i class="fa fa-fw fa-external-link"></i>', } DATA_TYPES_WITH_ICONS = ( (VIDEO, _(f'{ICONS[VIDEO]} Vidéo')), (AUDIO, _(f'{ICONS[AUDIO]} Audio')), (IMAGE, _(f'{ICONS[IMAGE]} Image')), (OTHER, _(f'{ICONS[OTHER]} Autre')), (TEXT, _(f'{ICONS[TEXT]} Texte')), (LINK, _(f'{ICONS[LINK]} Lien')), ) @property def icons(self): return ''.join( [self.ICONS[data_type] for data_type in self.data_types]) def update_media_info(self): if self.fichier: file_analyzer = FileAnalyzer(self, 'fichier') self.type_fichier = file_analyzer.type else: self.type_fichier = None def clean(self): super().clean() if not getattr(self, 'updated_media_info', False): self.update_media_info() self.updated_media_info = True @cached_property def first_page(self): return self.children.order_by('position').first() @cached_property def prev_page(self): if self.parent is not None: return self.parent.children.exclude(pk=self.pk).filter( position__lte=self.position, ).order_by('-position').first() @cached_property def next_page(self): if self.parent is not None: return self.parent.children.exclude(pk=self.pk).filter( position__gte=self.position, ).order_by('position').first() @property def filename(self): return Path(self.fichier.path).name @cached_property def linked_individus(self): return self.individus.distinct() @cached_property def linked_evenements(self): return self.evenements.distinct() @cached_property def linked_oeuvres(self): return self.oeuvres.distinct() @cached_property def linked_ensembles(self): return self.ensembles.distinct() @cached_property def linked_lieux(self): return self.lieux.distinct() @cached_property def linked_parties(self): return self.parties.distinct() def get_linked_objects(self): return [ *self.auteurs.all(), *self.linked_individus, *self.linked_evenements, *self.linked_oeuvres, *self.linked_ensembles, *self.linked_lieux, *self.linked_parties, ] def get_linked_objects_json(self): return json.dumps([{ 'url': obj.get_absolute_url(), 'label': str(obj), 'model': obj.class_name().lower(), } for obj in self.get_linked_objects()]) def nested_evenements(self): return apps.get_model('libretto.Evenement').objects.filter( sources__in=self.children.all() | Source.objects.filter(pk=self.pk)).distinct() def nested_oeuvres(self): return apps.get_model('libretto.Oeuvre').objects.filter( sources__in=self.children.all() | Source.objects.filter(pk=self.pk)).distinct() def nested_individus(self): return apps.get_model('libretto.Individu').objects.filter( sources__in=self.children.all() | Source.objects.filter(pk=self.pk)).distinct() def nested_ensembles(self): return apps.get_model('libretto.Ensemble').objects.filter( sources__in=self.children.all() | Source.objects.filter(pk=self.pk)).distinct() def nested_lieux(self): return apps.get_model('libretto.Lieu').objects.filter( sources__in=self.children.all() | Source.objects.filter(pk=self.pk)).distinct() def nested_parties(self): return apps.get_model('libretto.Partie').objects.filter( sources__in=self.children.all() | Source.objects.filter(pk=self.pk)).distinct() @property def small_thumbnail(self): if self.is_image(): thumbnailer = get_thumbnailer(self.fichier) return thumbnailer.get_thumbnail(aliases.get('small')).url @property def medium_thumbnail(self): if self.is_image(): thumbnailer = get_thumbnailer(self.fichier) return thumbnailer.get_thumbnail(aliases.get('medium')).url @staticmethod def autocomplete_search_fields(): return ( 'type__nom__unaccent__icontains', 'titre__unaccent__icontains', 'date__icontains', 'date_approx__unaccent__icontains', 'numero__unaccent__icontains', 'lieu_conservation__unaccent__icontains', 'cote__unaccent__icontains', )
def details_url_annotate(queryset, app_path=None, model_path=None, param_name=None, param_lookup_name=None): """ annotate each row in a `queryset` with an admin link to related records For example, we have a hosts and host events and host events linked via a :class:`Django Foreign Key <django.db.models.ForeignKey>` field. This function will annotate each row in the hosts `queryset` with the absolute `Django admin URL` to the related host events like below:: http://10.2.50.35:8080/admin/citrus_borg/winlogevent/?source_host__host_name=bccss-t450s-02 :arg queryset: the initial :class:`Django queryset <django.db.models.query.QuerySet>` :arg str app_path: the `app_label` for the model with the details. If ``None``, the `app_label` is picked from the `queryset` using the `Model _meta API <https://docs.djangoproject.com/en/2.2/ref/models/meta/#module-django.db.models.options>`_. This is only useful if the master and the details models are defined in the same `Django application`. :arg str model_path: the `model_name` property of the `Django model` with the details. If ``None``, it will be picked from the `queryset` using the `Model _meta API`. This, however, is o very little use, since there are very few realistic data models where the master and the details are in the same `Djanog model`. :arg str param_name: `Django lookup` key_name__field_name used to build the `param` part of the `URL`. If one considers the example above, this argument is 'source_host__host_name' which means that the events (the details) model has a foreign key named 'source_host' pointing to the hosts (master) model and the lookup will be applied against a field named 'host_name' in the later model. :arg str param_lookup_name: the name of the field that contains the `value` part of the `URL`. If one considers the example above, the value used in the filter is picked from the field containing the host_name. """ if not isinstance(queryset, QuerySet): raise TypeError('bad type %s for object %s' % (type(queryset), queryset)) if param_name is None: raise ValueError( 'cannot build URL parameters without a parameter name') if param_lookup_name is None: raise ValueError( 'cannot build URL parameters without a parameter value') obj_sample = queryset.model._meta if app_path is None: app_path = obj_sample.app_label if model_path is None: model_path = obj_sample.model_name try: return queryset.annotate( details_url=Concat(Value(settings.SERVER_PROTO), Value('://'), Value(socket.getfqdn()), Value(':'), Value(settings.SERVER_PORT), Value('/admin/'), Value(app_path), Value('/'), Value(model_path), Value('/?'), Value(param_name), Value('='), F(param_lookup_name), output_field=URLField())) except Exception as error: raise error
class Organization(BaseModel): """ Fields: name -- Unique organization name url -- Internet site URL email -- list of emails phone -- list of phones """ class Meta(BaseModel.Meta): ordering = ('name', ) unique_together = tuple( ('name_%s' % lang[0], 'monitoring') for lang in settings.LANGUAGES) verbose_name = pgettext_lazy(u'change organization in admin', u'Organization') verbose_name_plural = _('Organizations') name = CharField(max_length=255, verbose_name=_('name')) url = URLField(max_length=255, null=True, blank=True, verbose_name=_('Website')) email = EmailsField(null=True, blank=True, verbose_name=_('email')) phone = PhonesField(null=True, blank=True, verbose_name=_('phone')) monitoring = ForeignKey("Monitoring", verbose_name=_('monitoring'), editable=False) inv_code = CharField(verbose_name=_("Invitation code"), blank=True, max_length=6, unique=True, editable=False) inv_status = CharField(max_length=3, choices=INV_STATUS, default='NTS', verbose_name=_('Invitation status'), editable=False) recommendations_hidden = BooleanField( verbose_name=_("Recommendations hidden"), default=False) def __unicode__(self): return self.name def save(self, *args, **kwargs): if not self.pk and not self.inv_code: self.inv_code = generate_inv_code(6) super(Organization, self).save(*args, **kwargs) def validate_unique(self, exclude=None): """ Prevent "monitoring" field from being excluded in validation checks. This is workaround for Django bug 13091 https://code.djangoproject.com/ticket/13091 This workaround will force modelform to validate unique_together constraints involving "monitoring" field on the model, even if "monitoring" field is absent in the form. - Failing to do that will raise IntegrityError on instance saving. """ if 'monitoring' in exclude: exclude.remove('monitoring') super(Organization, self).validate_unique(exclude) def clean(self): """ Replace empty strings with None for all modeltranslation fields to store NULL in database. This will allow multiple orgs with empty modeltranslation fields to pass unique checks during form validation. """ from exmo2010.translation import OrganizationTranslationOptions for field in OrganizationTranslationOptions.fields: for lang in settings.LANGUAGES: if not getattr(self, '{}_{}'.format(field, lang[0])): setattr(self, '{}_{}'.format(field, lang[0]), None) def email_iter(self): if not self.email: return for email in self.email.replace(' ', '').split(','): if email: yield email
class Study(Model): EEA = 'eea' OTHER = 'other' REQUESTED_BY_CHOICES = ( (EEA, 'EEA'), (OTHER, 'Other'), ) YES = 1 NO = 0 YES_NO_CHOICES = ( ('', '----'), (YES, 'Yes'), (NO, 'No'), ) POLICY = 'policy' NON_POLICY = 'non_policy' PURPOSE_CHOICES = ( (POLICY, 'Support to policy'), (NON_POLICY, 'Non-policy (research, civil initiative, NGOs...'), ) ACTIVITY = 'activity' EVALUATION = 'evaluation' TYPE_CHOICES = ( (ACTIVITY, 'Forward looking activity'), (EVALUATION, 'Evaluation'), ) BLOSSOM_CHOICES = ( (YES, 'BLOSSOM study'), (NO, 'other study'), ) draft = BooleanField(default=True) created_on = DateTimeField(auto_now_add=True) last_updated = DateTimeField(auto_now_add=True, auto_now=True) user_id = CharField(max_length=64, blank=True) title = CharField('title in English', max_length=255) languages = ManyToManyField('Language', verbose_name='language of the study', through='StudyLanguage') url = URLField(blank=True) study_type = CharField( 'I want to add a new', choices=TYPE_CHOICES, max_length=128, null=True, ) blossom = IntegerField( 'Approach to evaluation', choices=BLOSSOM_CHOICES, default=NO, ) requested_by = CharField('who requested the study?', max_length=64, choices=REQUESTED_BY_CHOICES, blank=True) start_date = DateField('start date', null=True, blank=True) end_date = DateField('end date') lead_author = TextField('lead author') other = TextField('other organisations/authors or contact persons', blank=True) purpose_and_target = CharField( 'purpose and target audience', max_length=128, choices=PURPOSE_CHOICES, blank=True, ) additional_information = TextField('additional information', blank=True) phase_of_policy = ForeignKey('PhasesOfPolicy', verbose_name='phases of policy cycle', null=True, blank=True) additional_information_phase = TextField( ('additional information about the application'), blank=True) foresight_approaches = ManyToManyField( 'ForesightApproaches', verbose_name='foresight approaches used') additional_information_foresight = TextField('additional information', blank=True) stakeholder_participation = BooleanField('stakeholder participation', default=False) additional_information_stakeholder = TextField( 'additional information about stakeholder involvement', blank=True) environmental_themes = ManyToManyField('common.EnvironmentalTheme', verbose_name='topics', blank=True) geographical_scope = ForeignKey('common.GeographicalScope', verbose_name='geographical scope', null=True, blank=True) countries = ManyToManyField('common.Country', verbose_name='countries', blank=True) def __unicode__(self): return self.title
class AppRelease(TranslatableModel): version = CharField(max_length=256, verbose_name=_('Version'), help_text=_('Version follows Semantic Versioning')) app = ForeignKey('App', on_delete=CASCADE, verbose_name=_('App'), related_name='releases') # dependencies php_extensions = ManyToManyField( 'PhpExtension', blank=True, through='PhpExtensionDependency', verbose_name=_('PHP extension dependency')) databases = ManyToManyField('Database', blank=True, through='DatabaseDependency', verbose_name=_('Database dependency')) licenses = ManyToManyField('License', verbose_name=_('License')) shell_commands = ManyToManyField( 'ShellCommand', blank=True, verbose_name=_('Shell command dependency')) php_version_spec = CharField(max_length=256, verbose_name=_('PHP version requirement')) platform_version_spec = CharField( max_length=256, verbose_name=_('Platform version requirement')) raw_php_version_spec = CharField( max_length=256, verbose_name=_('PHP version requirement (raw)')) raw_platform_version_spec = CharField( max_length=256, verbose_name=_('Platform version requirement (raw)')) min_int_size = IntegerField(blank=True, default=32, verbose_name=_('Minimum Integer bits'), help_text=_('e.g. 32 for 32bit Integers')) download = URLField(max_length=256, blank=True, verbose_name=_('Archive download URL')) created = DateTimeField(auto_now_add=True, editable=False, verbose_name=_('Created at')) last_modified = DateTimeField(auto_now=True, editable=False, db_index=True, verbose_name=_('Updated at')) signature = TextField( verbose_name=_('Signature'), help_text=_('A signature using the app\'s certificate')) signature_digest = CharField(max_length=256, verbose_name=_('Signature hashing algorithm')) translations = TranslatedFields(changelog=TextField( verbose_name=_('Changelog'), help_text=_('The release changelog. Can contain Markdown'), default='')) is_nightly = BooleanField(verbose_name=_('Nightly'), default=False) class Meta: verbose_name = _('App release') verbose_name_plural = _('App releases') unique_together = (('app', 'version', 'is_nightly'), ) ordering = ['-version'] def can_update(self, user: User) -> bool: return self.app.owner == user or user in self.app.co_maintainers.all() def can_delete(self, user: User) -> bool: return self.can_update(user) def __str__(self) -> str: return '%s %s' % (self.app, self.version) def is_compatible(self, platform_version, inclusive=False): """Checks if a release is compatible with a platform version :param platform_version: the platform version, not required to be semver compatible :param inclusive: if True the check will also return True if an app requires 9.0.1 and the given platform version is 9.0 :return: True if compatible, otherwise false """ min_version = Version(pad_min_version(platform_version)) spec = Spec(self.platform_version_spec) if inclusive: max_version = Version(pad_max_inc_version(platform_version)) return (min_version in spec or max_version in spec) else: return min_version in spec @property def is_unstable(self): return self.is_nightly or '-' in self.version
class Test(Model): id = UUIDField( primary_key=True, default=uuid4, editable=False, ) label = CharField( verbose_name=_("label"), max_length=32, blank=False, db_index=True, unique=True, ) category = ForeignKey( verbose_name=_("category"), related_name="test_set", to=Category, null=True, blank=True, db_index=True, on_delete=PROTECT, ) theme_set = ManyToManyField( verbose_name=_("theme_set"), related_name="test_set", to=Theme, blank=True, ) category2 = ForeignKey( verbose_name=_("category 2"), related_name="test2_set", to=Category, null=True, blank=True, db_index=True, on_delete=CASCADE, ) theme_set2 = ManyToManyField( verbose_name=_("theme_set 2"), related_name="test2_set", to=Theme, blank=True, ) category3 = ForeignKey( verbose_name=_("category 3"), related_name="test3_set", to=Category, null=True, blank=True, db_index=True, on_delete=CASCADE, ) theme_set3 = ManyToManyField( verbose_name=_("theme_set 3"), related_name="test3_set", to=Theme, blank=True, ) category4 = ForeignKey( verbose_name=_("category 4"), related_name="test4_set", to=Category, null=True, blank=True, db_index=True, on_delete=CASCADE, ) theme_set4 = ManyToManyField( verbose_name=_("theme_set 4"), related_name="test4_set", to=Theme, blank=True, ) category5 = ForeignKey( verbose_name=_("category 5"), related_name="test5_set", to=Category, null=True, blank=True, db_index=True, on_delete=CASCADE, ) theme_set5 = ManyToManyField( verbose_name=_("theme_set 5"), related_name="test5_set", to=Theme, blank=True, ) category6 = ForeignKey( verbose_name=_("category 6"), related_name="test6_set", to=Category, null=True, blank=True, db_index=True, on_delete=CASCADE, ) theme_set6 = ManyToManyField( verbose_name=_("theme_set 6"), related_name="test6_set", to=Theme, blank=True, ) tag_set = ManyToManyField( verbose_name=_("theme_set"), related_name="test_set", to=Tag, through="Mapping", blank=True, ) number = PositiveSmallIntegerField( verbose_name=_("number"), unique=True, ) percent = DecimalField( verbose_name=_("percent"), max_digits=5, decimal_places=2, validators=[MinValueValidator(0), MaxValueValidator(100)], blank=True, null=True, ) progress = FloatField( verbose_name=_("progress"), validators=[MinValueValidator(0), MaxValueValidator(100)], blank=True, null=True, ) grade = IntegerField( verbose_name=_("grade"), validators=[MinValueValidator(-10), MaxValueValidator(10)], blank=True, null=True, ) slug = SlugField( unique=True, max_length=32, editable=True, db_index=True, ) owner = EmailField( verbose_name=_("owner"), blank=True, null=True, ) url = URLField( verbose_name=_("url"), blank=True, null=True, ) key = UUIDField(default=uuid4, ) description = TextField(verbose_name=_("description"), ) active = BooleanField(verbose_name=_("active"), ) highlight = NullBooleanField(verbose_name=_("highlight"), ) creation_date = DateField( verbose_name=_("creation date"), auto_now_add=True, ) last_modification_date = DateField( verbose_name=_("last modification date"), auto_now=True, ) random_date = DateField( verbose_name=_("random date"), blank=True, null=True, ) creation_datetime = DateTimeField( verbose_name=_("creation datetime"), auto_now_add=True, ) last_modification_datetime = DateTimeField( verbose_name=_("last modification datetime"), auto_now=True, ) random_datetime = DateTimeField( verbose_name=_("random datetime"), blank=True, null=True, ) duration = DurationField( verbose_name=_("duration"), blank=True, null=True, ) creation_time = TimeField( verbose_name=_("creation time"), auto_now_add=True, ) last_modification_time = TimeField( verbose_name=_("last modification time"), auto_now=True, ) random_time = TimeField( verbose_name=_("random time"), blank=True, null=True, ) ip = GenericIPAddressField( verbose_name=_("IP v4 ou 6"), protocol="both", blank=True, null=True, ) ipv4 = GenericIPAddressField( verbose_name=_("IP v4 as is"), protocol="IPv4", blank=True, null=True, ) ipv6_forced = GenericIPAddressField( verbose_name=_("IP v6 (ipv4 will be converted)"), protocol="both", unpack_ipv4=True, blank=True, null=True, ) ipv6 = GenericIPAddressField( verbose_name=_("IP v6"), protocol="IPv6", blank=True, null=True, ) raw_data = BinaryField( verbose_name=_("raw data"), max_length=127, editable=True, blank=True, null=True, ) def compute_upload_path(current_object, sub_path, filename): """Describe the image storage path""" today = now() return str( Path.joinpath(*list( map( Path, ( current_object._meta.app_label, # pylint: disable=protected-access current_object._meta.model_name, # pylint: disable=protected-access sub_path, str(today.year), str(today.month), str(uuid4()) + Path(filename).suffix))))) file = FileField( verbose_name=_("file"), max_length=256, upload_to=partial(compute_upload_path, subpath="file"), null=True, blank=True, ) image = ImageField( verbose_name=_("image"), max_length=256, upload_to=partial(compute_upload_path, subpath="image"), null=True, blank=True, ) path = FilePathField( verbose_name=_("path"), path=settings.STATIC_PATH, ) def __str__(self): """Return a string that represent the current object to an end user.""" return self.label class Meta: # pylint: disable=too-few-public-methods """Test Meta class""" verbose_name = _("test") verbose_name_plural = _("tests") ordering = ("number", )
class Game(Model): """game model""" bgg_id = PositiveIntegerField(primary_key=True) name = CharField(max_length=255, db_index=True) alt_name = JSONField(default=list) year = SmallIntegerField(blank=True, null=True, db_index=True) description = TextField(blank=True, null=True) designer = ManyToManyField("Person", blank=True, related_name="designer_of") artist = ManyToManyField("Person", blank=True, related_name="artist_of") # publisher = ListField(CharField(), blank=True) url = URLField(blank=True, null=True) image_url = JSONField(default=list) video_url = JSONField(default=list) external_link = JSONField(default=list) # list_price = CharField(max_length=100, blank=True, null=True) min_players = PositiveSmallIntegerField(blank=True, null=True, db_index=True) max_players = PositiveSmallIntegerField(blank=True, null=True, db_index=True) min_players_rec = PositiveSmallIntegerField(blank=True, null=True, db_index=True) max_players_rec = PositiveSmallIntegerField(blank=True, null=True, db_index=True) min_players_best = PositiveSmallIntegerField(blank=True, null=True, db_index=True) max_players_best = PositiveSmallIntegerField(blank=True, null=True, db_index=True) min_age = PositiveSmallIntegerField(blank=True, null=True, db_index=True) max_age = PositiveSmallIntegerField(blank=True, null=True, db_index=True) min_age_rec = FloatField(blank=True, null=True, db_index=True) max_age_rec = FloatField(blank=True, null=True, db_index=True) min_time = PositiveSmallIntegerField(blank=True, null=True, db_index=True) max_time = PositiveSmallIntegerField(blank=True, null=True, db_index=True) game_type = ManyToManyField("GameType", blank=True, related_name="games") category = ManyToManyField("Category", blank=True, related_name="games") mechanic = ManyToManyField("Mechanic", blank=True, related_name="games") cooperative = BooleanField(default=False, db_index=True) compilation = BooleanField(default=False, db_index=True) compilation_of = ManyToManyField("self", symmetrical=False, blank=True, related_name="contained_in") # family = ListField(CharField(), blank=True) # expansion = ListField(CharField(), blank=True) implements = ManyToManyField("self", symmetrical=False, blank=True, related_name="implemented_by") integrates_with = ManyToManyField("self", symmetrical=True, blank=True) bgg_rank = PositiveIntegerField(blank=True, null=True, db_index=True) num_votes = PositiveIntegerField(default=0, db_index=True) avg_rating = FloatField(blank=True, null=True, db_index=True) stddev_rating = FloatField(blank=True, null=True, db_index=True) bayes_rating = FloatField(blank=True, null=True, db_index=True) rec_rank = PositiveIntegerField(blank=True, null=True, db_index=True) rec_rating = FloatField(blank=True, null=True, db_index=True) rec_stars = FloatField(blank=True, null=True, db_index=True) complexity = FloatField(blank=True, null=True, db_index=True) language_dependency = FloatField(blank=True, null=True, db_index=True) kennerspiel_score = FloatField(blank=True, null=True, db_index=True) freebase_id = JSONField(default=list) wikidata_id = JSONField(default=list) wikipedia_id = JSONField(default=list) dbpedia_id = JSONField(default=list) luding_id = JSONField(default=list) spielen_id = JSONField(default=list) bga_id = JSONField(default=list) def highest_ranking(self, ranking_type=Ranking.BGG): """Find the highest ever rank of the given type.""" return ( # pylint: disable=no-member self.ranking_set.filter(ranking_type=ranking_type ).order_by("rank", "-date").first()) @property def highest_ranking_bgg(self): """Highest BGG ranking.""" return self.highest_ranking(ranking_type=Ranking.BGG) @property def highest_ranking_factor(self): """Highest factor model ranking.""" return self.highest_ranking(ranking_type=Ranking.FACTOR) @property def highest_ranking_similarity(self): """Highest similarity model ranking.""" return self.highest_ranking(ranking_type=Ranking.SIMILARITY) class Meta: """meta""" ordering = ("-rec_rating", "-bayes_rating", "-avg_rating") indexes = (Index(fields=("-rec_rating", "-bayes_rating", "-avg_rating")), ) def __str__(self): return str(self.name)
class VideoRepresentation(Representation): """ Video Representation entity which saves URL to video """ video_url = URLField(null=True, max_length=1024) class Meta: db_table = "green_planet_video_representation"
class Event(BasePage): resource_type = "event" parent_page_types = ["events.Events"] subpage_types = [] template = "event.html" # Content fields description = RichTextField( blank=True, default="", features=RICH_TEXT_FEATURES_SIMPLE, help_text="Optional short text description, max. 400 characters", max_length=400, ) image = ForeignKey( "mozimages.MozImage", null=True, blank=True, on_delete=SET_NULL, related_name="+", ) start_date = DateField(default=datetime.date.today) end_date = DateField(blank=True, null=True) latitude = FloatField(blank=True, null=True) longitude = FloatField(blank=True, null=True) register_url = URLField("Register URL", blank=True, null=True) body = CustomStreamField( blank=True, null=True, help_text=( "Optional body content. Supports rich text, images, embed via URL, " "embed via HTML, and inline code snippets"), ) venue_name = CharField(max_length=100, blank=True, default="") venue_url = URLField("Venue URL", max_length=100, blank=True, default="") address_line_1 = CharField(max_length=100, blank=True, default="") address_line_2 = CharField(max_length=100, blank=True, default="") address_line_3 = CharField(max_length=100, blank=True, default="") city = CharField(max_length=100, blank=True, default="") state = CharField("State/Province/Region", max_length=100, blank=True, default="") zip_code = CharField("Zip/Postal code", max_length=100, blank=True, default="") country = CountryField(blank=True, default="") agenda = StreamField( StreamBlock([("agenda_item", AgendaItemBlock())], required=False), blank=True, null=True, help_text="Optional list of agenda items for this event", ) speakers = StreamField( StreamBlock( [ ("speaker", PageChooserBlock(target_model="people.Person")), ("external_speaker", ExternalSpeakerBlock()), ], required=False, ), blank=True, null=True, help_text="Optional list of speakers for this event", ) # Card fields card_title = CharField("Title", max_length=140, blank=True, default="") card_description = TextField("Description", max_length=400, blank=True, default="") card_image = ForeignKey( "mozimages.MozImage", null=True, blank=True, on_delete=SET_NULL, related_name="+", verbose_name="Image", ) # Meta fields keywords = ClusterTaggableManager(through=EventTag, blank=True) # Content panels content_panels = BasePage.content_panels + [ FieldPanel("description"), MultiFieldPanel( [ImageChooserPanel("image")], heading="Image", help_text= ("Optional header image. If not specified a fallback will be used. " "This image is also shown when sharing this page via social media" ), ), MultiFieldPanel( [ FieldPanel("start_date"), FieldPanel("end_date"), FieldPanel("latitude"), FieldPanel("longitude"), FieldPanel("register_url"), ], heading="Event details", classname="collapsible", help_text=mark_safe( "Optional time and location information for this event. Latitude and " "longitude are used to show a map of the event’s location. For more " "information on finding these values for a given location, " "'<a href='https://support.google.com/maps/answer/18539'>" "see this article</a>"), ), StreamFieldPanel("body"), MultiFieldPanel( [ FieldPanel("venue_name"), FieldPanel("venue_url"), FieldPanel("address_line_1"), FieldPanel("address_line_2"), FieldPanel("address_line_3"), FieldPanel("city"), FieldPanel("state"), FieldPanel("zip_code"), FieldPanel("country"), ], heading="Event address", classname="collapsible", help_text=( "Optional address fields. The city and country are also shown " "on event cards"), ), StreamFieldPanel("agenda"), StreamFieldPanel("speakers"), ] # Card panels card_panels = [ FieldPanel("card_title"), FieldPanel("card_description"), ImageChooserPanel("card_image"), ] # Meta panels meta_panels = [ MultiFieldPanel( [InlinePanel("topics")], heading="Topics", help_text= ("These are the topic pages the event will appear on. The first topic " "in the list will be treated as the primary topic and will be shown " "in the page’s related content."), ), MultiFieldPanel( [ FieldPanel("seo_title"), FieldPanel("search_description"), ImageChooserPanel("social_image"), FieldPanel("keywords"), ], heading="SEO", help_text=( "Optional fields to override the default title and description " "for SEO purposes"), ), ] # Settings panels settings_panels = BasePage.settings_panels + [FieldPanel("slug")] edit_handler = TabbedInterface([ ObjectList(content_panels, heading="Content"), ObjectList(card_panels, heading="Card"), ObjectList(meta_panels, heading="Meta"), ObjectList(settings_panels, heading="Settings", classname="settings"), ]) @property def is_upcoming(self): """Returns whether an event is in the future.""" return self.start_date >= get_past_event_cutoff() @property def primary_topic(self): """Return the first (primary) topic specified for the event.""" article_topic = self.topics.first() return article_topic.topic if article_topic else None @property def month_group(self): return self.start_date.replace(day=1) @property def country_group(self): return ({ "slug": self.country.code.lower(), "title": self.country.name } if self.country else { "slug": "" }) @property def event_dates(self): """Return a formatted string of the event start and end dates""" event_dates = self.start_date.strftime("%b %-d") if self.end_date and self.end_date != self.start_date: event_dates += " – " start_month = self.start_date.strftime("%m") if self.end_date.strftime("%m") == start_month: event_dates += self.end_date.strftime("%-d") else: event_dates += self.end_date.strftime("%b %-d") return event_dates @property def event_dates_full(self): """Return a formatted string of the event start and end dates, including the year""" return self.event_dates + self.start_date.strftime(", %Y") def has_speaker(self, person): for speaker in self.speakers: # pylint: disable=not-an-iterable if speaker.block_type == "speaker" and str(speaker.value) == str( person.title): return True return False
class Ad(Model): APPROVAL_CHOICES = ( ('accepted', 'قبول'), ('denied', 'رد'), ) advertiser = ForeignKey(to=Advertiser, related_name='ads', verbose_name='تبلیغ کننده', on_delete=CASCADE) approve = CharField(max_length=10, choices=APPROVAL_CHOICES, verbose_name='وضعیت', default='denied') title = CharField(max_length=100, verbose_name='موضوع') img_url = URLField(verbose_name=' ادرس عکس تبلیغ', ) link = URLField(verbose_name='ادرس سایت شما') class Meta: verbose_name = 'تبلیغ' verbose_name_plural = 'تبلیغات' def __str__(self): return str(self.advertiser) + ' : ' + str(self.title) @staticmethod def get_total_ctr(start_time, end_time): return Ad.objects.annotate( total_views=Count(F('views'), distinct=True, filter=Q(views__time__range=(start_time, end_time))) ).filter(total_views__gt=0).annotate( ctr=Cast( Count(F('clicks'), distinct=True, filter=Q(clicks__time__range=( start_time, end_time))), FloatField()) / Cast( Count(F('views'), distinct=True, filter=Q(views__time__range=(start_time, end_time)), output_field=FloatField()), FloatField())).order_by( '-ctr') @staticmethod def get_total_clicks_views(start_time, end_time, delta): ads = Ad.objects.all() response = dict() for ad in ads: ad_response = list() start = start_time while start < end_time: end = start + timezone.timedelta(hours=delta) d = ad.get_dict_in_time_range(start_time=start, end_time=end) ad_response.append(d) start = end response.update({ad: ad_response}) return response def get_dict_in_time_range(self, start_time, end_time): clicks_count = self.clicks.filter(time__range=(start_time, end_time)).count() views_count = self.views.filter(time__range=(start_time, end_time)).count() d = dict() d.update({ 'start_time': start_time, 'end_time': end_time, 'total_clicks': clicks_count, 'total_view': views_count, }) return d def get_closest_view(self, ip, time): return self.views.filter(ip=ip, time__lt=time).order_by('-time')[0]
class Announcement(SearchableModel): title = CharField(max_length=255, db_index=True, help_text=_(u'Max length \ 255 characters, required field.')) slug = SlugField(max_length=255, db_index=True, help_text=_(u'The \ part of the URL specific to this announcement. This field is required; \ it autocompletes from the value you enter in the title field, but you \ can edit it to suit your need. Allowd characters: 0-9a-z-_ If the \ field is left empty by the time you save the announcement, the slug \ will be automatically generated.')) subtitle = CharField(max_length=255, blank=True, help_text=_(u'Optional \ field, max lenght 255 characters.')) text = TextField(help_text=_(u'This field is required.')) image = ImageField(max_length=200, upload_to='announcements', blank=True, verbose_name=_(u'Main image'), help_text=_(u'Optional \ field. allowed mime types: png, jpg, jpeg, gif.')) img_url = URLField( max_length=255, blank=True, verbose_name=_(u'Image URL'), help_text=_( u'Optionally, you can provide a URL for the image you want \ to associate with the announcement. You need to supply the URL of the \ image (something like http://example.com/image.jpg). It will be \ downloaded and served from your server.')) thumbnail = ImageSpecField(image_field='image', processors=[ResizeToFit(220, 160)]) evsdate = DateTimeField(blank=True, null=True, verbose_name=_(u'Event \ starts'), help_text=_(u'Optional field')) evedate = DateTimeField(blank=True, null=True, verbose_name=_(u'Event \ ends'), help_text=_(u'Optional field')) evlocation = CharField(blank=True, verbose_name=_(u'Event location'), help_text=_(u'Optional field, max 255 characters.'), max_length=255) summary = TextField(blank=True, help_text=_(u'An optional "tl;dr" \ field. If filled, the template will output the value in a bold font, \ above the text.')) metadescription = CharField(max_length=160, blank=True, help_text=_(u'\ Optional field, max length 160 characters. Generates a metadescription \ tag for search engines. If left blank, the meta tag will be filled \ with the first 160 characters of the Text field.')) noindex = BooleanField(default=False, help_text=_(u'Check if you have \ reasons to stop search engines from indexing this announcement.')) date = DateTimeField( default=datetime.now, db_index=True, verbose_name=_(u'\ Publish date'), help_text=_('Announcement\'s publishing date and time, \ defaults to now. If you set a future date, the announcement will be \ published at that time.')) expdate = DateTimeField( blank=True, null=True, verbose_name=_(u'Expiration \ date'), help_text=_(u'Optional field. If you set this date, the \ announcement will become unavailble on the public section of the \ website at that time.')) timestamp = DateTimeField(auto_now=True, db_index=True) public = BooleanField(default=False, help_text=_(u'Check this box \ to make the announcement public. Uncheck if you need to stop it from \ appearing on the website.')) objects = AnnouncementsManager() search_objects = SearchManager(fields=( 'title', 'subtitle', 'text', 'summary', )) class Meta: verbose_name = u'Announcement' verbose_name_plural = u'Announcements' ordering = ('-date', '-id') get_latest_by = 'date' def __unicode__(self): return u'%s' % self.title def __init__(self, *args, **kwargs): super(Announcement, self).__init__(*args, **kwargs) # on init, previous and next announcements are unknown, # so they should default to None self._next = None self._prev = None def save(self, *args, **kwargs): # before save, make sure there is a slug if not self.slug: self.slug = slugify(self.title) # send data to the database super(Announcement, self).save(*args, **kwargs) # after save # invalidate cache (next/prev announcement, homepage announcements) if self.public is True: i = self.id keys = ('dcae_ann_%s' % i, 'dcae_anp_%s' % i, 'dcae_han') for key in keys: try: cache.delete(key) except Exception, e: logger.info(e) # now try retreive the remote image, if set and if no image has been # uploaded if self.img_url and not self.image: # first, check if the image has already been downloaded from django.conf import settings from utils.func import image_name_from_url, file_exists expected = '%s/announcements/%s' % ( settings.MEDIA_ROOT, image_name_from_url(self.img_url)) if file_exists(expected): pass # if the file has already been downloaded, execution stops here else: # image hasn't been downloaded yet # check if the provided url is an actual image from utils.func import is_url_image if is_url_image(self.img_url): # download file url = self.img_url path = '%s/announcements/%s' % ( settings.MEDIA_ROOT, image_name_from_url(self.img_url)) try: from urllib import urlretrieve urlretrieve(url, path) except Exception, e: logger.info(e) else: logger.info( u'The provided image URL for the Announcement "%s" was not a real image. Please check again.' % self.title)
class App(TranslatableModel): objects = AppManager() id = CharField(max_length=256, unique=True, primary_key=True, verbose_name=_('ID'), help_text=_('app ID, identical to folder name')) categories = ManyToManyField('Category', verbose_name=_('Category')) translations = TranslatedFields( name=CharField(max_length=256, verbose_name=_('Name'), help_text=_('Rendered app name for users')), summary=CharField( max_length=256, verbose_name=_('Summary'), help_text=_('Short text describing the app\'s purpose')), description=TextField(verbose_name=_('Description'), help_text=_('Will be rendered as Markdown'))) # resources user_docs = URLField(max_length=256, blank=True, verbose_name=_('User documentation URL')) admin_docs = URLField(max_length=256, blank=True, verbose_name=_('Admin documentation URL')) developer_docs = URLField(max_length=256, blank=True, verbose_name=_('Developer documentation URL')) issue_tracker = URLField(max_length=256, blank=True, verbose_name=_('Issue tracker URL')) website = URLField(max_length=256, blank=True, verbose_name=_('Homepage')) discussion = URLField(max_length=256, blank=True, verbose_name=_('Forum')) created = DateTimeField(auto_now_add=True, editable=False, verbose_name=_('Created at')) last_modified = DateTimeField(auto_now=True, editable=False, db_index=True, verbose_name=_('Updated at')) owner = ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_('App owner'), on_delete=CASCADE, related_name='owned_apps') co_maintainers = ManyToManyField(settings.AUTH_USER_MODEL, blank=True, verbose_name=_('Co-Maintainers'), related_name='co_maintained_apps') authors = ManyToManyField('AppAuthor', blank=True, related_name='apps', verbose_name=_('App authors')) is_featured = BooleanField(verbose_name=_('Featured'), default=False) rating_recent = FloatField(verbose_name=_('Recent rating'), default=0.5) rating_overall = FloatField(verbose_name=_('Overall rating'), default=0.5) rating_num_recent = IntegerField( verbose_name=_('Number of recently submitted ratings'), default=0) rating_num_overall = IntegerField( verbose_name=_('Number of overall submitted ratings'), default=0) last_release = DateTimeField(editable=False, db_index=True, verbose_name=_('Last release at'), default=timezone.now) certificate = TextField(verbose_name=_('Certificate')) ownership_transfer_enabled = BooleanField( verbose_name=_('Ownership transfer enabled'), default=False, help_text=_('If enabled, a user can try to register the same app ' 'again using the public certificate and signature. If he ' 'does, the app will be transferred to him.')) is_integration = BooleanField(verbose_name=_('Integration (i.e. Outlook ' 'plugin)'), default=False) approved = BooleanField(verbose_name=_('Used to approve integrations'), default=False) class Meta: verbose_name = _('App') verbose_name_plural = _('Apps') def __str__(self) -> str: return self.name def can_update(self, user: User) -> bool: return self.owner == user or user in self.co_maintainers.all() def can_delete(self, user: User) -> bool: return self.owner == user @property def discussion_url(self): if self.discussion: return self.discussion else: return '%s/c/apps/%s' % (settings.DISCOURSE_URL, self.id.replace('_', '-')) def _get_grouped_releases(self, get_release_func): releases = NextcloudRelease.objects.all() versions = map(lambda r: r.version, releases) compatible_releases = map(lambda v: (v, get_release_func(v)), versions) grouped_releases = group_by_main_version(dict(compatible_releases)) # deduplicate releases result = {} for version, releases in grouped_releases.items(): result[version] = list(distinct(releases, lambda r: r.version)) return result def releases_by_platform_v(self): """Looks up all compatible stable releases for each platform version. Example of returned dict: {'9.1': [<AppRelease object>, <AppRelease object>], '9.0': [<AppRelease object>]} :return dict with all compatible stable releases for each platform version. """ return self._get_grouped_releases(self.compatible_releases) def unstable_releases_by_platform_v(self): """Looks up all compatible unstable releases for each platform version. Example of returned dict: {'9.1': [<AppRelease object>, <AppRelease object>], '9.0': [<AppRelease object>]} :return dict with all compatible unstable releases for each platform version. """ return self._get_grouped_releases(self.compatible_unstable_releases) def latest_releases_by_platform_v(self): """Looks up the latest stable and unstable release for each platform version. Example of returned dict: {'9.1': { 'stable': <AppRelease object>, 'unstable': <AppRelease object> }, '9.0': { 'stable': <AppRelease object> }} :return dict with the latest stable and unstable release for each platform version. """ stable = self.releases_by_platform_v() unstable = self.unstable_releases_by_platform_v() def filter_latest(pair): version, releases = pair return (version, self._latest(releases)) latest_stable = dict(map(filter_latest, stable.items())) latest_unstable = dict(map(filter_latest, unstable.items())) all_versions = set(chain(latest_stable.keys(), latest_unstable.keys())) def stable_or_unstable_releases(ver): return (ver, { 'stable': latest_stable.get(ver, None), 'unstable': latest_unstable.get(ver, None) }) return dict(map(stable_or_unstable_releases, all_versions)) def compatible_releases(self, platform_version, inclusive=True): """Returns all stable releases of this app that are compatible with the given platform version. :param inclusive: Use inclusive version check (see AppRelease.is_compatible()). :return a sorted list of all compatible stable releases. """ return sorted( filter( lambda r: r.is_compatible(platform_version, inclusive) and not r.is_unstable, self.releases.all()), key=lambda r: AppSemVer(r.version, r.is_nightly, r.last_modified), reverse=True) def compatible_unstable_releases(self, platform_version, inclusive=True): """Returns all unstable releases of this app that are compatible with the given platform version. :param inclusive: Use inclusive version check (see AppRelease.is_compatible()). :return a sorted list of all compatible unstable releases. """ return sorted( filter( lambda r: r.is_compatible(platform_version, inclusive) and r. is_unstable, self.releases.all()), key=lambda r: AppSemVer(r.version, r.is_nightly, r.last_modified), reverse=True) def _latest(self, releases): try: return max(releases, key=lambda r: AppSemVer(r.version, r.is_nightly, r. last_modified)) except ValueError: return None def save(self, *args, **kwargs): # If the certificate has changed, delete all releases. try: if self.pk is not None: orig = App.objects.get(pk=self.pk) current = self.certificate.replace('\r', '').strip() former = orig.certificate.replace('\r', '').strip() # for some reason the django admin inserts \r\n for \n so # saving a model in the admin with the same cert kills all # releases if current != former: self.releases.all().delete() except self.DoesNotExist: pass super().save(*args, **kwargs)
class Staff(TranslatableModel): #region -----Translation----- translations = TranslatedFields( second_name=CharField(max_length=40, blank=False, verbose_name=_("Second name")), first_name=CharField(max_length=40, blank=False, verbose_name=_("First name")), third_name=CharField(max_length=40, blank=False, verbose_name=_("Third name")), rank=CharField(max_length=300, blank=True, verbose_name=_("Rank")), methodical_works=HTMLField(blank=True, verbose_name=_("Methodical works")), description=HTMLField(blank=True, verbose_name=_("Description")), ndr_theme=TextField(blank=True, verbose_name=_("Topics of research work"))) #endregion #region -----Information----- google_scholar = URLField(blank=True, verbose_name=_("Google Scholar"), null=True) web_of_science = URLField(blank=True, verbose_name=_("Web Of Science"), null=True) researchgate = URLField(blank=True, verbose_name=_("Researchgate"), null=True) scopus = URLField(verbose_name=_("Scopus"), blank=True, null=True) orcid = URLField(verbose_name=_("ORCID"), blank=True, null=True) photo = ImageField(verbose_name=_("Photo"), upload_to="photos", blank=False) phone = CharField(max_length=20, blank=True, null=True, verbose_name=_("Phone number")) emails = MultiEmailField(blank=True) #endregion #region -----Relation----- disciplines = ManyToManyField(Discipline, blank=True) books = ManyToManyField(Book, blank=True) rewards = ManyToManyField("Reward", blank=True, verbose_name=_("Rewards"), related_name="staff_rewards") #endregion #region -----Metadata----- class Meta(object): verbose_name_plural = _("Staff") verbose_name = _("Staff") #endregion #region -----Internal Methods----- def get_absolute_url(self) -> str: """@return link to model""" return reverse('teacher', kwargs={'teacher_id': self.pk}) def searching_fields(self) -> List[str]: """@return translated fields""" return [ "translations__first_name", "translations__methodical_works", "translations__second_name", "translations__description", "translations__third_name" ] def __str__(self) -> str: """@return staff information""" return (self.second_name + " " + self.first_name + " " + self.third_name)
class YTChannel(Model): url = URLField(unique=True) title = CharField(max_length=70, blank=True) def __str__(self): return self.title
class Poodle(BaseModel): slug = AutoSlugField(default=None, unique=True, populate_from="name_registered") pd_id = IntegerField(verbose_name="PD ID", unique=True, null=True) name_call = CharField(verbose_name="Call Name", max_length=50, blank=True, null=True, default="") name_registered = CharField( verbose_name="Registered Name", max_length=500, blank=True, null=True, default="", ) owners = ManyToManyField(Person, verbose_name="Owner(s)", related_name="owns_poodles", blank=True) breeders = ManyToManyField(Person, verbose_name="Breeder(s)", related_name="bred_poodles", blank=True) pd_owner = CharField(verbose_name="PD Owner", max_length=200, null=True, blank=True, default="") pd_breeder = CharField(verbose_name="PD Breeder", max_length=200, null=True, blank=True, default="") origin_country = ForeignKey(Country, verbose_name="Country", on_delete=PROTECT, null=True) honorifics = CharField(verbose_name="Honorifics", max_length=50, blank=True, null=True, default="") chic = CharField(verbose_name="CHIC", max_length=50, null=True, blank=True, default="") ofa_url = URLField(verbose_name="OFA URL", max_length=300, **NULL_AND_BLANK, default="") akc = CharField(verbose_name="AKC", max_length=50, null=True, blank=True, default="") akc_dna = CharField(verbose_name="AKC DNA", max_length=50, **NULL_AND_BLANK, default="") ukc = CharField(verbose_name="UKC", max_length=50, **NULL_AND_BLANK, default="") addtl = CharField( verbose_name="Addtl Reg", max_length=50, null=True, blank=True, default="", ) sex = CharField(verbose_name="Sex", max_length=1, choices=SEX_CHOICES) pd_color = CharField(verbose_name="PD Color", max_length=100, blank=True, null=True, default="") height = CharField(verbose_name="Height", max_length=10, blank=True, null=True, default="") color = ForeignKey(Color, verbose_name="Color", on_delete=PROTECT, null=True) dob_dod = CharField(verbose_name="Lifespan", max_length=60, blank=True, null=True, default="") dob = CharField(verbose_name="Date of Birth", max_length=12, blank=True, null=True) dod = CharField(verbose_name="Date of Death", max_length=12, blank=True, null=True) sire = ForeignKey("self", verbose_name="Sire", related_name="poodle_sire", null=True, on_delete=PROTECT) dam = ForeignKey("self", verbose_name="Dam", related_name="poodle_dam", null=True, on_delete=PROTECT) pedigree_src = CharField(verbose_name="Pedigree Source", max_length=100, null=True, blank=True, default="") variety = CharField(verbose_name="Variety", max_length=1, null=True, blank=True, default="", choices=VARIETY_CHOICES) pd_variety = CharField( verbose_name="PD Variety", max_length=1, null=True, blank=True, default="", ) titles_prefix = ManyToManyField(Title, verbose_name="Prefix Titles", related_name="poodles_prefix", blank=True) titles_suffix = ManyToManyField(Title, verbose_name="Suffix Titles", related_name="poodles_suffix", blank=True) vwd_clearance = CharField(verbose_name="Von Willebrand Disease", max_length=100, blank=True, null=True, default="") thyroid_clearance = CharField(verbose_name="Thyroid", max_length=100, blank=True, null=True, default="") legg_c_p_clearance = CharField( verbose_name="Legg-Calvé-Perthes Disease (LCP)", max_length=100, blank=True, null=True, default="") pra_optigen_clearance = CharField( verbose_name="Progressive Retinal Atrophy (PRA)", max_length=100, blank=True, null=True, default="") neonatal_enceph_clearance = CharField( verbose_name="Neonatal Encephalopathy", max_length=100, blank=True, null=True, default="") hip_clearance = CharField(verbose_name="Hip Dysplasia", max_length=100, blank=True, null=True, default="") eye_clearance = CharField(verbose_name="Eye Examination", max_length=100, blank=True, null=True, default="") sa_clearance = CharField(verbose_name="Sebaceous Adenitis (SA)", max_length=100, blank=True, null=True, default="") heart_clearance = CharField(verbose_name="Cardiac Disease", max_length=100, blank=True, null=True, default="") elbow_clearance = CharField(verbose_name="Elbow Dysplasia", max_length=100, blank=True, null=True, default="") patella_clearance = CharField(verbose_name="Patellar Luxation", max_length=100, blank=True, null=True, default="") health_information = CharField(verbose_name="Other Health Info", max_length=100, blank=True, null=True, default="") comments = TextField(verbose_name="Comments", **NULL_AND_BLANK, default="") is_viewable = BooleanField(verbose_name="Viewable?", default=False) class Meta(BaseModel.Meta): verbose_name_plural = "Poodles" def __str__(self): if self.name_call: return '{n} "{c}"'.format(n=self.name_registered, c=self.name_call) else: return self.name_registered def get_absolute_url(self): return reverse("core:poodle-detail", args=[str(self.slug)]) def get_owners(self): return ", ".join([o.full_name for o in self.owners.all()]) def get_breeders(self): return ", ".join([o.full_name for o in self.breeders.all()]) def get_titles_p(self): return " ".join([o.abbr for o in self.titles_prefix.all()]) def get_titles_s(self): return " ".join([o.abbr for o in self.titles_suffix.all()]) def offspring(self): return Poodle.objects.filter(Q(sire=self.id) | Q(dam=self.id)).order_by( 'sire', 'dam').select_related( "color", "origin_country", "sire", "dam", ).prefetch_related( "color", "origin_country", "sire", "dam", ) def siblings_full(self): return Poodle.objects.filter(Q(sire=self.sire) & Q( dam=self.dam)).exclude(id=self.id).order_by('name_registered') def siblings_damside(self): return Poodle.objects.filter(~Q(sire=self.sire) & Q(dam=self.dam)).exclude( id=self.id).order_by('dam') def siblings_sireside(self): return Poodle.objects.filter(Q(sire=self.sire) & ~Q(dam=self.dam)).exclude( id=self.id).order_by('sire') def images(self): return self.poodles_images.all() @staticmethod def autocomplete_search_fields(): return ('name_registered__icontains', 'name_call__icontains')
class User(AbstractUser): # First Name and Last Name do not cover name patterns # around the globe. nickname = CharField(verbose_name="昵称", null=True, blank=True, max_length=255, default='') name = CharField(verbose_name="真实姓名", null=True, blank=True, max_length=255, default='') avatar = ImageField(upload_to='users/avatars/', null=True, blank=True, verbose_name='用户头像', default='') sex = CharField(verbose_name="性别", choices=(("M", "男"), ("F", "女"), ("P", "不公开")), default="P", max_length=50) birthday = DateField(verbose_name="生日", null=True, blank=True, default=timezone.now) position = CharField(verbose_name="职位", null=True, blank=True, max_length=255, default='') company = CharField(verbose_name="公司", null=True, blank=True, max_length=255, default='') education = CharField(verbose_name="学历", null=True, blank=True, max_length=255, default='') industry = CharField(verbose_name="行业", null=True, blank=True, max_length=255, default='') introduction = CharField(verbose_name="简介", null=True, blank=True, max_length=255, default='') website = URLField(verbose_name="网站", null=True, blank=True, max_length=255, default='') skill = TaggableManager(help_text='多个标签使用英文逗号(,)隔开', blank=True, verbose_name='技能') # skill = CharField(verbose_name='技能', blank=True,null=True, default='', max_length=512) # homepage = ManyToManyField(Homepages, null=True, blank=True, verbose_name="个人主页") # medal = ForeignKey(Medal, on_delete=models.CASCADE, verbose_name="勋章") created_at = DateField(auto_now_add=True, verbose_name='创建时间') class Meta: verbose_name = '用户' verbose_name_plural = verbose_name def __str__(self): return self.username def get_profile_name(self): if self.nickname: return self.nickname return self.username def get_absolute_url(self): return reverse("users:detail", kwargs={"username": self.username})
class HomePage(BasePage): subpage_types = [ "articles.Articles", "content.ContentPage", "events.Events", "people.People", "topics.Topics", "videos.Videos", ] template = "home.html" # Content fields subtitle = TextField(max_length=250, blank=True, default="") button_text = CharField(max_length=30, blank=True, default="") button_url = CharField(max_length=2048, blank=True, default="") image = ForeignKey( "mozimages.MozImage", null=True, blank=True, on_delete=SET_NULL, related_name="+", ) featured = StreamField( StreamBlock( [ ( "post", PageChooserBlock(target_model=( "articles.Article", "externalcontent.ExternalArticle", )), ), ( "content_page", PageChooserBlock(target_model=("content.ContentPage", )), ), ("external_page", FeaturedExternalBlock()), ( "video", PageChooserBlock(target_model=( "videos.Video", # NB: ExternalVideo is NOT allowed on the homepage # "externalcontent.ExternalVideo" )), ), ], min_num=2, max_num=5, required=False, ), null=True, blank=True, help_text= ("Optional space for featured posts, videos or links, min. 2, max. 5. " "Note that External Video is NOT allowed here."), ) featured_people = StreamField( StreamBlock( [("person", PageChooserBlock(target_model="people.Person"))], max_num=3, required=False, ), null=True, blank=True, help_text="Optional featured people, max. 3", ) about_title = TextField(max_length=250, blank=True, default="") about_subtitle = TextField(max_length=250, blank=True, default="") about_button_text = CharField(max_length=30, blank=True, default="") about_button_url = URLField(max_length=140, blank=True, default="") # Card fields card_title = CharField("Title", max_length=140, blank=True, default="") card_description = TextField("Description", max_length=DESCRIPTION_MAX_LENGTH, blank=True, default="") card_image = ForeignKey( "mozimages.MozImage", null=True, blank=True, on_delete=SET_NULL, related_name="+", verbose_name="Image", ) # Meta fields keywords = ClusterTaggableManager(through=HomePageTag, blank=True) # Editor panel configuration content_panels = BasePage.content_panels + [ MultiFieldPanel( [ FieldPanel("subtitle"), FieldPanel("button_text"), FieldPanel("button_url"), ], heading="Header section", help_text="Optional fields for the header section", ), MultiFieldPanel( [ImageChooserPanel("image")], heading="Image", help_text= ("Optional image shown when sharing this page through social media" ), ), StreamFieldPanel("featured"), StreamFieldPanel("featured_people"), MultiFieldPanel( [ FieldPanel("about_title"), FieldPanel("about_subtitle"), FieldPanel("about_button_text"), FieldPanel("about_button_url"), ], heading="About section", help_text="Optional section to explain more about Mozilla", ), ] # Card panels card_panels = [ MultiFieldPanel( [ FieldPanel("card_title"), FieldPanel("card_description"), ImageChooserPanel("card_image"), ], heading="Card overrides", help_text=(( "Optional fields to override the default title, " "description and image when this page is shown as a card")), ) ] # Meta panels meta_panels = [ MultiFieldPanel( [ FieldPanel("seo_title"), FieldPanel("search_description"), ImageChooserPanel("social_image"), FieldPanel("keywords"), ], heading="SEO", help_text=("Optional fields to override the default " "title and description for SEO purposes"), ) ] # Settings panels settings_panels = [FieldPanel("slug")] # Tabs edit_handler = TabbedInterface([ ObjectList(content_panels, heading="Content"), ObjectList(card_panels, heading="Card"), ObjectList(meta_panels, heading="Meta"), ObjectList(settings_panels, heading="Settings", classname="settings"), ]) @classmethod def can_create_at(cls, parent): # Allow only one instance of this page type return super().can_create_at(parent) and not cls.objects.exists() @property def primary_topics(self): """The site’s top-level topics, i.e. topics without a parent topic.""" from ..topics.models import Topic return Topic.published_objects.filter(parent_topics__isnull=True)
class HierarchicUser(TreeModelMixin, AbstractUser): show_email = BooleanField(_('afficher l’email'), default=False) website = URLField(_('site internet'), blank=True) website_verbose = CharField( _('nom affiché du site internet'), max_length=50, blank=True) legal_person = BooleanField( _('personne morale'), default=False, help_text=_('Cochez si vous êtes une institution ou un ensemble.')) content_type = ForeignKey( ContentType, blank=True, null=True, limit_choices_to={'model__in': _get_valid_modelnames_func()}, verbose_name=_('type d’autorité associée'), on_delete=CASCADE) object_id = PositiveIntegerField(_('identifiant de l’autorité associée'), blank=True, null=True) content_object = GenericForeignKey() mentor = ForeignKey( 'self', null=True, blank=True, related_name='disciples', verbose_name=_('responsable scientifique'), limit_choices_to={'willing_to_be_mentor__exact': True}, on_delete=CASCADE) path = PathField(order_by=('last_name', 'first_name', 'username'), db_index=True) willing_to_be_mentor = BooleanField( _('Veut être responsable scientifique'), default=False) avatar = ImageField(_('photographie d’identité'), upload_to='avatars/', blank=True, null=True) presentation = TextField( _('présentation'), blank=True, validators=[MaxLengthValidator(5000)]) fonctions = TextField(_('fonctions au sein de l’équipe'), blank=True, validators=[MaxLengthValidator(200)]) literature = TextField(_('publications'), blank=True) objects = HierarchicUserManager() class Meta(object): ordering = ('last_name', 'first_name') verbose_name = _('utilisateur') verbose_name_plural = _('utilisateurs') def __str__(self, tags=False): return self.html(tags=False) def get_full_name(self, tags=False): full_name = f'{self.first_name} {sc(self.last_name, tags=tags)}' return full_name.strip() def html(self, tags=True): txt = self.get_full_name(tags=tags) or self.get_username() return href(self.get_absolute_url(), txt, tags=tags) def link(self, tags=True): return self.html(tags=tags) @permalink def get_absolute_url(self): return 'user_profile', (self.username,) def website_link(self): return href(self.website, self.website_verbose or self.website, new_tab=True) def email_link(self): return href(f'mailto:{self.email}', self.email) def dossiers_edites(self): return apps.get_model('dossiers.DossierDEvenements').objects.filter( editeurs_scientifiques=self ).exclude(parent__editeurs_scientifiques=self) @staticmethod def autocomplete_search_fields(): return ('first_name__unaccent__icontains', 'last_name__unaccent__icontains')
class ExternalFile(Model): url = URLField(default="", blank=True) label = TextField()
class Kid(Model): class Color(IntegerChoices): BLACK = 1, _("Preto") BROWN = 2, _("Castanhos") BLONDE = 3, _("Loiro") RED = 4, _("Ruivo") BLUE = ( 5, _("Azul"), ) SWARTHY = 6, _("Morena") WHITE = 7, _("Branca") # required fiels name = CharField("Nome", max_length=255, db_index=True, unique=True) url = URLField("URL") full_text = TextField() # optional indexed fields dob = DateField("Data de nascimento", null=True, blank=True, db_index=True) missing_since = DateField( "Desaparecida(o) desde", null=True, blank=True, db_index=True ) eyes = CharField( "Cor dos olhos", max_length=50, choices=Color.choices, null=True, blank=True, db_index=True, ) hair = CharField( "Cor dos cabelos", max_length=50, choices=Color.choices, null=True, blank=True, db_index=True, ) skin = CharField( "Cor da pele", max_length=50, choices=Color.choices, null=True, blank=True, db_index=True, ) # optional fields mother = CharField("Mãe", max_length=255, null=True, blank=True) father = CharField("Pai", max_length=255, null=True, blank=True) last_seen_at = CharField( "Local onde foi vista(o) pela última vez", max_length=255, null=True, blank=True ) age_at_occurrence = IntegerField("Idade quando desapareceu", null=True, blank=True) class Meta: verbose_name = "criança" ordering = ("name",) def __str__(self): return self.name
class ExternalContent(BasePage): is_external = True subpage_types = [] # Card fields description = RichTextField( blank=True, default="", features=RICH_TEXT_FEATURES_SIMPLE, help_text="Optional short text description, max. 400 characters", max_length=400, ) external_url = URLField( "URL", blank=True, default="", help_text=( "The URL that this content links to, max. 2048 characters " "for compatibility with older web browsers" ), max_length=2048, ) image = ForeignKey( "mozimages.MozImage", null=True, blank=True, on_delete=SET_NULL, related_name="+", ) card_panels = BasePage.content_panels + [ FieldPanel("description"), MultiFieldPanel( [ImageChooserPanel("image")], heading="Image", help_text=( "Optional header image. If not specified a fallback will be used. " "This image is also shown when sharing this page via social media" ), ), FieldPanel("external_url"), ] settings_panels = BasePage.settings_panels + [FieldPanel("slug")] edit_handler = TabbedInterface( [ ObjectList(card_panels, heading="Card"), ObjectList(settings_panels, heading="Settings", classname="settings"), ] ) class Meta: verbose_name_plural = "External Content" def get_full_url(self, request=None): return self.external_url def get_url(self, request=None, current_site=None): return self.external_url def relative_url(self, current_site, request=None): return self.external_url @property def url(self): return self.external_url def serve_preview(self, request, mode_name): # ExternalContent subclasses don't preview like regular Pages: we just need # to show where they link to. return HttpResponseRedirect(self.external_url)
class Film(Model): titre = CharField(max_length=200, unique=True) respo = ForeignKey(User) description = TextField() slug = SlugField(unique=True, blank=True) annee_sortie = IntegerField(choices=CHOIX_ANNEES, blank=True, null=True, verbose_name="Année de sortie") titre_vo = CharField(max_length=200, blank=True, null=True, verbose_name="Titre en VO") imdb = URLField(blank=True, null=True, verbose_name="IMDB") allocine = URLField(blank=True, null=True, verbose_name="Allociné") realisateur = CharField(max_length=200, null=True, blank=True, verbose_name="Réalisateur") duree = CharField(max_length=20, null=True, blank=True, verbose_name="Durée") duree_min = IntegerField("Durée en minutes", null=True) vu = BooleanField(default=False) imdb_id = CharField(max_length=10, verbose_name="id IMDB", null=True, blank=True) imdb_poster_url = URLField(blank=True, null=True, verbose_name="URL du poster") imdb_poster = ImageField(upload_to='cine/posters', blank=True, null=True) def save(self, *args, **kwargs): update = self.pk is None if not update: orig = Film.objects.get(pk=self.pk) if orig.slug != self.slug or orig.imdb_poster_url != self.imdb_poster_url: update = True if update: self.slug = slugify(self.titre) img = requests.get(self.imdb_poster_url) if img.status_code == requests.codes.ok: img_temp = NamedTemporaryFile(delete=True) img_temp.write(img.content) img_temp.flush() self.imdb_poster.save(self.slug, File(img_temp), save=False) img_temp.close() super(Film, self).save(*args, **kwargs) if update: self.nouveau() def nouveau(self): # Création des votes & envoi des mails de notif film_url = self.get_full_url() vote_url = full_url(reverse('cine:votes')) message = "Hello :)\n\n%s a proposé un nouveau film : %s (%s)' ; " % ( self.respo, self.titre, film_url) message += "tu peux donc aller actualiser ton classement (%s) \\o/ \n\n @+!" % vote_url for cinephile in get_cinephiles(): vote = Vote.objects.get_or_create(film=self, cinephile=cinephile) if vote[1] and settings.PROD: cinephile.email_user('[CinéNim] Film ajouté !', message) def get_absolute_url(self): return reverse('cine:film', kwargs={'slug': self.slug}) def get_full_url(self): return full_url(self.get_absolute_url()) def get_description(self): return self.description.replace('\r\n', '\\n') def score_absolu(self): score = 0 for vote in self.vote_set.all(): score -= vote.choix return score @staticmethod def get_imdb_dict(imdb_id): try: imdb_id = re.search(r'tt\d+', imdb_id).group() imdb_infos = requests.get(IMDB_API_URL, params={ 'i': imdb_id }).json() return { 'realisateur': imdb_infos['Director'], 'description': imdb_infos['Plot'], 'imdb_poster_url': imdb_infos['Poster'], 'annee_sortie': imdb_infos['Year'], 'titre': imdb_infos['Title'], 'titre_vo': imdb_infos['Title'], 'duree_min': int( timedelta(**dict([ (key, int(value) if value else 0) for key, value in re.search( r'((?P<hours>\d+) h )?(?P<minutes>\d+) min', imdb_infos['Runtime']).groupdict().items() ])).seconds / 60), # TGCM 'imdb_id': imdb_id, 'imdb': 'http://www.imdb.com/title/%s/' % imdb_id, } except: return {} def __str__(self): return self.titre
class UserInfo(Model): class Meta: verbose_name = '用户信息' verbose_name_plural = '用户信息表' UserModel = settings.AUTH_USER_MODEL user = OneToOneField(UserModel, related_name='user_info') stu_id = PositiveIntegerField( '学号', unique=True, validators=[RegexValidator(r'\d{10}', '学号为10位数字')]) id_card_number = CharField( '身份证号', max_length=18, unique=True, null=True, validators=[RegexValidator(r'\d{17}[xX\d]{1}', '身份证号格式不正确')], editable=False) sys_password = CharField('教务系统密码', max_length=32) name = CharField('姓名', max_length=10, null=True) avatar = URLField('照片', null=True) sex = CharField('性别', max_length=1, choices=[('男', '男'), ('女', '女')], null=True) birthday = DateTimeField('生日', null=True) phone = CharField('联系电话', max_length=13, null=True, validators=[ RegexValidator(r'\d{11}|\d{4}-\d{7}', '电话格式为11位数字或 0000-1234567') ]) home_phone = CharField('家庭电话', max_length=13, null=True, validators=[ RegexValidator(r'\d{11}|\d{4}-\d{7}', '电话格式为11位数字或 0000-1234567') ]) high_school = CharField('毕业高中', max_length=20, null=True) college = CharField('学院简称', max_length=20, null=True) major = CharField('专业简称', max_length=20, null=True) klass = CharField('班级简称', max_length=20, null=True) nation = CharField('民族', max_length=10, null=True) native_place = CharField('籍贯', max_length=10, null=True) poi_id = IntegerField('poi数据id', unique=True, null=True) qq = IntegerField('QQ', unique=True, null=True, validators=[RegexValidator(r'\d{5,15}', 'QQ号码最少为5位数字')]) address = CharField('家庭地址', max_length=128, null=True) def sync_info_from_hfut(self): stu = StuLib(self.stu_id, self.sys_password) stu_info = stu.get_stu_info() res = lbs_storage.list_poi( GEOTABLE_ID, stu_id=','.join([unicode(self.stu_id), unicode(self.stu_id)])) if res['size'] == 1: lbs_storage.delete_poi(GEOTABLE_ID, res['pois'][0]['id']) hfut_stu_location_logger.warning( '已存在学号为 {:d} 的 poi 数据, 已删除'.format(self.stu_id)) loc = lbs_api.geocoding(stu_info['家庭地址'])['result']['location'] res = lbs_storage.create_poi( GEOTABLE_ID, title='-'.join([stu_info['班级简称'], stu_info['姓名']]), latitude=loc['lat'], longitude=loc['lng'], address=stu_info['家庭地址'], avatar=stu_info['照片'], name=stu_info['姓名'], stu_id=stu.stu_id, sex=stu_info['性别'], high_school=stu_info['毕业高中'], college=stu_info['学院简称'], major=stu_info['专业简称'], klass=stu_info['班级简称'], tags=' '.join([ stu_info['性别'], stu_info['毕业高中'], stu_info['学院简称'], stu_info['专业简称'], stu_info['班级简称'] ])) hfut_stu_location_logger.info('成功新建学号为 {:d} 的 poi 数据'.format( self.stu_id)) self.poi_id = res['id'] self.id_card_number = stu_info['身份证号'] self.avatar = stu_info['照片'] self.name = stu_info['姓名'] self.sex = stu_info['性别'] self.birthday = datetime.strptime(stu_info['出生日期'], '%Y-%m-%d') self.phone = stu_info['联系电话'] self.home_phone = stu_info['家庭电话'] self.high_school = stu_info['毕业高中'] self.college = stu_info['学院简称'] self.major = stu_info['专业简称'] self.klass = stu_info['班级简称'] self.nation = stu_info['民族'] self.native_place = stu_info['籍贯'] self.address = stu_info['家庭地址'] self.save() def delete_data(self, with_poi=True): self.delete() if with_poi: lbs_storage.delete_poi(GEOTABLE_ID, self.poi_id) def filter_info_by_config(self): # todo: 完善详细资料获取功能 info = {} if self.user_info_config.show_qq: info['QQ'] = self.qq if self.user_info_config.show_phone: info['联系电话'] = self.phone if self.user_info_config.show_home_phone: info['家庭电话'] = self.home_phone if self.user_info_config.show_birthday: info['生日'] = self.birthday if self.user_info_config.show_avatar: info['照片'] = self.avatar return info def __unicode__(self): return ' '.join([unicode(self.stu_id), self.name])
class MessageHistory(models.Model): time = models.BigIntegerField(default=get_milliseconds) message = models.ForeignKey('Message', models.CASCADE, null=False) content = models.TextField(null=True, blank=True) giphy = URLField(null=True, blank=True)
class MusicAccess(Model): user_agent = TextField("Client's user agent", null = True) ip_address = CharField("Client's IP address", max_length = 45, null = True) referer = URLField("HTTP referer", null = True) music_id = IntegerField("Id accessed")
class Entry(models.Model): TYPE_TUTORIAL = 'tutorial' TYPE_PROJECT = 'project' TYPE_JUPYTER = 'jupyter' TYPE_CHOICES = ( (TYPE_TUTORIAL, 'Tutorial'), (TYPE_PROJECT, 'Project'), (TYPE_JUPYTER, 'Jupyter Notebook') ) ICON_MAP = { TYPE_TUTORIAL: '<i class="fa fa-graduation-cap"></i>', TYPE_PROJECT: '<i class="fa fa-bolt"></i>', TYPE_JUPYTER: '<i class="fa fa-code"></i>', } type = CharField(max_length=10, choices=TYPE_CHOICES) title = CharField(max_length=250, help_text='The main title of the entry. Does not have to be unique') subtitle = CharField(max_length=250, default='', blank=True) description = CharField(max_length=200, default='', blank=True) author = ForeignKey(User, on_delete=models.CASCADE, default=1, related_name='tutorials') thumbnail = FilerImageField(related_name="tutorial_thumbnail", on_delete=models.CASCADE, null=True) slug = SlugField(max_length=250, default='auto', unique=True) content = TextField(default='') text = TextField(default='') publishing_date = DateTimeField(default=timezone.now) creation_date = DateTimeField(default=timezone.now) next = URLField(null=True, blank=True) previous = URLField(null=True, blank=True) comments = GenericRelation(Comment) def save(self, *args, **kwargs) -> None: if self.slug == 'auto': self.slug = slugify(self.title) # So we need the "text" property to literally just contain the content of the post in all lower case and # without all the html markup (this will be used for fulltext search of keywords). BeautifulSoup does this # really well natively. soup = BeautifulSoup(self.content, 'lxml') self.text = soup.text.lower() super(Entry, self).save(*args, **kwargs) @classmethod def get_most_recent(cls, n: int) -> List[Entry]: entries = cls.objects.order_by('-publishing_date').exclude(publishing_date__gte=timezone.now()).all()[0:n] return entries @property def comment_count(self): return len(self.comments.filter(active=True)) @property def fa_icon(self): return self.ICON_MAP[self.type] @property def url(self) -> str: """ Returns the absolute URL of the detail view of the entry instance. :return: """ # This is a bit hacky (because it technically stretches the limits of SOC a bit) but very convenient! # Here is the thing: This is an abstract base model which will be the base for multiple specific # implementations, but we want a common list view for those and a list view would need knowledge of the urls # of the detail pages to link to those correctly. Thus we need a generalized method for getting those aka # we cannot do the {% url "..." %} thing because for that we need to provide a *specific* model type, which we # generally do not know at that point since it could be any specific implementation. Sooo it would be better if # the url information for the detail page would be attached to every individual element right away <- this # property. # Now this only works because of an implicit assumption we make: In the "url.py" module we set the name of # the according detail view for a model to the "type" property of the corresponding model class. If we adhere # to this convention, we can make use of it here and already assemble all the information to let django reverse # the url for a specific Entry instance... view_name = f'{BlogAppConfig.name}:{self.type}' return reverse_lazy(view_name, kwargs={'slug': self.slug}) def __str__(self): return f'{self.type.upper()}: {self.title}'