class Category(TranslatableModel): slug = models.SlugField(_('slug'), max_length=100, unique=True) image = ImageField(_("image"), max_length=255, blank=True, null=True, upload_to='categories/', help_text=_("Category image")) video = models.FileField( _("video"), max_length=255, blank=True, null=True, validators=[ validate_video_file_size, FileMimetypeValidator( allowed_mimetypes=settings.VIDEO_FILE_ALLOWED_MIME_TYPES) ], help_text=_('This video will autoplay at the background. ' 'Allowed types are mp4, ogg, 3gp, avi, mov and webm. ' 'File should be smaller then 10MB.'), upload_to='banner_slides/') image_logo = ImageField(_("logo"), max_length=255, blank=True, null=True, upload_to='categories/logos/', help_text=_("Category Logo image")) translations = TranslatedFields(title=models.CharField(_("name"), max_length=255), description=models.TextField( _("description"))) class Meta(object): verbose_name = _("category") verbose_name_plural = _("categories") # ordering = ['title'] permissions = (('api_read_category', 'Can view categories through API'), ) def __str__(self): return self.title def save(self, **kwargs): if not self.slug: self.slug = slugify(self.title) super(Category, self).save(**kwargs) def get_absolute_url(self): return 'https://{}/projects/?category={}'.format( properties.tenant.domain_url, self.slug)
class PictureItem(ContentItem): """ Picture content item """ class PictureAlignment(DjangoChoices): float_left = ChoiceItem('float-left', label=_("Float left")) center = ChoiceItem('center', label=_("Center")) float_right = ChoiceItem('float-right', label=_("Float right")) image = ImageField( _("Picture"), upload_to='content_images', validators=[ FileMimetypeValidator( allowed_mimetypes=settings.IMAGE_ALLOWED_MIME_TYPES, ), validate_file_infection ]) align = models.CharField(_("Align"), max_length=50, choices=PictureAlignment.choices) class Meta(object): verbose_name = _("Picture") verbose_name_plural = _("Pictures") def __str__(self): return self.image.name if self.image else u'(no image)'
class Slide(SortableMixin, models.Model): block = models.ForeignKey('cms.SlidesContent', related_name='slides') tab_text = models.CharField( _("Tab text"), max_length=100, help_text=_("This is shown on tabs beneath the banner.") ) title = models.CharField(_("Title"), max_length=100, blank=True) body = models.TextField(_("Body text"), blank=True) image = ImageField( _("Image"), max_length=255, blank=True, null=True, upload_to='banner_slides/', validators=[ FileMimetypeValidator( allowed_mimetypes=settings.IMAGE_ALLOWED_MIME_TYPES, ), validate_file_infection ] ) background_image = ImageField( _("Background image"), max_length=255, blank=True, null=True, upload_to='banner_slides/', validators=[ FileMimetypeValidator( allowed_mimetypes=settings.IMAGE_ALLOWED_MIME_TYPES, ), validate_file_infection ] ) video_url = models.URLField( _("Video url"), max_length=100, blank=True, default='' ) link_text = models.CharField( _("Link text"), max_length=400, help_text=_("This is the text on the button inside the banner."), blank=True ) link_url = models.CharField( _("Link url"), max_length=400, help_text=_("This is the link for the button inside the banner."), blank=True ) sequence = models.PositiveIntegerField(default=0, editable=False, db_index=True) class Meta: ordering = ['sequence']
class Quote(models.Model): block = models.ForeignKey('cms.QuotesContent', related_name='quotes') name = models.CharField(max_length=60) quote = models.TextField() image = ImageField(_("Image"), max_length=255, blank=True, null=True, upload_to='quote_images/')
class Category(models.Model): title = models.CharField(_("name"), max_length=255, unique=True) slug = models.SlugField(_('slug'), max_length=100, unique=True) description = models.TextField(_("description")) image = ImageField(_("image"), max_length=255, blank=True, null=True, upload_to='categories/', help_text=_("Category image")) image_logo = ImageField(_("logo"), max_length=255, blank=True, null=True, upload_to='categories/logos/', help_text=_("Category Logo image")) class Meta: ordering = ('title', ) verbose_name = _("category") verbose_name_plural = _("categories") ordering = ['title'] def __unicode__(self): return self.title def save(self, **kwargs): if not self.slug: self.slug = slugify(self.title) super(Category, self).save(**kwargs) def get_absolute_url(self): return 'https://{}/projects/?category={}'.format( properties.tenant.domain_url, self.slug) @property def projects(self): return self.project_set\ .order_by('-favorite', '-popularity')\ .filter(status__slug__in=['campaign', 'done-complete', 'done-incomplete', 'voting', 'voting-done'])
class BaseFundraiser(models.Model): owner = models.ForeignKey('members.Member', verbose_name=_("initiator"), help_text=_("Project owner")) project = models.ForeignKey('projects.Project', verbose_name=_("project")) title = models.CharField(_("title"), max_length=255) description = models.TextField(_("description"), blank=True) image = ImageField(_("picture"), max_length=255, blank=True, null=True, upload_to='fundraiser_images/', help_text=_("Minimal of 800px wide")) video_url = models.URLField(max_length=100, blank=True, default='') amount = MoneyField(_("amount")) deadline = models.DateTimeField(null=True) created = CreationDateTimeField( _("created"), help_text=_("When this fundraiser was created.")) updated = ModificationDateTimeField(_('updated')) deleted = models.DateTimeField(_('deleted'), blank=True, null=True) location = models.ForeignKey('geo.Location', null=True, blank=True) wallposts = GenericRelation(Wallpost, related_query_name='fundraiser_wallposts') def __unicode__(self): return self.title @property def amount_donated(self): donations = self.donation_set.filter(order__status__in=[ StatusDefinition.SUCCESS, StatusDefinition.PENDING, StatusDefinition.PLEDGED ]) totals = [ Money(data['amount__sum'], data['amount_currency']) for data in donations.values('amount_currency').annotate( Sum('amount')).order_by() ] totals = [convert(amount, self.amount.currency) for amount in totals] return sum(totals) or Money(0, self.amount.currency) class Meta(): abstract = True verbose_name = _('fundraiser') verbose_name_plural = _('fundraisers')
class NewsItem(AnonymizationMixin, PublishableModel): title = models.CharField(_("Title"), max_length=200) slug = models.SlugField(_("Slug")) # Contents main_image = ImageField( _("Main image"), help_text=_("Shows at the top of your post."), upload_to='blogs', blank=True, validators=[ FileMimetypeValidator( allowed_mimetypes=settings.IMAGE_ALLOWED_MIME_TYPES, ), validate_file_infection ]) language = models.CharField(_("language"), max_length=5, choices=lazy(get_languages, tuple)()) contents = PlaceholderField("blog_contents", plugins=[ 'TextPlugin', 'ImageTextPlugin', 'OEmbedPlugin', 'RawHtmlPlugin', 'PicturePlugin' ]) # This should not be necessary, but fixes deletion of some news items # See https://github.com/edoburu/django-fluent-contents/issues/19 contentitem_set = ContentItemRelation() allow_comments = models.BooleanField(_("Allow comments"), default=True) def __str__(self): return self.title def get_meta_description(self, **kwargs): request = kwargs.get('request') s = MLStripper() s.feed(mark_safe(render_placeholder(request, self.contents).html)) return truncatechars(s.get_data(), 250) class Meta(object): verbose_name = _("news item") verbose_name_plural = _("news items") permissions = ( ('api_read_newsitem', 'Can view news items through the API'), ('api_add_newsitem', 'Can add news items through the API'), ('api_change_newsitem', 'Can change news items through the API'), ('api_delete_newsitem', 'Can delete news items through the API'), )
class Logo(SortableMixin, models.Model): block = models.ForeignKey('cms.LogosContent', related_name='logos') image = ImageField(_("Image"), max_length=255, blank=True, null=True, upload_to='logo_images/') link = models.CharField(max_length=100, blank=True, null=True) sequence = models.PositiveIntegerField(default=0, editable=False, db_index=True) class Meta: ordering = ['sequence']
class Quote(models.Model): block = models.ForeignKey('cms.QuotesContent', related_name='quotes') name = models.CharField(max_length=60) quote = models.TextField() image = ImageField( _("Image"), max_length=255, blank=True, null=True, upload_to='quote_images/', validators=[ FileMimetypeValidator( allowed_mimetypes=settings.IMAGE_ALLOWED_MIME_TYPES, ), validate_file_infection ] )
class Step(SortableMixin, models.Model): block = models.ForeignKey('cms.StepsContent', related_name='steps') image = ImageField(_("Image"), max_length=255, blank=True, null=True, upload_to='step_images/') header = models.CharField(_("Header"), max_length=100) text = models.CharField(_("Text"), max_length=400, null=True, blank=True) sequence = models.PositiveIntegerField(default=0, editable=False, db_index=True) class Meta: ordering = ['sequence']
class CategoryContent(SortableMixin, TranslatableModel): category = models.ForeignKey(Category, related_name='contents') translations = TranslatedFields( title=models.CharField(_('title'), max_length=60, help_text=_("Max: %(chars)s characters.") % {'chars': 60}), description=models.TextField( _('description'), max_length=190, blank=True, default='', help_text=_("Max: %(chars)s characters.") % {'chars': 190}), link_text=models.CharField( _("link name"), max_length=60, blank=True, default=_("Read more"), help_text=_( "The link will only be displayed if an URL is provided. " "Max: %(chars)s characters.") % {'chars': 60}), link_url=models.CharField(_("link url"), max_length=300, blank=True)) image = ImageField(_('image'), max_length=255, blank=True, null=True, upload_to='categories/content/', help_text=_("Accepted file format: .jpg, .jpeg & .png")) video_url = models.URLField( max_length=100, blank=True, default='', help_text= _("Setting a video url will replace the image. Only YouTube or Vimeo videos " "are accepted. Max: %(chars)s characters.") % {'chars': 100}) sequence = models.PositiveIntegerField(default=0, editable=False, db_index=True) class Meta(object): verbose_name = _("content block") verbose_name_plural = _("content blocks") ordering = ['sequence'] def __str__(self): return self.title
class Logo(SortableMixin, models.Model): block = models.ForeignKey('cms.LogosContent', related_name='logos') image = ImageField( _("Image"), max_length=255, blank=True, null=True, upload_to='logo_images/', validators=[ FileMimetypeValidator( allowed_mimetypes=settings.IMAGE_ALLOWED_MIME_TYPES, ), validate_file_infection ] ) link = models.CharField(max_length=100, blank=True, null=True) sequence = models.PositiveIntegerField(default=0, editable=False, db_index=True) class Meta: ordering = ['sequence']
class Organization(ValidatedModelMixin, AnonymizationMixin, models.Model): """ Organizations can run Projects. An organization has one or more members. """ name = models.CharField(_('name'), max_length=255) slug = models.SlugField(_('slug'), max_length=100) description = models.TextField(_('description'), default='', blank=True) created = CreationDateTimeField(_('created')) updated = ModificationDateTimeField(_('updated')) owner = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_('owner'), null=True) website = models.URLField(_('website'), blank=True) logo = ImageField( _('logo'), blank=True, help_text=_('Partner Organization Logo'), max_length=255, null=True, upload_to='partner_organization_logos/', validators=[ FileMimetypeValidator( allowed_mimetypes=settings.IMAGE_ALLOWED_MIME_TYPES, ), validate_file_infection ] ) required_fields = ['name', 'website'] def __str__(self): return self.name def save(self, *args, **kwargs): self.slug = slugify(self.name) super(Organization, self).save(*args, **kwargs) class Meta(object): ordering = ['name'] verbose_name = _("partner organization") verbose_name_plural = _("partner organizations")
class PictureItem(ContentItem): """ Picture content item """ class PictureAlignment(DjangoChoices): float_left = ChoiceItem('float-left', label=_("Float left")) center = ChoiceItem('center', label=_("Center")) float_right = ChoiceItem('float-right', label=_("Float right")) image = ImageField(_("Picture"), upload_to='content_images') align = models.CharField(_("Align"), max_length=50, choices=PictureAlignment.choices) class Meta: verbose_name = _("Picture") verbose_name_plural = _("Pictures") def __unicode__(self): return self.image.name if self.image else u'(no image)'
class BlueBottleBaseUser(AbstractBaseUser, PermissionsMixin): """ Custom user model for BlueBottle. When extending the user model, the serializer should extend too. We provide a default base serializer in sync with the base user model The Django Meta attribute seems the best place for this configuration, so we have to add this. """ class Gender(DjangoChoices): male = ChoiceItem('male', label=_('Male')) female = ChoiceItem('female', label=_('Female')) class UserType(DjangoChoices): person = ChoiceItem('person', label=_('Person')) company = ChoiceItem('company', label=_('Company')) foundation = ChoiceItem('foundation', label=_('Foundation')) school = ChoiceItem('school', label=_('School')) group = ChoiceItem('group', label=_('Club / association')) email = models.EmailField(_('email address'), db_index=True, max_length=254, unique=True) username = models.CharField(_('username'), max_length=254, unique=True) is_staff = models.BooleanField(_('staff status'), default=False, help_text=_('Designates whether the user can log into this admin site.')) is_active = models.BooleanField(_('active'), default=False, help_text=_('Designates whether this user should be treated as active. Unselect ' 'this instead of deleting accounts.')) disable_token = models.CharField(blank=True, max_length=32, null=True) date_joined = models.DateTimeField(_('date joined'), default=timezone.now) updated = ModificationDateTimeField() last_seen = models.DateTimeField(_('Last Seen'), blank=True, null=True) deleted = models.DateTimeField(_('deleted'), blank=True, null=True) user_type = models.CharField(_('Member Type'), choices=UserType.choices, default=UserType.person, max_length=25) first_name = models.CharField(_('first name'), blank=True, max_length=100) last_name = models.CharField(_('last name'), blank=True, max_length=100) place = models.CharField(_('Location your at now'), blank=True, max_length=100) location = models.ForeignKey('geo.Location', blank=True, help_text=_('Location'), null=True, on_delete=models.SET_NULL) favourite_themes = models.ManyToManyField(ProjectTheme, blank=True) skills = models.ManyToManyField('tasks.Skill', blank=True) phone_number = models.CharField(_('phone number'), blank=True, max_length=50) gender = models.CharField(_('gender'), blank=True, choices=Gender.choices, max_length=6) birthdate = models.DateField(_('birthdate'), blank=True, null=True) about_me = models.TextField(_('about me'), blank=True, max_length=265) # TODO Use generate_picture_filename (or something) for upload_to picture = ImageField(_('picture'), blank=True, upload_to='profiles') is_co_financer = models.BooleanField(_('Co-financer'), default=False, help_text=_('Donations by co-financers are shown in a separate list on the ' 'project page. These donation will always be visible.')) can_pledge = models.BooleanField(_('Can pledge'), default=False, help_text=_('User can create a pledge donation.')) # Use lazy for the choices and default, so that tenant properties # will be correctly loaded primary_language = models.CharField(_('primary language'), choices=lazy(get_language_choices, tuple)(), default=lazy(get_default_language, str)(), help_text=_('Language used for website and emails.'), max_length=5) share_time_knowledge = models.BooleanField(_('share time and knowledge'), default=False) share_money = models.BooleanField(_('share money'), default=False) newsletter = models.BooleanField(_('newsletter'), default=True, help_text=_('Subscribe to newsletter.')) campaign_notifications = models.BooleanField(_('Project Notifications'), default=True) website = models.URLField(_('website'), blank=True) facebook = models.CharField(_('facebook profile'), blank=True, max_length=50) twitter = models.CharField(_('twitter profile'), blank=True, max_length=15) skypename = models.CharField(_('skype profile'), blank=True, max_length=32) partner_organization = models.ForeignKey( 'organizations.Organization', blank=True, null=True, help_text=_('Users that are connected to a partner organisation ' 'will skip the organisation step in initiative create.'), related_name='partner_organization_members', verbose_name=_('Partner organisation')) is_anonymized = models.BooleanField(_('Is anonymized'), default=False) welcome_email_is_sent = models.BooleanField(_('Welcome email is sent'), default=False) USERNAME_FIELD = 'email' slug_field = 'username' objects = BlueBottleUserManager() class Meta(object): abstract = True verbose_name = _('member') verbose_name_plural = _('members') permissions = ( ('api_read_member', 'Can view members through the API'), ('api_read_full_member', 'Can view full members through the API'), ('api_add_member', 'Can add members through the API'), ('api_change_member', 'Can change members through the API'), ('api_delete_member', 'Can delete members through the API'), ('api_read_own_member', 'Can view own members through the API'), ('api_change_own_member', 'Can change own members through the API'), ('api_delete_own_member', 'Can delete own members through the API'), ) def update_deleted_timestamp(self): """ Automatically set or unset the deleted timestamp.""" if not self.is_active and self.deleted is None: self.deleted = timezone.now() elif self.is_active and self.deleted is not None: self.deleted = None def generate_username(self): """ Generate and set a username if it hasn't already been set. """ if not self.username: username = self.email original_username = username queryset = self.__class__.objects.all() if self.pk: queryset = queryset.exclude(pk=self.pk) # Increase the number while searching for the next valid slug # depending on the given slug, clean-up next_num = 2 while queryset.filter(username=username): username = original_username end = str(next_num) username = '******'.format(username, end) next_num += 1 # Finally set the generated username. self.username = username def clean(self): self.update_deleted_timestamp() self.generate_username() def get_full_name(self): """ Returns the first_name plus the last_name, with a space in between. """ full_name = u'{0} {1}'.format(self.first_name, self.last_name) return full_name.strip() def anonymize(self): self.is_active = False self.is_anonymized = True self.email = '{}[email protected]'.format(self.pk) # disabled emails need to be unique too self.username = '******'.format(self.pk) # disabled emails need to be unique too self.remote_id = '{}[email protected]'.format(self.pk) # disabled emails need to be unique too self.set_unusable_password() self.first_name = 'Deactivated' self.last_name = 'Member' self.user_name = '' self.picture = '' self.avatar = '' self.about_me = '' self.gender = '' self.birthdate = '1000-01-01' self.location = None self.website = '' self.facebook = '' self.twitter = '' self.skypename = '' self.partner_organization = None self.save() @property def full_name(self): return self.get_full_name() def get_short_name(self): """ The user is identified by their email address. """ return self.first_name def email_user(self, subject, message, from_email=None): """ Sends an email to this User with content type HTML. """ # It's possible to send multi-part text / HTML email by following these # instructions: https://docs.djangoproject.com/en/1.5/topics/email # /#sending-alternative-content-types msg = EmailMessage(subject, message, from_email, [self.email]) msg.content_subtype = 'html' # Main content is now text/html msg.send() def get_jwt_token(self): jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER payload = jwt_payload_handler(self) token = jwt_encode_handler(payload) return token def get_login_token(self): return login_token_generator.make_token(self) @property def short_name(self): return self.get_short_name() @cached_property def is_initiator(self): return bool(self.own_initiatives.count()) @cached_property def is_supporter(self): from bluebottle.funding.states import DonationStateMachine from bluebottle.funding.models import Donation return bool(self.contribution_set.instance_of(Donation). filter(status=DonationStateMachine.succeeded.value).count()) @cached_property def is_volunteer(self): from bluebottle.assignments.models import Applicant from bluebottle.events.models import Participant from bluebottle.activities.states import ActivityStateMachine return bool(self.contribution_set.instance_of(Applicant, Participant). filter(status=ActivityStateMachine.succeeded.value).count()) @cached_property def amount_donated(self): from bluebottle.funding.states import DonationStateMachine from bluebottle.funding.models import Donation from bluebottle.funding.utils import calculate_total donations = self.contribution_set.instance_of(Donation).filter( status=DonationStateMachine.succeeded.value ) return calculate_total(donations) @cached_property def time_spent(self): from bluebottle.assignments.models import Applicant from bluebottle.events.models import Participant from bluebottle.activities.states import ActivityStateMachine contributions = self.contribution_set.instance_of(Applicant, Participant).\ filter(status=ActivityStateMachine.succeeded.value).all() return sum([c.time_spent for c in contributions]) @cached_property def subscribed(self): return self.campaign_notifications def reset_disable_token(self): # Generates a random UUID and converts it to a 32-character # hexidecimal string token = uuid.uuid4().hex self.disable_token = token self.save() def get_disable_token(self): if not self.disable_token: self.reset_disable_token() return self.disable_token def save(self, force_insert=False, force_update=False, using=None, update_fields=None): self.generate_username() super(BlueBottleBaseUser, self).save(force_insert, force_update, using, update_fields) def __getattr__(self, name): # Magically get extra fields if name.startswith('extra_'): name = name.replace('extra_', '') return self.extra.get(field__name=name).value return super(BlueBottleBaseUser, self).__getattribute__(name)
class Organization(models.Model): """ Organizations can run Projects. An organization has one or more members. """ name = models.CharField(_('name'), max_length=255) slug = models.SlugField(_('slug'), max_length=100, unique=True) description = models.TextField(_('description'), default='', blank=True) created = CreationDateTimeField(_('created')) updated = ModificationDateTimeField(_('updated')) deleted = models.DateTimeField(_('deleted'), blank=True, null=True) partner_organizations = models.TextField(_('partner organizations'), blank=True) # Address address_line1 = models.CharField(blank=True, max_length=100) address_line2 = models.CharField(blank=True, max_length=100) city = models.CharField(blank=True, max_length=100) state = models.CharField(blank=True, max_length=100) country = models.ForeignKey('geo.Country', blank=True, null=True, related_name='country') postal_code = models.CharField(blank=True, max_length=20) # Contact phone_number = models.CharField(_('phone number'), blank=True, max_length=40) website = models.URLField(_('website'), blank=True) email = models.EmailField(blank=True) tags = TaggableManager(blank=True, verbose_name=_('tags')) registration = models.FileField( blank=True, null=True, storage=FileSystemStorage(location=settings.PRIVATE_MEDIA_ROOT), upload_to='organizations/registrations') logo = ImageField(_('logo'), blank=True, help_text=_('Partner Organization Logo'), max_length=255, null=True, upload_to='partner_organization_logos/') def save(self, *args, **kwargs): if not self.slug: original_slug = slugify(self.name) slug = original_slug next_slug = 2 while not slug or self.__class__.objects.filter(slug=slug): slug = '{0}-{1}'.format(original_slug, next_slug) next_slug += 1 self.slug = slug super(Organization, self).save(*args, **kwargs) def merge(self, organizations): """ Merge `organizations` into the current organization. Makes sure that all foreign keys point to `this`. Deletes all organization models in `organization` after merging. """ for organization in organizations: for member in organization.members.all(): member.organization = self member.save() for project in organization.projects.all(): project.organization = self project.save() organization.delete() def __unicode__(self): return self.name class Meta: ordering = ['name'] verbose_name = _("partner organization") verbose_name_plural = _("partner organizations")
class Slide(PublishableModel): """ Slides for homepage """ class SlideStatus(DjangoChoices): published = ChoiceItem('published', label=_("Published")) draft = ChoiceItem('draft', label=_("Draft")) slug = models.SlugField(_("Slug")) language = models.CharField(_("language"), max_length=5, choices=lazy(get_languages, tuple)()) tab_text = models.CharField( _("Tab text"), max_length=100, help_text=_("This is shown on tabs beneath the banner.")) # Contents title = models.CharField(_("Title"), max_length=100, blank=True) body = models.TextField(_("Body text"), blank=True) image = ImageField( _("Image"), max_length=255, blank=True, null=True, upload_to='banner_slides/', validators=[ FileMimetypeValidator( allowed_mimetypes=settings.IMAGE_ALLOWED_MIME_TYPES, ), validate_file_infection ]) background_image = ImageField( _("Background image"), max_length=255, blank=True, null=True, upload_to='banner_slides/', validators=[ FileMimetypeValidator( allowed_mimetypes=settings.IMAGE_ALLOWED_MIME_TYPES, ), validate_file_infection ]) video = models.FileField( _("Video"), max_length=255, blank=True, null=True, validators=[ validate_video_file_size, FileMimetypeValidator( allowed_mimetypes=settings.VIDEO_FILE_ALLOWED_MIME_TYPES) ], help_text=_('This video will autoplay at the background. ' 'Allowed types are mp4, ogg, 3gp, avi, mov and webm. ' 'File should be smaller then 10MB.'), upload_to='banner_slides/') video_url = models.URLField(_("Video url"), max_length=100, blank=True, default='') link_text = models.CharField( _("Link text"), max_length=400, blank=True, help_text=_("This is the text on the button inside the banner.")) link_url = models.CharField( _("Link url"), max_length=400, blank=True, help_text=_("This is the link for the button inside the banner.")) style = models.CharField(_("Style"), max_length=40, help_text=_("Styling class name"), default='default', blank=True) # Metadata sequence = models.IntegerField() @property def background_image_full_path(self): return "{0}{1}".format(settings.MEDIA_URL, str(self.background_image)) def __str__(self): return self.title class Meta(object): ordering = ('language', 'sequence')
class Slide(PublishableModel): """ Slides for homepage """ class SlideStatus(DjangoChoices): published = ChoiceItem('published', label=_("Published")) draft = ChoiceItem('draft', label=_("Draft")) slug = models.SlugField(_("Slug")) language = models.CharField(_("language"), max_length=5, choices=lazy(get_languages, tuple)()) tab_text = models.CharField( _("Tab text"), max_length=100, help_text=_("This is shown on tabs beneath the banner.")) # Contents title = models.CharField(_("Title"), max_length=100, blank=True) body = models.TextField(_("Body text"), blank=True) image = ImageField(_("Image"), max_length=255, blank=True, null=True, upload_to='banner_slides/') background_image = ImageField(_("Background image"), max_length=255, blank=True, null=True, upload_to='banner_slides/') video_url = models.URLField(_("Video url"), max_length=100, blank=True, default='') link_text = models.CharField( _("Link text"), max_length=400, help_text=_("This is the text on the button inside the banner."), blank=True) link_url = models.CharField( _("Link url"), max_length=400, help_text=_("This is the link for the button inside the banner."), blank=True) style = models.CharField(_("Style"), max_length=40, help_text=_("Styling class name"), default='default', blank=True) # Metadata sequence = models.IntegerField() @property def background_image_full_path(self): return "{0}{1}".format(settings.MEDIA_URL, str(self.background_image)) def __unicode__(self): return self.title class Meta: ordering = ('language', 'sequence')