class SchemalessFieldMixin(models.Model):
    custom_data = HStoreField(null=True, blank=True)

    class Meta:
        abstract = True
示例#2
0
class User(AbstractBaseUser, PermissionsMixin):
    ACTIVATION_NONE = 0
    ACTIVATION_USER = 1
    ACTIVATION_ADMIN = 2

    SUBSCRIPTION_NONE = 0
    SUBSCRIPTION_NOTIFY = 1
    SUBSCRIPTION_ALL = 2

    SUBSCRIPTION_CHOICES = [
        (SUBSCRIPTION_NONE, _("No")),
        (SUBSCRIPTION_NOTIFY, _("Notify")),
        (SUBSCRIPTION_ALL, _("Notify with e-mail")),
    ]

    LIMIT_INVITES_TO_NONE = 0
    LIMIT_INVITES_TO_FOLLOWED = 1
    LIMIT_INVITES_TO_NOBODY = 2

    LIMIT_INVITES_TO_CHOICES = [
        (LIMIT_INVITES_TO_NONE, _("Everybody")),
        (LIMIT_INVITES_TO_FOLLOWED, _("Users I follow")),
        (LIMIT_INVITES_TO_NOBODY, _("Nobody")),
    ]

    #This is my custom user logging feature:
    activity_array = ArrayField(
        ArrayField(
            models.DateTimeField(null=True, blank=True),
            size=2,
            null=True,
        ),
        null=True,
    )

    # Note that "username" field is purely for shows.
    # When searching users by their names, always use lowercased string
    # and slug field instead that is normalized around DB engines
    # differences in case handling.
    username = models.CharField(max_length=30)
    slug = models.CharField(max_length=30, unique=True)

    # Misago stores user email in two fields:
    # "email" holds normalized email address
    # "email_hash" is lowercase hash of email address used to identify account
    # as well as enforcing on database level that no more than one user can be
    # using one email address
    email = models.EmailField(max_length=255, db_index=True)
    email_hash = models.CharField(max_length=32, unique=True)

    joined_on = models.DateTimeField(_("joined on"),
                                     default=timezone.now,
                                     db_index=True)
    joined_from_ip = models.GenericIPAddressField(null=True, blank=True)
    is_hiding_presence = models.BooleanField(default=False)

    rank = models.ForeignKey("Rank",
                             null=True,
                             blank=True,
                             on_delete=models.deletion.PROTECT)
    title = models.CharField(max_length=255, null=True, blank=True)
    requires_activation = models.PositiveIntegerField(default=ACTIVATION_NONE)

    is_staff = models.BooleanField(
        _("staff status"),
        default=False,
        help_text=_("Designates whether the user can log into admin sites."),
    )

    roles = models.ManyToManyField("misago_acl.Role")
    acl_key = models.CharField(max_length=12, null=True, blank=True)

    is_active = models.BooleanField(
        _("active"),
        db_index=True,
        default=True,
        help_text=_(
            "Designates whether this user should be treated as active. "
            "Unselect this instead of deleting accounts."),
    )
    is_active_staff_message = models.TextField(null=True, blank=True)

    is_deleting_account = models.BooleanField(default=False)

    avatar_tmp = models.ImageField(max_length=255,
                                   upload_to=avatars_store.upload_to,
                                   null=True,
                                   blank=True)
    avatar_src = models.ImageField(max_length=255,
                                   upload_to=avatars_store.upload_to,
                                   null=True,
                                   blank=True)
    avatar_crop = models.CharField(max_length=255, null=True, blank=True)
    avatars = JSONField(null=True, blank=True)
    is_avatar_locked = models.BooleanField(default=False)
    avatar_lock_user_message = models.TextField(null=True, blank=True)
    avatar_lock_staff_message = models.TextField(null=True, blank=True)

    signature = models.TextField(null=True, blank=True)
    signature_parsed = models.TextField(null=True, blank=True)
    signature_checksum = models.CharField(max_length=64, null=True, blank=True)
    is_signature_locked = models.BooleanField(default=False)
    signature_lock_user_message = models.TextField(null=True, blank=True)
    signature_lock_staff_message = models.TextField(null=True, blank=True)

    followers = models.PositiveIntegerField(default=0)
    following = models.PositiveIntegerField(default=0)

    follows = models.ManyToManyField("self",
                                     related_name="followed_by",
                                     symmetrical=False)
    blocks = models.ManyToManyField("self",
                                    related_name="blocked_by",
                                    symmetrical=False)

    limits_private_thread_invites_to = models.PositiveIntegerField(
        default=LIMIT_INVITES_TO_NONE, choices=LIMIT_INVITES_TO_CHOICES)
    unread_private_threads = models.PositiveIntegerField(default=0)
    sync_unread_private_threads = models.BooleanField(default=False)

    subscribe_to_started_threads = models.PositiveIntegerField(
        default=SUBSCRIPTION_NONE, choices=SUBSCRIPTION_CHOICES)
    subscribe_to_replied_threads = models.PositiveIntegerField(
        default=SUBSCRIPTION_NONE, choices=SUBSCRIPTION_CHOICES)

    threads = models.PositiveIntegerField(default=0)
    posts = models.PositiveIntegerField(default=0, db_index=True)

    last_posted_on = models.DateTimeField(null=True, blank=True)

    profile_fields = HStoreField(default=dict)
    agreements = ArrayField(models.PositiveIntegerField(), default=list)

    sso_id = models.PositiveIntegerField(null=True, blank=True, unique=True)

    USERNAME_FIELD = "slug"
    REQUIRED_FIELDS = ["email"]

    objects = UserManager()

    class Meta:
        indexes = [
            models.Index(
                name="misago_user_is_staff_part",
                fields=["is_staff"],
                condition=Q(is_staff=True),
            ),
            models.Index(
                name="misago_user_requires_acti_part",
                fields=["requires_activation"],
                condition=Q(requires_activation__gt=0),
            ),
            models.Index(
                name="misago_user_is_deleting_a_part",
                fields=["is_deleting_account"],
                condition=Q(is_deleting_account=True),
            ),
        ]

    def clean(self):
        self.username = self.normalize_username(self.username)
        self.email = UserManager.normalize_email(self.email)

    def lock(self):
        """locks user in DB, shortcut for locking user model in views"""
        return User.objects.select_for_update().get(pk=self.pk)

    def delete(self, *args, **kwargs):
        if kwargs.pop("delete_content", False):
            self.delete_content()

        username = kwargs.pop("anonymous_username", None)
        if username:
            self.anonymize_data(username)
        else:
            raise ValueError(
                "user.delete() requires 'anonymous_username' argument")

        delete_avatar(self)

        return super().delete(*args, **kwargs)

    def delete_content(self):
        from ..signals import delete_user_content

        delete_user_content.send(sender=self)

    def mark_for_delete(self):
        self.is_active = False
        self.is_deleting_account = True
        self.save(update_fields=["is_active", "is_deleting_account"])

    def anonymize_data(self, anonymous_username):
        """Replaces username with anonymized one, then send anonymization signal.

        Items associated with this user then anonymize their user-specific data
        like username or IP addresses.
        """
        self.username = anonymous_username
        self.slug = slugify(self.username)

        from ..signals import anonymize_user_data

        anonymize_user_data.send(sender=self)

    @property
    def requires_activation_by_admin(self):
        return self.requires_activation == self.ACTIVATION_ADMIN

    @property
    def requires_activation_by_user(self):
        return self.requires_activation == self.ACTIVATION_USER

    @property
    def can_be_messaged_by_everyone(self):
        preference = self.limits_private_thread_invites_to
        return preference == self.LIMIT_INVITES_TO_NONE

    @property
    def can_be_messaged_by_followed(self):
        preference = self.limits_private_thread_invites_to
        return preference == self.LIMIT_INVITES_TO_FOLLOWED

    @property
    def can_be_messaged_by_nobody(self):
        preference = self.limits_private_thread_invites_to
        return preference == self.LIMIT_INVITES_TO_NOBODY

    @property
    def has_valid_signature(self):
        return is_user_signature_valid(self)

    def get_absolute_url(self):
        return reverse("misago:user",
                       kwargs={
                           "slug": self.slug,
                           "pk": self.pk
                       })

    def get_username(self):
        """dirty hack: return real username instead of normalized slug"""
        return self.username

    def get_full_name(self):
        return self.username

    def get_short_name(self):
        return self.username

    def get_real_name(self):
        return self.profile_fields.get("real_name")

    def set_username(self, new_username, changed_by=None):
        new_username = self.normalize_username(new_username)
        if new_username != self.username:
            old_username = self.username
            self.username = new_username
            self.slug = slugify(new_username)

            if self.pk:
                changed_by = changed_by or self
                namechange = self.record_name_change(changed_by, new_username,
                                                     old_username)

                from ..signals import username_changed

                username_changed.send(sender=self)

                return namechange

    def record_name_change(self, changed_by, new_username, old_username):
        return self.namechanges.create(
            new_username=new_username,
            old_username=old_username,
            changed_by=changed_by,
            changed_by_username=changed_by.username,
        )

    def set_email(self, new_email):
        self.email = UserManager.normalize_email(new_email)
        self.email_hash = hash_email(new_email)

    def get_any_title(self):
        return self.title or self.rank.title or self.rank.name

    def get_roles(self):
        roles_pks = []
        roles_dict = {}

        for role in self.roles.all():
            roles_pks.append(role.pk)
            role.origin = self
            roles_dict[role.pk] = role

        if self.rank:
            for role in self.rank.roles.all():
                if role.pk not in roles_pks:
                    role.origin = self.rank
                    roles_pks.append(role.pk)
                    roles_dict[role.pk] = role

        return [roles_dict[r] for r in sorted(roles_pks)]

    def update_acl_key(self):
        roles_pks = []
        for role in self.get_roles():
            if role.origin == "self":
                roles_pks.append("u%s" % role.pk)
            else:
                roles_pks.append("%s:%s" % (self.rank.pk, role.pk))

        self.acl_key = md5(",".join(roles_pks).encode()).hexdigest()[:12]

    def email_user(self, subject, message, from_email=None, **kwargs):
        """sends an email to this user (for compat with Django)"""
        send_mail(subject, message, from_email, [self.email], **kwargs)

    def is_following(self, user_or_id):
        try:
            user_id = user_or_id.id
        except AttributeError:
            user_id = user_or_id

        try:
            self.follows.get(id=user_id)
            return True
        except User.DoesNotExist:
            return False

    def is_blocking(self, user_or_id):
        try:
            user_id = user_or_id.id
        except AttributeError:
            user_id = user_or_id

        try:
            self.blocks.get(id=user_id)
            return True
        except User.DoesNotExist:
            return False
示例#3
0
class Product(models.Model, ItemRange, index.Indexed):
    product_class = models.ForeignKey(ProductClass,
                                      related_name='products',
                                      verbose_name=pgettext_lazy(
                                          'Product field', 'product class'))
    product_tax = models.ForeignKey(ProductTax,
                                    related_name='producttax',
                                    blank=True,
                                    null=True,
                                    verbose_name=pgettext_lazy(
                                        'Product field', 'product class'))
    name = models.CharField(pgettext_lazy('Product field', 'name'),
                            unique=True,
                            max_length=128)
    description = models.TextField(verbose_name=pgettext_lazy(
        'Product field', 'description'),
                                   blank=True,
                                   null=True)
    categories = models.ManyToManyField(Category,
                                        verbose_name=pgettext_lazy(
                                            'Product field', 'categories'),
                                        related_name='products')
    price = PriceField(pgettext_lazy('Product field', 'price'),
                       currency=settings.DEFAULT_CURRENCY,
                       max_digits=12,
                       validators=[MinValueValidator(0)],
                       default=Decimal(0),
                       decimal_places=2)
    wholesale_price = PriceField(pgettext_lazy('Product field',
                                               'Wholesale price'),
                                 currency=settings.DEFAULT_CURRENCY,
                                 blank=True,
                                 null=True,
                                 max_digits=12,
                                 decimal_places=2)
    product_supplier = models.ForeignKey(Supplier,
                                         related_name='suppliers',
                                         blank=True,
                                         null=True,
                                         verbose_name=pgettext_lazy(
                                             'Product field',
                                             'product supplier'))

    available_on = models.DateField(pgettext_lazy('Product field',
                                                  'available on'),
                                    blank=True,
                                    null=True)
    attributes = HStoreField(pgettext_lazy('Product field', 'attributes'),
                             default={})
    updated_at = models.DateTimeField(pgettext_lazy('Product field',
                                                    'updated at'),
                                      auto_now=True,
                                      null=True)
    is_featured = models.BooleanField(pgettext_lazy('Product field',
                                                    'is featured'),
                                      default=False)
    low_stock_threshold = models.IntegerField(
        pgettext_lazy('Product field', 'low stock threshold'),
        validators=[MinValueValidator(0)],
        null=True,
        blank=True,
        default=Decimal(10))

    objects = ProductManager()

    search_fields = [
        index.SearchField('name', partial_match=True),
        index.SearchField('description'),
        index.FilterField('available_on')
    ]

    class Meta:
        app_label = 'product'
        verbose_name = pgettext_lazy('Product model', 'product')
        verbose_name_plural = pgettext_lazy('Product model', 'products')

    def __iter__(self):
        if not hasattr(self, '__variants'):
            setattr(self, '__variants', self.variants.all())
        return iter(getattr(self, '__variants'))

    def __repr__(self):
        class_ = type(self)
        return '<%s.%s(pk=%r, name=%r)>' % (class_.__module__, class_.__name__,
                                            self.pk, self.name)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('product:details',
                       kwargs={
                           'slug': self.get_slug(),
                           'product_id': self.id
                       })

    def get_slug(self):
        return slugify(smart_text(unidecode(self.name)))

    def get_product_tax(self):
        return self.product_tax

    def get_tax_value(self):
        return self.product_tax.get_tax()

    def is_in_stock(self):
        return any(variant.is_in_stock() for variant in self)

    def total_stock(self):
        return Sum(self.variant.stock.stock_available())

    def total_variants(self):
        return len(self.variants.all())

    def get_first_category(self):
        for category in self.categories.all():
            if not category.hidden:
                return category
        return None

    def get_variants_count(self):
        variants = self.variants.filter(product=self.pk)
        total = 0
        for stock in variants:
            total += stock.get_stock_quantity()
        return total

    def is_available(self):
        today = datetime.date.today()
        return self.available_on is None or self.available_on <= today

    def get_first_image(self):
        first_image = self.images.first()

        if first_image:
            return first_image.image
        return None

    def get_attribute(self, pk):
        return self.attributes.get(smart_text(pk))

    def set_attribute(self, pk, value_pk):
        self.attributes[smart_text(pk)] = smart_text(value_pk)

    def get_price_range(self, discounts=None, **kwargs):
        if not self.variants.exists():
            price = calculate_discounted_price(self, self.price, discounts,
                                               **kwargs)
            return PriceRange(price, price)
        else:
            return super(Product, self).get_price_range(discounts=discounts,
                                                        **kwargs)
示例#4
0
文件: models.py 项目: camerondiou/BMO
class Product(SeoModel):
    product_type = models.ForeignKey(ProductType,
                                     related_name='products',
                                     on_delete=models.CASCADE)
    name = models.CharField(max_length=128)
    description = models.TextField()
    category = models.ForeignKey(Category,
                                 related_name='products',
                                 on_delete=models.CASCADE)
    price = MoneyField(currency=settings.DEFAULT_CURRENCY,
                       max_digits=12,
                       decimal_places=settings.DEFAULT_DECIMAL_PLACES)
    available_on = models.DateField(blank=True, null=True)
    is_published = models.BooleanField(default=True)
    attributes = HStoreField(default={}, blank=True)
    updated_at = models.DateTimeField(auto_now=True, null=True)
    is_featured = models.BooleanField(default=False)
    charge_taxes = models.BooleanField(default=True)
    tax_rate = models.CharField(max_length=128,
                                default=DEFAULT_TAX_RATE_NAME,
                                blank=True)

    objects = ProductQuerySet.as_manager()

    class Meta:
        app_label = 'product'
        permissions = (('view_product',
                        pgettext_lazy('Permission description',
                                      'Can view products')),
                       ('edit_product',
                        pgettext_lazy('Permission description',
                                      'Can edit products')),
                       ('view_properties',
                        pgettext_lazy('Permission description',
                                      'Can view product properties')),
                       ('edit_properties',
                        pgettext_lazy('Permission description',
                                      'Can edit product properties')))

    def __iter__(self):
        if not hasattr(self, '__variants'):
            setattr(self, '__variants', self.variants.all())
        return iter(getattr(self, '__variants'))

    def __repr__(self):
        class_ = type(self)
        return '<%s.%s(pk=%r, name=%r)>' % (class_.__module__, class_.__name__,
                                            self.pk, self.name)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('product:details',
                       kwargs={
                           'slug': self.get_slug(),
                           'product_id': self.id
                       })

    def get_slug(self):
        return slugify(smart_text(unidecode(self.name)))

    def is_in_stock(self):
        return any(variant.is_in_stock() for variant in self)

    def is_available(self):
        today = datetime.date.today()
        return self.available_on is None or self.available_on <= today

    def get_first_image(self):
        first_image = self.images.first()
        return first_image.image if first_image else None

    def get_price_range(self, discounts=None, taxes=None):
        if self.variants.exists():
            prices = [
                variant.get_price(discounts=discounts, taxes=taxes)
                for variant in self
            ]
            return TaxedMoneyRange(min(prices), max(prices))
        price = calculate_discounted_price(self, self.price, discounts)
        if not self.charge_taxes:
            taxes = None
        tax_rate = self.tax_rate or self.product_type.tax_rate
        price = apply_tax_to_price(taxes, tax_rate, price)
        return TaxedMoneyRange(start=price, stop=price)
示例#5
0
文件: user.py 项目: yuan6785/Misago
class User(AbstractBaseUser, PermissionsMixin):
    ACTIVATION_NONE = 0
    ACTIVATION_USER = 1
    ACTIVATION_ADMIN = 2

    SUBSCRIBE_NONE = 0
    SUBSCRIBE_NOTIFY = 1
    SUBSCRIBE_ALL = 2

    SUBSCRIBE_CHOICES = [
        (SUBSCRIBE_NONE, _("No")),
        (SUBSCRIBE_NOTIFY, _("Notify")),
        (SUBSCRIBE_ALL, _("Notify with e-mail")),
    ]

    LIMIT_INVITES_TO_NONE = 0
    LIMIT_INVITES_TO_FOLLOWED = 1
    LIMIT_INVITES_TO_NOBODY = 2

    LIMIT_INVITES_TO_CHOICES = [
        (LIMIT_INVITES_TO_NONE, _("Everybody")),
        (LIMIT_INVITES_TO_FOLLOWED, _("Users I follow")),
        (LIMIT_INVITES_TO_NOBODY, _("Nobody")),
    ]
    # Note that "username" field is purely for shows.
    # When searching users by their names, always use lowercased string
    # and slug field instead that is normalized around DB engines
    # differences in case handling.
    username = models.CharField(max_length=30)
    slug = models.CharField(max_length=30, unique=True)

    # Misago stores user email in two fields:
    # "email" holds normalized email address
    # "email_hash" is lowercase hash of email address used to identify account
    # as well as enforcing on database level that no more than one user can be
    # using one email address
    email = models.EmailField(max_length=255, db_index=True)
    email_hash = models.CharField(max_length=32, unique=True)

    joined_on = models.DateTimeField(_('joined on'), default=timezone.now)
    joined_from_ip = models.GenericIPAddressField()
    last_ip = models.GenericIPAddressField(null=True, blank=True)
    is_hiding_presence = models.BooleanField(default=False)

    rank = models.ForeignKey(
        'Rank',
        null=True,
        blank=True,
        on_delete=models.deletion.PROTECT,
    )
    title = models.CharField(max_length=255, null=True, blank=True)
    requires_activation = models.PositiveIntegerField(default=ACTIVATION_NONE)

    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_('Designates whether the user can log into admin sites.'),
    )

    roles = models.ManyToManyField('misago_acl.Role')
    acl_key = models.CharField(max_length=12, null=True, blank=True)

    is_active = models.BooleanField(
        _('active'),
        db_index=True,
        default=True,
        help_text=_(
            "Designates whether this user should be treated as active. "
            "Unselect this instead of deleting accounts."),
    )
    is_active_staff_message = models.TextField(null=True, blank=True)

    avatar_tmp = models.ImageField(
        max_length=255,
        upload_to=avatars.store.upload_to,
        null=True,
        blank=True,
    )
    avatar_src = models.ImageField(
        max_length=255,
        upload_to=avatars.store.upload_to,
        null=True,
        blank=True,
    )
    avatar_crop = models.CharField(max_length=255, null=True, blank=True)
    avatars = JSONField(null=True, blank=True)
    is_avatar_locked = models.BooleanField(default=False)
    avatar_lock_user_message = models.TextField(null=True, blank=True)
    avatar_lock_staff_message = models.TextField(null=True, blank=True)

    signature = models.TextField(null=True, blank=True)
    signature_parsed = models.TextField(null=True, blank=True)
    signature_checksum = models.CharField(max_length=64, null=True, blank=True)
    is_signature_locked = models.BooleanField(default=False)
    signature_lock_user_message = models.TextField(null=True, blank=True)
    signature_lock_staff_message = models.TextField(null=True, blank=True)

    followers = models.PositiveIntegerField(default=0)
    following = models.PositiveIntegerField(default=0)

    follows = models.ManyToManyField(
        'self',
        related_name='followed_by',
        symmetrical=False,
    )
    blocks = models.ManyToManyField(
        'self',
        related_name='blocked_by',
        symmetrical=False,
    )

    limits_private_thread_invites_to = models.PositiveIntegerField(
        default=LIMIT_INVITES_TO_NONE,
        choices=LIMIT_INVITES_TO_CHOICES,
    )
    unread_private_threads = models.PositiveIntegerField(default=0)
    sync_unread_private_threads = models.BooleanField(default=False)

    subscribe_to_started_threads = models.PositiveIntegerField(
        default=SUBSCRIBE_NONE,
        choices=SUBSCRIBE_CHOICES,
    )
    subscribe_to_replied_threads = models.PositiveIntegerField(
        default=SUBSCRIBE_NONE,
        choices=SUBSCRIBE_CHOICES,
    )

    threads = models.PositiveIntegerField(default=0)
    posts = models.PositiveIntegerField(default=0, db_index=True)

    last_posted_on = models.DateTimeField(null=True, blank=True)

    profile_fields = HStoreField(default=dict)

    USERNAME_FIELD = 'slug'
    REQUIRED_FIELDS = ['email']

    objects = UserManager()

    class Meta:
        indexes = [
            PgPartialIndex(
                fields=['is_staff'],
                where={'is_staff': True},
            ),
            PgPartialIndex(
                fields=['requires_activation'],
                where={'requires_activation__gt': 0},
            ),
        ]

    def clean(self):
        self.username = self.normalize_username(self.username)
        self.email = UserManager.normalize_email(self.email)

    def lock(self):
        """locks user in DB, shortcut for locking user model in views"""
        return User.objects.select_for_update().get(pk=self.pk)

    def delete(self, *args, **kwargs):
        if kwargs.pop('delete_content', False):
            self.delete_content()

        avatars.delete_avatar(self)

        return super(User, self).delete(*args, **kwargs)

    def delete_content(self):
        from misago.users.signals import delete_user_content
        delete_user_content.send(sender=self)

    @property
    def acl_cache(self):
        try:
            return self._acl_cache
        except AttributeError:
            self._acl_cache = get_user_acl(self)
            return self._acl_cache

    @acl_cache.setter
    def acl_cache(self, value):
        raise TypeError("acl_cache can't be assigned")

    @property
    def acl_(self):
        raise NotImplementedError('user.acl_ property was renamed to user.acl')

    @property
    def requires_activation_by_admin(self):
        return self.requires_activation == self.ACTIVATION_ADMIN

    @property
    def requires_activation_by_user(self):
        return self.requires_activation == self.ACTIVATION_USER

    @property
    def can_be_messaged_by_everyone(self):
        preference = self.limits_private_thread_invites_to
        return preference == self.LIMIT_INVITES_TO_NONE

    @property
    def can_be_messaged_by_followed(self):
        preference = self.limits_private_thread_invites_to
        return preference == self.LIMIT_INVITES_TO_FOLLOWED

    @property
    def can_be_messaged_by_nobody(self):
        preference = self.limits_private_thread_invites_to
        return preference == self.LIMIT_INVITES_TO_NOBODY

    @property
    def has_valid_signature(self):
        return is_user_signature_valid(self)

    def get_absolute_url(self):
        return reverse('misago:user',
                       kwargs={
                           'slug': self.slug,
                           'pk': self.pk,
                       })

    def get_username(self):
        """dirty hack: return real username instead of normalized slug"""
        return self.username

    def get_full_name(self):
        return self.username

    def get_short_name(self):
        return self.username

    def set_username(self, new_username, changed_by=None):
        new_username = self.normalize_username(new_username)
        if new_username != self.username:
            old_username = self.username
            self.username = new_username
            self.slug = slugify(new_username)

            if self.pk:
                changed_by = changed_by or self
                self.record_name_change(changed_by, new_username, old_username)

                from misago.users.signals import username_changed
                username_changed.send(sender=self)

    def record_name_change(self, changed_by, new_username, old_username):
        self.namechanges.create(
            new_username=new_username,
            old_username=old_username,
            changed_by=changed_by,
            changed_by_username=changed_by.username,
        )

    def set_email(self, new_email):
        self.email = UserManager.normalize_email(new_email)
        self.email_hash = hash_email(new_email)

    def get_any_title(self):
        return self.title or self.rank.title or self.rank.name

    def get_roles(self):
        roles_pks = []
        roles_dict = {}

        for role in self.roles.all():
            roles_pks.append(role.pk)
            role.origin = self
            roles_dict[role.pk] = role

        if self.rank:
            for role in self.rank.roles.all():
                if role.pk not in roles_pks:
                    role.origin = self.rank
                    roles_pks.append(role.pk)
                    roles_dict[role.pk] = role

        return [roles_dict[r] for r in sorted(roles_pks)]

    def update_acl_key(self):
        roles_pks = []
        for role in self.get_roles():
            if role.origin == 'self':
                roles_pks.append('u%s' % role.pk)
            else:
                roles_pks.append('%s:%s' % (self.rank.pk, role.pk))

        self.acl_key = md5(','.join(roles_pks).encode()).hexdigest()[:12]

    def email_user(self, subject, message, from_email=None, **kwargs):
        """sends an email to this user (for compat with Django)"""
        send_mail(subject, message, from_email, [self.email], **kwargs)

    def is_following(self, user):
        try:
            self.follows.get(pk=user.pk)
            return True
        except User.DoesNotExist:
            return False

    def is_blocking(self, user):
        try:
            self.blocks.get(pk=user.pk)
            return True
        except User.DoesNotExist:
            return False
示例#6
0
        class Model(models.Model):
            json = JSONField()
            hstore = HStoreField()

            class Meta:
                app_label = "django_tables2_test"
示例#7
0
class SendGridMail(Model):
    """用SendGrid寄出的信件紀錄
    * case: 案件
    * template: 信件樣板
    * from_email: 寄送者
    * to_email: 收件者
    * data: SendGrid Transactional Templates所使用的json資料,使用Postgres的HStoreField儲存,
            詳見https://docs.djangoproject.com/en/2.1/ref/contrib/postgres/fields/#hstorefield
    * success: API請求狀態,若status_code回傳202則紀錄為成功
    * send_time: 發送時間
    """
    case = ForeignKey('cases.Case',
                      on_delete=CASCADE,
                      related_name='sendgrid_mails',
                      verbose_name=_('Case'))
    template = ForeignKey('mails.SendGridMailTemplate',
                          on_delete=CASCADE,
                          related_name='mails',
                          verbose_name=_('SendGrid Template'))
    from_email = EmailField(verbose_name=_('From Email'))
    to_email = EmailField(verbose_name=_('To Email'))
    data = HStoreField(verbose_name=_('Mail Data'))
    success = BooleanField(default=False, verbose_name=_('Request Success'))
    send_time = DateTimeField(auto_now=True,
                              null=True,
                              blank=True,
                              verbose_name=_('Send Time'))

    class Meta:
        verbose_name = _('SendGrid Mail')
        verbose_name_plural = _('SendGrid Mails')
        ordering = ('-send_time', )

    def __str__(self):
        return self.to_email

    def save(self, *args, **kwargs):
        if not self.pk:
            self.from_email = self.from_email or settings.SERVER_EMAIL
            self.to_email = self.to_email or self.case.email
        if self.to_email:
            try:
                response = SendGridMail.send_template(self.from_email,
                                                      self.to_email, self.data,
                                                      self.template.tid)
                self.success = bool(response and response.status_code == 202)
            except SendGridMailTemplate.DoesNotExist as e:
                sendgrid_system_mail(e)
            super(SendGridMail, self).save(*args, **kwargs)

    def send(self):
        self.save()

    @staticmethod
    def send_template(from_email, to_email, data, template_id):
        """Call Sendgrid Transactional Template API"""
        if from_email == settings.SERVER_EMAIL:
            from_email = Email(from_email, name=settings.SERVER_EMAIL_NAME)
        else:
            from_email = Email(from_email)

        mail = Mail(from_email=from_email, to_email=Email(to_email))
        mail.personalizations[0].dynamic_template_data = json.loads(
            json.dumps(data, cls=DjangoJSONEncoder))
        mail.template_id = template_id
        try:
            return sg.client.mail.send.post(request_body=mail.get())
        except HTTPError as e:
            sendgrid_system_mail(e)
            return None
示例#8
0
class Product(SeoModel, PublishableModel):
    product_type = models.ForeignKey(ProductType,
                                     related_name="products",
                                     on_delete=models.CASCADE)
    name = models.CharField(max_length=128)
    description = models.TextField(blank=True)
    description_json = JSONField(blank=True, default=dict)
    category = models.ForeignKey(Category,
                                 related_name="products",
                                 on_delete=models.CASCADE)
    price = MoneyField(
        currency=settings.DEFAULT_CURRENCY,
        max_digits=settings.DEFAULT_MAX_DIGITS,
        decimal_places=settings.DEFAULT_DECIMAL_PLACES,
    )
    attributes = HStoreField(default=dict, blank=True)
    updated_at = models.DateTimeField(auto_now=True, null=True)
    charge_taxes = models.BooleanField(default=True)
    tax_rate = models.CharField(max_length=128,
                                blank=True,
                                choices=TaxRateType.CHOICES)
    weight = MeasurementField(measurement=Weight,
                              unit_choices=WeightUnits.CHOICES,
                              blank=True,
                              null=True)

    objects = ProductsQueryset.as_manager()
    translated = TranslationProxy()

    class Meta:
        app_label = "product"
        ordering = ("name", )
        permissions = ((
            "manage_products",
            pgettext_lazy("Permission description", "Manage products."),
        ), )

    def __iter__(self):
        if not hasattr(self, "__variants"):
            setattr(self, "__variants", self.variants.all())
        return iter(getattr(self, "__variants"))

    def __repr__(self):
        class_ = type(self)
        return "<%s.%s(pk=%r, name=%r)>" % (
            class_.__module__,
            class_.__name__,
            self.pk,
            self.name,
        )

    def __str__(self):
        return self.name

    @property
    def is_available(self):
        return self.is_visible and self.is_in_stock()

    def get_absolute_url(self):
        return reverse("product:details",
                       kwargs={
                           "slug": self.get_slug(),
                           "product_id": self.id
                       })

    def get_slug(self):
        return slugify(smart_text(unidecode(self.name)))

    def is_in_stock(self):
        return any(variant.is_in_stock() for variant in self)

    def get_first_image(self):
        images = list(self.images.all())
        return images[0] if images else None

    def get_price_range(self,
                        discounts: Iterable[DiscountInfo] = None,
                        taxes=None):
        if self.variants.all():
            prices = [
                variant.get_price(discounts=discounts, taxes=taxes)
                for variant in self
            ]
            return TaxedMoneyRange(min(prices), max(prices))
        price = calculate_discounted_price(self, self.price, discounts)
        if not self.charge_taxes:
            taxes = None
        tax_rate = self.tax_rate or self.product_type.tax_rate
        price = apply_tax_to_price(taxes, tax_rate, price)
        return TaxedMoneyRange(start=price, stop=price)
示例#9
0
class AhomeJobTemplate(CreatedUpdatedModel):
    """
    Template for all ahome Job related modules
    """
    class Meta:
        abstract = True

    name         = models.CharField(max_length=100, blank=True)
    label        = models.CharField(max_length=200, blank=True)
    description  = models.CharField(max_length=200, blank=True, null=True)
    action       = models.CharField(max_length=200, blank=True, choices=ACTION_CHOICES, default='start')
    ahomefile    = JSONField(blank=True, default=dict, editable=True, null=True)
    project      = models.ForeignKey(Project, related_name='%(class)ss', on_delete=models.DO_NOTHING, blank=True, null=True)
    #organization = models.ForeignKey(ORGANISATION_MODEL, related_name='%(class)ss', on_delete=models.PROTECT, blank=True, null=True)
    #infrastructure= models.ForeignKey(INFRASTRUCTURE_MODEL, related_name='%(class)ss', on_delete=models.PROTECT, blank=True, null=True)
    iaas         = models.ForeignKey(INFRASTRUCTURE_MODEL, related_name='%(class)ss', on_delete=models.PROTECT, blank=True, null=True)
    target       = models.CharField(max_length=200, blank=True)
    kind         = models.CharField(max_length=200, default='generic')
    hosted       = models.CharField(max_length=200, blank=True)
    opts         = JSONField(blank=True, default=dict, editable=True, null=True)
    status       = models.CharField(max_length=200, blank=True, choices=STATUS_CHOICES, default='running')
    output       = models.CharField(max_length=200, blank=True)
    ident        = models.CharField(max_length=200, blank=True)
    uuid         = models.UUIDField(default=uuid.uuid4, editable=False)
    cloud        = models.BooleanField(verbose_name=_("cloud based"), default=False)
    unique_keys  = HStoreField(blank=True, default=dict, null=True,
                              verbose_name=_("unique keys"), help_text=_("Unique key(s) for ansible callback"))
    source       = JSONField(blank=True, default=dict, editable=True, null=True)
    # todo Encript this field
    credentials  = JSONField(blank=True, default=dict, editable=True, null=True)
    definition   = JSONField(blank=True, default=dict, editable=True, null=True)
    facts        = JSONField(blank=True, default=dict, editable=True, null=True)
    setfacts     = JSONField(blank=True, default=dict, editable=True, null=True)
    inputs       = JSONField(blank=True, default=dict, editable=True, null=True)
    applications = ArrayField(models.CharField(max_length=200), blank=True, default=list)
    schema       = JSONField(blank=True, default=dict, editable=True, null=True)
    runner       = JSONField(blank=True, default=dict, editable=True, null=True)
    tags         = models.ManyToManyField('Tag', verbose_name=_("tags"), blank=True, help_text=_("Select tag(s)"))
    # tags = ArrayField(models.CharField(max_length=200), blank=True)

    def save(self, *args, **kwargs):
        if self.kind:
            if self.kind in CLOUD_LISTS:
                self.cloud = True
            if not self.schema:
                self.schema = DEFAULT_CREDENTIAL_SCHEMA
        if not self.unique_keys:
            self.unique_keys = dict(uuid=self.uuid)

        return super().save(*args, **kwargs)

    def live_time(self, since=None):
        from sysutils.utils.timeutils import sting_to_date, date_time_now, display_time
        now = date_time_now()
        seconds = (now - self.created).total_seconds()
        hours = round(seconds / (60 * 60), 2)

        return {
            'seconds': seconds,
            'hours': hours,
            'human': display_time(seconds)
            }

    # def pre_create(self, user, *args, **kwargs):
    #     try:
    #        # self.owner = user
    #       form_data = kwargs.get('form_data')
    #       _logger.debug("PRE_CREATE - FORM DATA \n{}".format(pprint.pformat(form_data, indent=4)))
    #     except:
    #         pass
    #     pass
示例#10
0
class Unit(models.Model):
    id = models.IntegerField(primary_key=True)

    public = models.BooleanField(null=False, default=True)

    location = models.PointField(null=True, srid=PROJECTION_SRID)  # lat, lng?
    geometry = models.GeometryField(srid=PROJECTION_SRID, null=True)
    department = models.ForeignKey(Department, null=True)
    root_department = models.ForeignKey(Department, null=True, related_name='descendant_units')

    organizer_type = models.PositiveSmallIntegerField(choices=ORGANIZER_TYPES, null=True)
    organizer_name = models.CharField(max_length=150, null=True)
    organizer_business_id = models.CharField(max_length=10, null=True)

    provider_type = models.PositiveSmallIntegerField(choices=PROVIDER_TYPES, null=True)
    contract_type = models.PositiveSmallIntegerField(choices=CONTRACT_TYPES, null=True)

    picture_url = models.URLField(max_length=250, null=True)
    picture_entrance_url = models.URLField(max_length=500, null=True)
    streetview_entrance_url = models.URLField(max_length=500, null=True)

    description = models.TextField(null=True)
    short_description = models.TextField(null=True)
    name = models.CharField(max_length=200, db_index=True)
    street_address = models.CharField(max_length=100, null=True)

    www = models.URLField(max_length=400, null=True)
    address_postal_full = models.CharField(max_length=100, null=True)
    call_charge_info = models.CharField(max_length=100, null=True)

    picture_caption = models.TextField(null=True)

    phone = models.CharField(max_length=120, null=True)
    fax = models.CharField(max_length=50, null=True)
    email = models.EmailField(max_length=100, null=True)
    accessibility_phone = models.CharField(max_length=50, null=True)
    accessibility_email = models.EmailField(max_length=100, null=True)
    accessibility_www = models.URLField(max_length=400, null=True)

    created_time = models.DateTimeField(null=True)  # ASK API: are these UTC? no Z in output

    municipality = models.ForeignKey(Municipality, null=True, db_index=True)
    address_zip = models.CharField(max_length=10, null=True)

    data_source = models.CharField(max_length=30, null=True)
    extensions = HStoreField(null=True)

    last_modified_time = models.DateTimeField(db_index=True, help_text='Time of last modification')

    service_nodes = models.ManyToManyField("ServiceNode", related_name='units')
    services = models.ManyToManyField("Service", related_name='units', through='UnitServiceDetails')
    keywords = models.ManyToManyField(Keyword)

    connection_hash = models.CharField(max_length=40, null=True,
                                       help_text='Automatically generated hash of connection info')
    accessibility_property_hash = models.CharField(
        max_length=40, null=True, help_text='Automatically generated hash of accessibility property info')
    identifier_hash = models.CharField(max_length=40, null=True,
                                       help_text='Automatically generated hash of other identifiers')
    service_details_hash = models.CharField(max_length=40, null=True)

    accessibility_viewpoints = JSONField(default="{}", null=True)

    # Cached fields for better performance
    root_service_nodes = models.CharField(max_length=50, null=True,
                                          validators=[validate_comma_separated_integer_list])

    objects = models.GeoManager()
    search_objects = UnitSearchManager()

    class Meta:
        ordering = ['-pk']

    def __str__(self):
        return "%s (%s)" % (get_translated(self, 'name'), self.id)

    def get_root_service_nodes(self):
        from .service_node import ServiceNode

        tree_ids = self.service_nodes.all().values_list('tree_id', flat=True).distinct()
        qs = ServiceNode.objects.filter(level=0).filter(tree_id__in=list(tree_ids))
        service_node_list = qs.values_list('id', flat=True).distinct()
        return sorted(service_node_list)
示例#11
0
class Shapefile(models.Model):
    url = models.URLField(unique=True)
    etags = HStoreField(default=dict)
示例#12
0
class Mapping(models.Model):
    # MappingID = models.IntegerField(primary_key = True)
    UserID = models.ForeignKey('Usr.Usr', on_delete = models.RESTRICT)
    MappingFor = models.TextField(null = True)
    CreatedOn = models.DateField(auto_now_add = True, null = True)
    Mappings =  HStoreField(null=True)
示例#13
0
class MLData(models.Model):
    fe = models.ForeignKey(FeatExtractedData, on_delete=models.CASCADE)
    parameters = HStoreField(null=True, default=None)
    path_to_file = models.CharField(max_length=250)#FileField()
示例#14
0
文件: test_hstore.py 项目: 01-/django
 def test_not_a_string(self):
     field = HStoreField()
     with self.assertRaises(exceptions.ValidationError) as cm:
         field.clean({'a': 1}, None)
     self.assertEqual(cm.exception.code, 'not_a_string')
     self.assertEqual(cm.exception.message % cm.exception.params, 'The value of "a" is not a string.')
示例#15
0
class Section(models.Model):
    exam = models.ForeignKey(Exam, related_name='sections', null=False)
    SECTION_CHOICES = (('MC', 'Multiple Choice'), ('E', 'Essay'), ('M',
                                                                   'Matching'),
                       ('TF', 'True False'), ('FB', 'Fill in the Blank'))
    section_type = models.CharField(max_length=2,
                                    choices=SECTION_CHOICES,
                                    default='E')

    SECTION_TEMPLATES = (
        ('E', 'exams/essay_question_template.html'),
        ('MC', 'exams/mc_question_template.html'),
        ('M', 'exams/matching_question_template.html'),
        ('TF', 'exams/tf_question_template.html'),
        ('FB', 'exams/fitb_question_template.html'),
    )

    SECTION_FORM_TEMPLATES = (
        ('E', 'exams/essay_question.html'),
        ('M', 'exams/matching_question.html'),
        ('TF', 'exams/tf_question.html'),
        ('FB', 'exams/fitb_question.html'),
        ('MC', 'exams/mc_question.html'),
    )

    @property
    def question_template(self):
        return dict(Section.SECTION_TEMPLATES)[self.section_type]

    # Instructions
    instructions = models.TextField(null=True, blank=True)

    # Required number of questions needed to submit exam
    required_number_to_submit = models.IntegerField(default=0)

    # First section in exam has a section_index of 0
    section_index = models.IntegerField(default=0)

    first_question_index = models.IntegerField(default=1)
    question_count = models.IntegerField()
    questions = HStoreField(null=True)

    def __unicode__(self):
        try:
            return "Section %s [%s] for %s" % (
                self.section_index, self.get_section_type_display(), self.exam)
        except AttributeError as e:
            return str(self.id) + ": " + str(e)

    class Meta:
        ordering = ['exam', 'section_index']
        unique_together = ('exam', 'section_index')

    def autograde(self, response):
        if self.section_type != 'E':
            responses = response.responses
            score_for_section = 0
            for i in range(1, self.question_count + 1):
                question_data = ast.literal_eval(self.questions[str(i)])
                # see if response of trainee equals answer; if it does assign point
                if self.section_type == 'FB':
                    responses_to_blanks = responses[str(i)].replace(
                        '\"', '').lower().split('$')
                    answers_to_blanks = str(
                        question_data["answer"]).lower().split('$')
                    total_blanks = len(responses_to_blanks)
                    number_correct = 0
                    for i in range(0, total_blanks):
                        try:
                            if responses_to_blanks[i] == answers_to_blanks[i]:
                                number_correct += 1
                        except IndexError:
                            continue
                    # TODO: convert to decimal
                    blank_weight = float(
                        question_data["points"]) / float(total_blanks)
                    score_for_section += (number_correct * blank_weight)
                # Everything else other than FB and Essay can be automatically graded with this
                elif (responses[str(i)].replace('\"', '').lower() == str(
                        question_data["answer"]).lower()):
                    score_for_section += int(question_data["points"])
            response.score = score_for_section
        else:
            response.comments = "NOT GRADED YET"
        # Finally save the response
        response.save()
        return response.score if response.score else 0
示例#16
0
class FeatExtractedData(models.Model):
    pp_recording = models.ForeignKey(Preprocessed_Recording, on_delete=models.CASCADE)
    parameters = HStoreField(null=True, default=None)
    path_to_file = models.CharField(max_length=250)#FileField()  # To become FileField...
示例#17
0
class Thumbnail(models.Model, File):
    user = models.ForeignKey(User,
                             related_name='thumbnails_at_user',
                             null=True)
    thumbnail_file = models.CharField(max_length=2000)
    thumbnail_sizes = HStoreField(null=True)

    @property
    def key(self):
        return self.thumbnail_file

    @key.setter
    def key(self, value):
        self.thumbnail_file = value

    @staticmethod
    @app.task
    def thumbnail_from_url(url,
                           key,
                           thumbnail,
                           sizes=settings.THUMBNAIL_SIZES):

        # download the file
        filename, _ = urllib.urlretrieve(url)
        # TODO use os.path.splitext:
        # https://docs.python.org/2/library/os.path.html#os.path.splitext
        ext = filename.rpartition('.')[2]
        image = Image.open(filename)

        # jpegs are rotated according to their exif data
        if ext in ['jpeg', 'jpg']:
            image = rotate_jpg_from_exif(image)
            ext = JPEG_FILE_EXTENSION

        # create a thumbnail for size
        for label, size in sizes.iteritems():
            if ext == GIF_FILE_EXTENSION:
                # NOTE: resize_gif_with_ratio is calling save on img internally
                thumb_image = resize_gif_with_ratio(image, size, StringIO())
            else:
                thumb_image = StringIO()
                # NOTE: while we're calling it manually here
                _thumb_image = resize_single_image_with_ratio(image, size)
                # NOTE: For thumbnails, we want to convert all supported image
                #       formats (with the exception of gif) to jpeg, as it
                #       generally does the best job in compression for all types
                #       of images.
                ext = JPEG_FILE_EXTENSION
                _thumb_image.format = ext
                _thumb_image.save(thumb_image, ext)

            # upload to aws
            aws_key = Key(aws.get_bucket())
            aws_key.key = Thumbnail.build_aws_key(key, label, ext)
            aws_key.set_contents_from_string(thumb_image.getvalue())
            aws_key.make_public()

            # update thumbnail
            if label == settings.THUMBNAIL_SIZE_DEFAULT and thumbnail.thumbnail_file == settings.THUMBNAIL_DEFAULT:
                thumbnail.thumbnail_file = aws_key.key
            thumbnail.thumbnail_sizes[label] = File.url_safe_from_key(
                aws_key.key)
            thumbnail.save()

            logger.info('Thumbnail created and uploaded to: \n{}'.format(
                thumbnail.thumbnail_sizes[label]))

        return thumbnail

    @staticmethod
    def build_aws_key(key, label, extension):
        return '{}_thumbnails/{}/{}.{}'.format(key, label, str(uuid.uuid4()),
                                               extension)
示例#18
0
class ProductVariant(models.Model):
    sku = models.CharField(max_length=32, unique=True)
    name = models.CharField(max_length=255, blank=True)
    price_override = MoneyField(
        currency=settings.DEFAULT_CURRENCY,
        max_digits=settings.DEFAULT_MAX_DIGITS,
        decimal_places=settings.DEFAULT_DECIMAL_PLACES,
        blank=True,
        null=True,
    )
    product = models.ForeignKey(Product,
                                related_name="variants",
                                on_delete=models.CASCADE)
    attributes = HStoreField(default=dict, blank=True)
    images = models.ManyToManyField("ProductImage", through="VariantImage")
    track_inventory = models.BooleanField(default=True)
    quantity = models.IntegerField(validators=[MinValueValidator(0)],
                                   default=Decimal(1))
    quantity_allocated = models.IntegerField(validators=[MinValueValidator(0)],
                                             default=Decimal(0))
    cost_price = MoneyField(
        currency=settings.DEFAULT_CURRENCY,
        max_digits=settings.DEFAULT_MAX_DIGITS,
        decimal_places=settings.DEFAULT_DECIMAL_PLACES,
        blank=True,
        null=True,
    )
    weight = MeasurementField(measurement=Weight,
                              unit_choices=WeightUnits.CHOICES,
                              blank=True,
                              null=True)
    translated = TranslationProxy()

    class Meta:
        app_label = "product"

    def __str__(self):
        return self.name or self.sku

    @property
    def quantity_available(self):
        return max(self.quantity - self.quantity_allocated, 0)

    @property
    def is_visible(self):
        return self.product.is_visible

    @property
    def is_available(self):
        return self.product.is_available

    def check_quantity(self, quantity):
        """Check if there is at least the given quantity in stock
        if stock handling is enabled.
        """
        if self.track_inventory and quantity > self.quantity_available:
            raise InsufficientStock(self)

    @property
    def base_price(self):
        return (self.price_override
                if self.price_override is not None else self.product.price)

    def get_price(self, discounts: Iterable[DiscountInfo] = None, taxes=None):
        price = calculate_discounted_price(self.product, self.base_price,
                                           discounts)
        if not self.product.charge_taxes:
            taxes = None
        tax_rate = self.product.tax_rate or self.product.product_type.tax_rate
        return apply_tax_to_price(taxes, tax_rate, price)

    def get_weight(self):
        return self.weight or self.product.weight or self.product.product_type.weight

    def get_absolute_url(self):
        slug = self.product.get_slug()
        product_id = self.product.id
        return reverse("product:details",
                       kwargs={
                           "slug": slug,
                           "product_id": product_id
                       })

    def is_shipping_required(self):
        return self.product.product_type.is_shipping_required

    def is_digital(self):
        is_digital = self.product.product_type.is_digital
        return not self.is_shipping_required() and is_digital

    def is_in_stock(self):
        return self.quantity_available > 0

    def display_product(self, translated=False):
        if translated:
            product = self.product.translated
            variant_display = str(self.translated)
        else:
            variant_display = str(self)
            product = self.product
        product_display = ("%s (%s)" % (product, variant_display)
                           if variant_display else str(product))
        return smart_text(product_display)

    def get_first_image(self):
        images = list(self.images.all())
        return images[0] if images else self.product.get_first_image()

    def get_ajax_label(self, discounts=None):
        price = self.get_price(discounts).gross
        return "%s, %s, %s" % (
            self.sku,
            self.display_product(),
            prices_i18n.amount(price),
        )
示例#19
0
class Product(models.Model):
    product_type = models.ForeignKey(ProductType,
                                     related_name='products',
                                     on_delete=models.CASCADE)
    name = models.CharField(max_length=128)
    description = models.TextField()
    seo_description = models.CharField(max_length=300,
                                       blank=True,
                                       null=True,
                                       validators=[MaxLengthValidator(300)])
    category = models.ForeignKey(Category,
                                 related_name='products',
                                 on_delete=models.CASCADE)
    price = MoneyField(currency=settings.DEFAULT_CURRENCY,
                       max_digits=12,
                       decimal_places=2)
    available_on = models.DateField(blank=True, null=True)
    is_published = models.BooleanField(default=True)
    attributes = HStoreField(default={})
    updated_at = models.DateTimeField(auto_now=True, null=True)
    is_featured = models.BooleanField(default=False)

    objects = ProductQuerySet.as_manager()

    class Meta:
        app_label = 'product'
        permissions = (('view_product',
                        pgettext_lazy('Permission description',
                                      'Can view products')),
                       ('edit_product',
                        pgettext_lazy('Permission description',
                                      'Can edit products')),
                       ('view_properties',
                        pgettext_lazy('Permission description',
                                      'Can view product properties')),
                       ('edit_properties',
                        pgettext_lazy('Permission description',
                                      'Can edit product properties')))

    def __iter__(self):
        if not hasattr(self, '__variants'):
            setattr(self, '__variants', self.variants.all())
        return iter(getattr(self, '__variants'))

    def __repr__(self):
        class_ = type(self)
        return '<%s.%s(pk=%r, name=%r)>' % (class_.__module__, class_.__name__,
                                            self.pk, self.name)

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('product:details',
                       kwargs={
                           'slug': self.get_slug(),
                           'product_id': self.id
                       })

    def get_slug(self):
        return slugify(smart_text(unidecode(self.name)))

    def is_in_stock(self):
        return any(variant.is_in_stock() for variant in self)

    def is_available(self):
        today = datetime.date.today()
        return self.available_on is None or self.available_on <= today

    def get_first_image(self):
        first_image = self.images.first()
        return first_image.image if first_image else None

    def get_attribute(self, pk):
        return self.attributes.get(smart_text(pk))

    def set_attribute(self, pk, value_pk):
        self.attributes[smart_text(pk)] = smart_text(value_pk)

    def get_price_per_item(self, item, discounts=None):
        return item.get_price_per_item(discounts)

    def get_price_range(self, discounts=None):
        if self.variants.exists():
            prices = [
                self.get_price_per_item(variant, discounts=discounts)
                for variant in self
            ]
            return TaxedMoneyRange(min(prices), max(prices))
        price = TaxedMoney(net=self.price, gross=self.price)
        discounted_price = calculate_discounted_price(self, price, discounts)
        return TaxedMoneyRange(start=discounted_price, stop=discounted_price)

    def get_gross_price_range(self, discounts=None):
        grosses = [
            self.get_price_per_item(variant, discounts=discounts)
            for variant in self
        ]
        if not grosses:
            return None
        grosses = sorted(grosses, key=lambda x: x.tax)
        return TaxedMoneyRange(min(grosses), max(grosses))
示例#20
0
class Product(models.Model, ItemRange):
    product_class = models.ForeignKey(ProductClass,
                                      related_name='products',
                                      verbose_name=pgettext_lazy(
                                          'Product field', 'product class'),
                                      on_delete=models.CASCADE)
    name = models.CharField(pgettext_lazy('Product field', 'name'),
                            max_length=128)
    price = models.DecimalField('Price', max_digits=6, decimal_places=2)
    #    description = models.TextField(
    #        verbose_name=pgettext_lazy('Product field', 'description'), blank=True)
    categories = models.ManyToManyField(Category,
                                        verbose_name=pgettext_lazy(
                                            'Product field', 'companies'),
                                        related_name='products')
    is_published = models.BooleanField(pgettext_lazy('Product field',
                                                     'is published'),
                                       default=True)
    attributes = HStoreField(pgettext_lazy('Product field', 'attributes'),
                             default={})
    updated_at = models.DateTimeField(pgettext_lazy('Product field',
                                                    'updated at'),
                                      auto_now=True,
                                      null=True)

    objects = ProductManager()

    class Meta:
        app_label = 'product'
        permissions = (('view_product',
                        pgettext_lazy('Permission description',
                                      'Can view products')),
                       ('edit_product',
                        pgettext_lazy('Permission description',
                                      'Can edit products')),
                       ('view_properties',
                        pgettext_lazy('Permission description',
                                      'Can view product properties')),
                       ('edit_properties',
                        pgettext_lazy('Permission description',
                                      'Can edit product properties')))

    def __iter__(self):
        if not hasattr(self, '__variants'):
            setattr(self, '__variants', self.variants.all())
        return iter(getattr(self, '__variants'))

    def __repr__(self):
        class_ = type(self)
        return '<%s.%s(pk=%r, name=%r)>' % (class_.__module__, class_.__name__,
                                            self.pk, self.name)

    def __str__(self):
        return self.name

    def get_slug(self):
        return slugify(smart_text(unidecode(self.name)))

    def get_first_category(self):
        for category in self.categories.all():
            return category
        return None

    def is_available(self):
        return True

    def get_first_image(self):
        first_image = self.images.first()

        if first_image:
            return first_image.image
        return None

    def get_attribute(self, pk):
        return self.attributes.get(smart_text(pk))

    def set_attribute(self, pk, value_pk):
        self.attributes[smart_text(pk)] = smart_text(value_pk)
class Contact(models.Model):
    uuid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
    core_user_uuid = models.UUIDField(blank=True, null=True)
    customer_id = models.CharField(
        max_length=32,
        blank=True,
        null=True,
        help_text='ID set by the customer. Must be unique in organization.')
    first_name = models.CharField(max_length=50,
                                  blank=True,
                                  help_text='First name',
                                  db_index=True)
    middle_name = models.CharField(
        max_length=50,
        blank=True,
        help_text='Middle name (not common in Germany)')
    last_name = models.CharField(max_length=50,
                                 blank=True,
                                 help_text='Surname or family name')
    title = models.CharField(max_length=16,
                             choices=TITLE_CHOICES,
                             blank=True,
                             null=True,
                             help_text='Choices: {}'.format(", ".join(
                                 [kv[0] for kv in TITLE_CHOICES])))
    suffix = models.CharField(
        max_length=50,
        blank=True,
        help_text='Suffix for titles like dr., prof., dr. med. etc.')
    contact_type = models.CharField(max_length=30,
                                    choices=CONTACT_TYPE_CHOICES,
                                    blank=True,
                                    null=True,
                                    help_text='Choices: {}'.format(", ".join([
                                        kv[0] for kv in CONTACT_TYPE_CHOICES
                                    ])))
    customer_type = models.CharField(max_length=30,
                                     choices=CUSTOMER_TYPE_CHOICES,
                                     blank=True,
                                     null=True,
                                     help_text='Choices: {}'.format(", ".join([
                                         kv[0] for kv in CUSTOMER_TYPE_CHOICES
                                     ])))
    company = models.CharField(max_length=100, blank=True, null=True)
    addresses = ArrayField(HStoreField(),
                           blank=True,
                           null=True,
                           help_text="""
                           List of 'address' objects with the structure:
                           type (string - Choices: {}),
                           street (string),
                           house_number (string),
                           postal_code: (string),
                           city (string),
                           country (string)
                           """.format(", ".join(
                               [k for k in ADDRESS_TYPE_CHOICES])),
                           validators=[validate_addresses])
    siteprofile_uuids = ArrayField(models.UUIDField(),
                                   blank=True,
                                   null=True,
                                   help_text='List of SiteProfile UUIDs')
    emails = ArrayField(HStoreField(),
                        blank=True,
                        null=True,
                        help_text="""
                               List of 'email' objects with the structure:
                               type (string - Choices: {}),
                               email (string)
                               """.format(", ".join(
                            [k for k in EMAIL_TYPE_CHOICES])),
                        validators=[validate_emails])
    phones = ArrayField(HStoreField(),
                        blank=True,
                        null=True,
                        help_text="""
                               List of 'phone' objects with the structure:
                               type (string - Choices: {}),
                               number (string)
                               """.format(", ".join(
                            [k for k in PHONE_TYPE_CHOICES])),
                        validators=[validate_phones])
    notes = models.TextField(blank=True, null=True)
    organization_uuid = models.CharField(max_length=36,
                                         blank=True,
                                         null=True,
                                         verbose_name='Organization UUID',
                                         db_index=True)
    workflowlevel1_uuids = ArrayField(models.CharField(max_length=36),
                                      help_text='List of Workflowlevel1 UUIDs')
    workflowlevel2_uuids = ArrayField(models.CharField(max_length=36),
                                      blank=True,
                                      null=True,
                                      help_text='List of Workflowlevel2 UUIDs')

    def __str__(self):
        return f"{self.first_name} {self.last_name}"

    class Meta:
        indexes = [
            GinIndex(fields=['workflowlevel1_uuids']),
            GinIndex(fields=['workflowlevel2_uuids'])
        ]
示例#22
0
文件: models.py 项目: kahihia/project
class B2CProduct(ActiveModelMixing, models.Model, IndexedModelMixin):
    name = models.CharField(max_length=255, blank=False, name=False)
    categories = models.ManyToManyField(B2CProductCategory,
                                        related_name='products')
    slug = models.SlugField(max_length=255)
    short_description = models.TextField(null=False)
    description = models.TextField(blank=False, null=False)
    image = CustomImageField(upload_to=generate_upload_path,
                             storage=image_storage,
                             sizes=['big', 'small', 'th'],
                             blank=True,
                             null=True,
                             max_length=255)
    additional_images = ArrayField(ArrayField(
        models.CharField(max_length=500, blank=True)),
                                   blank=True,
                                   null=True)
    company = models.ForeignKey(Company,
                                on_delete=models.CASCADE,
                                related_name='b2c_products')
    keywords = models.CharField(max_length=2048, blank=True, null=False)
    currency = models.CharField(max_length=255,
                                blank=False,
                                null=True,
                                choices=CURRENCY)
    cost = models.DecimalField(max_digits=15,
                               decimal_places=2,
                               null=True,
                               blank=False)
    producer = models.ForeignKey(Producer,
                                 related_name='b2c_products',
                                 verbose_name=_('Producer'),
                                 null=True,
                                 blank=True)
    galleries = GenericRelation(Gallery)
    documents = GenericRelation(Document)
    show_on_main = models.BooleanField(default=False, db_index=True)
    is_active = models.BooleanField(default=True)
    is_deleted = models.BooleanField(default=False, db_index=True)
    additional_pages = GenericRelation(AdditionalPage)
    additional_parameters = GenericRelation(AdditionalParameters)
    metadata = HStoreField()
    discount_percent = models.FloatField(null=True, blank=True)
    coupon_discount_percent = models.FloatField(null=True, blank=True)
    coupon_dates = DateRangeField(null=True, blank=True)

    extra_params = JSONField(_('Extra param fields'), null=True, blank=True)
    colors = ArrayField(models.CharField('Colors', max_length=100),
                        blank=True,
                        null=True)

    created_by = models.ForeignKey(settings.AUTH_USER_MODEL,
                                   related_name='%(class)s_create_user')
    updated_by = models.ForeignKey(settings.AUTH_USER_MODEL,
                                   related_name='%(class)s_update_user')
    created_at = models.DateTimeField(default=timezone.now, db_index=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        index_together = [
            ['created_at', 'company'],
        ]

    def upload_images(self):
        from core import tasks
        params = {
            'file': self.image.path,
            'sizes': {
                'big': {
                    'box': (500, 500),
                    'fit': False
                },
                'small': {
                    'box': (200, 200),
                    'fit': False
                },
                'th': {
                    'box': (80, 80),
                    'fit': True
                }
            }
        }

        tasks.upload_images.delay(params)

    @property
    def country(self):
        return self.company.country

    @property
    def sku(self):
        if self.metadata:
            return self.metadata.get('stock_keeping_unit', None)
        return None

    @staticmethod
    def get_index_model(**kwargs):
        from b24online.search_indexes import B2cProductIndex
        return B2cProductIndex

    def __str__(self):
        return self.name

    def has_perm(self, user):
        return self.company.has_perm(user)

    def get_absolute_url(self):
        return reverse('products:B2CDetail', args=[self.slug, self.pk])

    @property
    def gallery_images(self):
        model_type = ContentType.objects.get_for_model(self)
        return GalleryImage.objects.filter(gallery__content_type=model_type,
                                           gallery__object_id=self.pk)

    @property
    def start_coupon_date(self):
        if self.coupon_dates:
            return self.coupon_dates.lower
        return None

    @property
    def end_coupon_date(self):
        if self.coupon_dates:
            return self.coupon_dates.upper
        return None

    @property
    def is_coupon(self):
        return self.start_coupon_date and self.end_coupon_date \
               and self.start_coupon_date <= now().date() < self.end_coupon_date

    @property
    def has_discount(self):
        return self.cost and (self.is_coupon or self.discount_percent)

    def get_discount_price(self):
        discount_percent = 0
        original_price = self.cost or 0

        if self.is_coupon:
            discount_percent = self.coupon_discount_percent
        elif self.discount_percent:
            discount_percent = self.discount_percent
        return original_price - original_price * Decimal(
            discount_percent) / 100

    def get_profit(self):
        return self.cost - self.get_discount_price()

    def get_contextmenu_options(self):
        """
        Return extra options for context menu.
        """
        model_type = ContentType.objects.get_for_model(self)
        if getattr(self, 'pk', None):
            yield (reverse('questionnaires:list',
                           kwargs={
                               'content_type_id': model_type.id,
                               'item_id': self.pk
                           }), _('Questionnaire'))
            yield (reverse('products:extra_params_list',
                           kwargs={'item_id':
                                   self.pk}), _('Additional_parameters'))

    def get_extra_params(self):
        """Return the additional parameters."""
        result = []
        for field_item in self.extra_params or []:
            row = {}
            for field_name, field_value in field_item.items():
                if field_name == 'initial':
                    if isinstance(field_value, str):
                        row[field_name] = [('en', field_value)]
                    elif isinstance(field_value, (tuple, list)):
                        row[field_name] = field_value
                else:
                    row[field_name] = field_value
            result.append(row)
        return result
示例#23
0
 class MyModel(PostgreSQLModel):
     field = HStoreField(default=dict)
示例#24
0
class ProductVariant(models.Model, Item):
    sku = models.CharField(pgettext_lazy('Product variant field', 'SKU'),
                           max_length=32,
                           unique=True)
    name = models.CharField(pgettext_lazy('Product variant field',
                                          'variant name'),
                            max_length=100,
                            blank=True)
    price_override = PriceField(pgettext_lazy('Product variant field',
                                              'price override'),
                                currency=settings.DEFAULT_CURRENCY,
                                max_digits=12,
                                decimal_places=2,
                                blank=True,
                                null=True)
    wholesale_override = PriceField(pgettext_lazy('Product variant field',
                                                  'wholesale override'),
                                    currency=settings.DEFAULT_CURRENCY,
                                    max_digits=12,
                                    decimal_places=2,
                                    blank=True,
                                    null=True)

    product = models.ForeignKey(Product, related_name='variants')
    attributes = HStoreField(pgettext_lazy('Product variant field',
                                           'attributes'),
                             default={})
    images = models.ManyToManyField('ProductImage',
                                    through='VariantImage',
                                    verbose_name=pgettext_lazy(
                                        'Product variant field', 'images'))
    low_stock_threshold = models.IntegerField(
        pgettext_lazy('Product variant field', 'low stock threshold'),
        validators=[MinValueValidator(0)],
        null=True,
        blank=True,
        default=Decimal(10))
    objects = ProductVariantManager()

    class Meta:
        app_label = 'product'
        verbose_name = pgettext_lazy('Product variant model',
                                     'product variant')
        verbose_name_plural = pgettext_lazy('Product variant model',
                                            'product variants')

    def __str__(self):
        return self.name or self.display_variant()

    def check_quantity(self, quantity):
        available_quantity = self.get_stock_quantity()
        if quantity > available_quantity:
            raise InsufficientStock(self)

    def get_stock_pk(self):
        stock_pk = self.stock.all().values('pk')
        if stock_pk.exists():
            for st in stock_pk:
                stock_pk = st['pk']
        else:
            stock_pk = 0
        return stock_pk

    def get_stock_quantity(self):
        if not len(self.stock.all()):
            return 0
        return max([stock.quantity_available for stock in self.stock.all()])

    def get_price_per_item(self, discounts=None, **kwargs):
        price = self.price_override or self.product.price
        price = calculate_discounted_price(self.product, price, discounts,
                                           **kwargs)
        return price

    def get_wholesale_price_per_item(self, discounts=None, **kwargs):
        price = self.wholesale_override or self.product.wholesale_price
        price = calculate_discounted_price(self.product, price, discounts,
                                           **kwargs)
        return price

    def get_total_price_cost(self):
        cost = self.get_cost_price() * self.get_stock_quantity()
        return cost

    def get_absolute_url(self):
        slug = self.product.get_slug()
        product_id = self.product.id
        return reverse('product:details',
                       kwargs={
                           'slug': slug,
                           'product_id': product_id
                       })

    def as_data(self):
        return {
            'product_name': str(self),
            'product_id': self.product.pk,
            'variant_id': self.pk,
            'unit_price': str(self.get_price_per_item().gross)
        }

    def is_shipping_required(self):
        return self.product.product_class.is_shipping_required

    def is_in_stock(self):
        return any(
            [stock.quantity_available > 0 for stock in self.stock.all()])

    def get_attribute(self, pk):
        return self.attributes.get(smart_text(pk))

    def set_attribute(self, pk, value_pk):
        self.attributes[smart_text(pk)] = smart_text(value_pk)

    def display_variant(self, attributes=None):
        if attributes is None:
            attributes = self.product.product_class.variant_attributes.all()
        values = get_attributes_display_map(self, attributes)
        if values:
            return ', '.join([
                ' %s' % (smart_text(value))
                for (key, value) in six.iteritems(values)
            ])
        else:
            return smart_text(self.sku)

    def display_product(self):
        return '%s (%s)' % (smart_text(self.product), smart_text(self))

    def get_first_image(self):
        return self.product.get_first_image()

    def select_stockrecord(self, quantity=1):
        # By default selects stock with lowest cost price
        stock = filter(lambda stock: stock.quantity_available >= quantity,
                       self.stock.all())
        stock = sorted(stock, key=lambda stock: stock.cost_price, reverse=True)
        if stock:
            return stock[0]

    def get_cost_price(self):
        stock = self.select_stockrecord()
        if stock:
            if stock.cost_price:
                return stock.cost_price
            else:
                return 0
        else:
            return 0

    def product_category(self):
        category = self.product.categories.first().name
        return category
示例#25
0
 def test_none_allowed_as_value(self):
     field = HStoreField()
     self.assertEqual(field.clean({'a': None}, None), {'a': None})
示例#26
0
文件: models.py 项目: camerondiou/BMO
class ProductVariant(models.Model):
    sku = models.CharField(max_length=32, unique=True)
    name = models.CharField(max_length=255, blank=True)
    price_override = MoneyField(currency=settings.DEFAULT_CURRENCY,
                                max_digits=12,
                                decimal_places=settings.DEFAULT_DECIMAL_PLACES,
                                blank=True,
                                null=True)
    product = models.ForeignKey(Product,
                                related_name='variants',
                                on_delete=models.CASCADE)
    attributes = HStoreField(default={}, blank=True)
    images = models.ManyToManyField('ProductImage', through='VariantImage')
    quantity = models.IntegerField(validators=[MinValueValidator(0)],
                                   default=Decimal(1))
    quantity_allocated = models.IntegerField(validators=[MinValueValidator(0)],
                                             default=Decimal(0))
    cost_price = MoneyField(currency=settings.DEFAULT_CURRENCY,
                            max_digits=12,
                            decimal_places=settings.DEFAULT_DECIMAL_PLACES,
                            blank=True,
                            null=True)

    class Meta:
        app_label = 'product'

    def __str__(self):
        return self.name or self.sku

    @property
    def quantity_available(self):
        return max(self.quantity - self.quantity_allocated, 0)

    def check_quantity(self, quantity):
        if quantity > self.quantity_available:
            raise InsufficientStock(self)

    @property
    def base_price(self):
        return self.price_override or self.product.price

    def get_price(self, discounts=None, taxes=None):
        price = calculate_discounted_price(self.product, self.base_price,
                                           discounts)
        if not self.product.charge_taxes:
            taxes = None
        tax_rate = (self.product.tax_rate
                    or self.product.product_type.tax_rate)
        return apply_tax_to_price(taxes, tax_rate, price)

    def get_absolute_url(self):
        slug = self.product.get_slug()
        product_id = self.product.id
        return reverse('product:details',
                       kwargs={
                           'slug': slug,
                           'product_id': product_id
                       })

    def is_shipping_required(self):
        return self.product.product_type.is_shipping_required

    def is_in_stock(self):
        return self.quantity_available > 0

    def display_product(self):
        variant_display = str(self)
        product_display = ('%s (%s)' % (self.product, variant_display)
                           if variant_display else str(self.product))
        return smart_text(product_display)

    def get_first_image(self):
        return self.product.get_first_image()

    def get_ajax_label(self, discounts=None):
        price = self.get_price(discounts).gross
        return '%s, %s, %s' % (self.sku, self.display_product(),
                               prices_i18n.amount(price))
示例#27
0
 def test_model_field_formfield(self):
     model_field = HStoreField()
     form_field = model_field.formfield()
     self.assertIsInstance(form_field, forms.HStoreField)
示例#28
0
class Contact(models.Model):
    """
    A contact in RapidPro
    """

    DISPLAY_NAME = "name"
    DISPLAY_URNS = "urns"
    DISPLAY_ANON = "uuid"

    SAVE_GROUPS_ATTR = "__data__groups"

    org = models.ForeignKey(Org,
                            verbose_name=_("Organization"),
                            related_name="contacts",
                            on_delete=models.PROTECT)

    uuid = models.CharField(max_length=36, unique=True, null=True)

    name = models.CharField(verbose_name=_("Full name"),
                            max_length=128,
                            null=True,
                            blank=True,
                            help_text=_("The name of this contact"))

    groups = models.ManyToManyField(Group, related_name="contacts")

    fields = HStoreField(null=True)

    language = models.CharField(max_length=3,
                                verbose_name=_("Language"),
                                null=True,
                                blank=True,
                                help_text=_("Language for this contact"))

    is_active = models.BooleanField(default=True,
                                    help_text="Whether this contact is active")

    is_blocked = models.BooleanField(
        default=False, help_text="Whether this contact is blocked")

    is_stopped = models.BooleanField(
        default=False,
        help_text="Whether this contact opted out of receiving messages")

    is_stub = models.BooleanField(
        default=False, help_text="Whether this contact is just a stub")

    suspended_groups = models.ManyToManyField(
        Group, help_text=_("Groups this contact has been suspended from"))

    created_on = models.DateTimeField(
        auto_now_add=True, help_text=_("When this contact was created"))

    urns = ArrayField(models.CharField(max_length=255),
                      default=list,
                      help_text=_("List of URNs of the format 'scheme:path'"))

    def __init__(self, *args, **kwargs):
        if self.SAVE_GROUPS_ATTR in kwargs:
            setattr(self, self.SAVE_GROUPS_ATTR,
                    kwargs.pop(self.SAVE_GROUPS_ATTR))

        super(Contact, self).__init__(*args, **kwargs)

    @classmethod
    def get_or_create(cls, org, uuid, name=None):
        """
        Gets an existing contact or creates a stub contact. Used when receiving messages where the contact might not
        have been synced yet
        """
        with cls.lock(org, uuid):
            contact = cls.objects.filter(org=org, uuid=uuid).first()
            if not contact:
                contact = cls.objects.create(org=org,
                                             uuid=uuid,
                                             name=name,
                                             is_stub=True)

            return contact

    @classmethod
    def get_or_create_from_urn(cls, org, urn, name=None):
        """
        Gets an existing contact or creates a new contact. Used when opening a case without an initial message
        """
        normalized_urn = URN.normalize(urn)

        contact = cls.objects.filter(urns__contains=[normalized_urn]).first()
        if not contact:
            URN.validate(normalized_urn)

            contact = cls.objects.create(org=org,
                                         name=name,
                                         urns=[normalized_urn],
                                         is_stub=False)
            org.get_backend().push_contact(org, contact)
        return contact

    @classmethod
    def lock(cls, org, uuid):
        return get_redis_connection().lock(CONTACT_LOCK_KEY % (org.pk, uuid),
                                           timeout=60)

    def get_display(self):
        """
        Gets the display of this contact. If the site uses anonymous contacts this is generated from the backend UUID.
        If the display setting is recognised and set then that field is returned, otherwise the name is returned.
        If no name is set an empty string is returned.
        """
        display_format = getattr(settings, "SITE_CONTACT_DISPLAY",
                                 self.DISPLAY_NAME)

        if display_format == self.DISPLAY_ANON and self.uuid:
            return self.uuid[:6].upper()
        elif display_format == self.DISPLAY_URNS and self.urns:
            _scheme, path = URN.to_parts(self.urns[0])
            return path
        elif display_format == self.DISPLAY_NAME and self.name:
            return self.name

        return "---"

    def get_fields(self, visible=None):
        fields = self.fields if self.fields else {}

        if visible:
            keys = Field.get_all(self.org, visible=True).values_list("key",
                                                                     flat=True)
            return {k: fields.get(k) for k in keys}
        else:
            return fields

    def get_language(self):
        if self.language:
            return {
                "code": self.language,
                "name": get_language_name(self.language)
            }
        else:
            return None

    def prepare_for_case(self):
        """
        Prepares this contact to be put in a case
        """
        if self.is_stub:  # pragma: no cover
            raise ValueError("Can't create a case for a stub contact")

        # suspend contact from groups while case is open
        self.suspend_groups()

        # expire any active flow runs they have
        self.expire_flows()

        # labelling task may have picked up messages whilst case was closed. Those now need to be archived.
        self.archive_messages()

    def suspend_groups(self):
        with self.lock(self.org, self.uuid):
            if self.suspended_groups.all():  # pragma: no cover
                raise ValueError(
                    "Can't suspend from groups as contact is already suspended from groups"
                )

            cur_groups = list(self.groups.all())
            suspend_groups = set(Group.get_suspend_from(self.org))

            for group in cur_groups:
                if group in suspend_groups:
                    self.groups.remove(group)
                    self.suspended_groups.add(group)

                    self.org.get_backend().remove_from_group(
                        self.org, self, group)

    def restore_groups(self):
        with self.lock(self.org, self.uuid):
            for group in list(self.suspended_groups.all()):
                if not group.is_dynamic:
                    self.groups.add(group)
                    self.org.get_backend().add_to_group(self.org, self, group)

                self.suspended_groups.remove(group)

    def expire_flows(self):
        self.org.get_backend().stop_runs(self.org, self)

    def archive_messages(self):
        self.incoming_messages.update(is_archived=True)

        self.org.get_backend().archive_contact_messages(self.org, self)

    def release(self):
        """
        Deletes this contact, removing them from any groups they were part of
        """
        self.groups.clear()

        # mark all messages as inactive and handled
        self.incoming_messages.update(is_handled=True, is_active=False)

        self.is_active = False
        self.save(update_fields=("is_active", ))

    def as_json(self, full=True):
        """
        Prepares a contact for JSON serialization
        """
        result = {"id": self.pk, "display": self.get_display()}

        if full:
            hidden_fields = getattr(settings, "SITE_HIDE_CONTACT_FIELDS", [])
            result["urns"] = self.urns if "urns" not in hidden_fields else []
            result["name"] = self.name if "name" not in hidden_fields else None
            result["groups"] = [
                g.as_json(full=False) for g in self.groups.all()
            ]
            result["fields"] = self.get_fields(visible=True)
            result["language"] = self.get_language()
            result["blocked"] = self.is_blocked
            result["stopped"] = self.is_stopped

        return result

    def __str__(self):
        return self.get_display()
示例#29
0
class ProductVariant(models.Model):
    sku = models.CharField(max_length=32, unique=True)
    name = models.CharField(max_length=100, blank=True)
    price_override = MoneyField(currency=settings.DEFAULT_CURRENCY,
                                max_digits=12,
                                decimal_places=2,
                                blank=True,
                                null=True)
    product = models.ForeignKey(Product,
                                related_name='variants',
                                on_delete=models.CASCADE)
    attributes = HStoreField(default={})
    images = models.ManyToManyField('ProductImage', through='VariantImage')

    class Meta:
        app_label = 'product'

    def __str__(self):
        return self.name or self.display_variant_attributes()

    def check_quantity(self, quantity):
        total_available_quantity = self.get_stock_quantity()
        if quantity > total_available_quantity:
            raise InsufficientStock(self)

    def get_stock_quantity(self):
        return sum([stock.quantity_available for stock in self.stock.all()])

    def get_price_per_item(self, discounts=None):
        price = self.price_override or self.product.price
        price = TaxedMoney(net=price, gross=price)
        price = calculate_discounted_price(self.product, price, discounts)
        return price

    def get_absolute_url(self):
        slug = self.product.get_slug()
        product_id = self.product.id
        return reverse('product:details',
                       kwargs={
                           'slug': slug,
                           'product_id': product_id
                       })

    def as_data(self):
        return {
            'product_name': str(self),
            'product_id': self.product.pk,
            'variant_id': self.pk,
            'unit_price': str(self.get_price_per_item().gross)
        }

    def is_shipping_required(self):
        return self.product.product_type.is_shipping_required

    def is_in_stock(self):
        return any(
            [stock.quantity_available > 0 for stock in self.stock.all()])

    def display_variant_attributes(self, attributes=None):
        if attributes is None:
            attributes = self.product.product_type.variant_attributes.all()
        values = get_attributes_display_map(self, attributes)
        if values:
            return ', '.join([
                '%s: %s' %
                (smart_text(attributes.get(id=int(key))), smart_text(value))
                for (key, value) in values.items()
            ])
        return ''

    def display_product(self):
        variant_display = str(self)
        product_display = ('%s (%s)' % (self.product, variant_display)
                           if variant_display else str(self.product))
        return smart_text(product_display)

    def get_first_image(self):
        return self.product.get_first_image()

    def select_stockrecord(self, quantity=1):
        # By default selects stock with lowest cost price. If stock cost price
        # is None we assume price equal to zero to allow sorting.
        stock = [
            stock_item for stock_item in self.stock.all()
            if stock_item.quantity_available >= quantity
        ]
        zero_price = Money(0, settings.DEFAULT_CURRENCY)
        stock = sorted(stock,
                       key=(lambda s: s.cost_price or zero_price),
                       reverse=False)
        if stock:
            return stock[0]
        return None

    def get_cost_price(self):
        stock = self.select_stockrecord()
        if stock:
            return stock.cost_price
        return None
示例#30
0
 def test_none_allowed_as_value(self):
     field = HStoreField()
     self.assertEqual(field.clean({'a': None}, None), {'a': None})
示例#31
0
class Listing(SlugMixin, AbstractProduct):
    FORCE_SLUG_REGENERATION = False

    SOCIAL_NETWORKS = ['Facebook', 'Twitter', 'Google', 'Instagram', 'Vimeo', 'YouTube', 'LinkedIn', 'Dribbble',
                       'Skype', 'Foursquare', 'Behance']  # TODO: move to settings

    PRICE_UNITS = [
        ('ENTRY', _('entry')),  # tickets
        ('HOUR', _('hour')),  # parking
        ('DAY', _('day')),  # vehicle per day
        ('NIGHT', _('night')),  # room unit per night
    ]

    # definition
    title = models.CharField(_('title'), max_length=100)
    slug = models.SlugField(unique=True, max_length=SlugMixin.MAX_SLUG_LENGTH, blank=True)
    description = models.TextField(_('description'), blank=True)

    # management
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name=_('author'))
    published = models.BooleanField(_('published'), default=True)
    hidden = models.BooleanField(_('hidden'), default=False)
    promoted = models.BooleanField(_('promoted'), default=False)
    rank = models.PositiveSmallIntegerField(_('rank'), default=1)

    # specification
    categories = models.ManyToManyField(to=Category, verbose_name=_('categories'), blank=True, related_name='listings_of_category')
    features = models.ManyToManyField(to=Feature, verbose_name=_('features'), blank=True, related_name='listings_with_features')

    # price
    price_starts_at = models.BooleanField(_('price starts at'), default=False)
    # price = models.DecimalField(_('price'), help_text=inventor_settings.CURRENCY, max_digits=10, decimal_places=2, db_index=True, validators=[MinValueValidator(0)],
    #                             blank=True, null=True, default=None)
    price_unit = models.CharField(_('price unit'), choices=PRICE_UNITS, max_length=5, blank=True)
    price_per_person = models.BooleanField(_('price per person'), default=False)

    # location
    locality = models.ForeignKey(Locality, on_delete=models.SET_NULL,
                                 blank=True, null=True, default=None)

    address = models.TextField(_('address'), help_text=_('street, postcode, city'), max_length=500, blank=True)

    # street = models.CharField(_('street'), max_length=200, blank=True)
    # postcode = models.CharField(_('postcode'), max_length=30, blank=True)
    # city = models.CharField(_('city'), max_length=50, blank=True)
    country = CountryField(verbose_name=_('country'), blank=True, db_index=True)
    point = models.PointField(_('point'), blank=True, null=True, default=None, db_index=True)

    # previews
    image = thumbnail.ImageField(
        verbose_name=_('image'),
        help_text=_('photo or image'),
        max_length=1024,
        upload_to='images',
        blank=True
    )

    banner = models.ImageField(
        verbose_name=_('banner'),
        help_text=_('photo or image'),
        max_length=1024 * 5,
        upload_to='banners',
        blank=True
    )

    # contact information
    person = models.CharField(_('person'), max_length=100, blank=True)
    phone = models.CharField(_('phone'), max_length=40, blank=True)
    email = models.EmailField(_('email'), blank=True)
    website = models.URLField(_('website'), max_length=400, blank=True)

    # social
    social_networks = HStoreField(verbose_name=_('social networks'), blank=True, default=dict)

    # relations
    # comments = GenericRelation(get_comment_model(), content_type_field='content_type', object_id_field='object_pk',
    #                            related_query_name='comment')

    supplies = GenericRelation('commerce.Supply', content_type_field='content_type', object_id_field='object_id',
                               related_query_name='product')

    created = models.DateTimeField(_('created'), auto_now_add=True)
    modified = models.DateTimeField(_('modified'), auto_now=True)
    i18n = TranslationField(fields=('title', 'slug', 'description'))
    objects = MultilingualManager.from_queryset(ListingQuerySet)()

    class Meta:
        verbose_name = _('listing')
        verbose_name_plural = _('listings')
        ordering = ('title',)
        db_table = 'listings_general'
        indexes = [GinIndex(fields=["i18n"]), ]

    def __str__(self):
        return self.title_i18n

    def get_absolute_url(self):
        return reverse('listings:listing_detail', args=(self.slug_i18n,))

    def get_update_url(self):
        return reverse('listings:listing_update', args=(self.pk,))

    @property
    def full_address(self):
        return '{}, {}'.format(self.address, self.country).strip(', ')

    def get_price_display(self):
        if not self.price:
            return ''

        price = str(self.price)

        if price.endswith('.00'):
            price = price[:-3]

        if inventor_settings.CURRENCY_AFTER_AMOUNT:
            price_display = '{} {}'.format(price, inventor_settings.CURRENCY_SYMBOL)  # example: 10 €
        else:
            price_display = '{}{}'.format(inventor_settings.CURRENCY_SYMBOL, price)   # example: $10

        if self.price_starts_at:
            price_display = '{} {}'.format(_('starts at'), price_display)

        if self.price_unit:
            price_display = '{} / {}'.format(price_display, self.get_price_unit_display())

        return price_display

    @cached_property
    def rating(self):
        avg_rating = self.comments.aggregate(Avg('rating'))
        # TODO: rating subjects:
        # - Facilities / Amenities
        # - Cleanliness
        # - Comfort
        # - Location
        # - Services?
        rating = avg_rating['rating__avg']
        if rating:
            rating = round(rating, 2)
        return rating

    def delete(self, **kwargs):
        """ Deletes file before deleting instance """
        self.delete_banner()
        super().delete(**kwargs)

    def delete_banner(self):
        """ Deletes image file """
        try:
            os.remove(self.banner.path)
        except ValueError:
            pass
        except IOError:
            pass
        except OSError:
            pass

    @property
    def listing_class(self):
        return self.__class__

    @property
    def listing_class_name(self):
        return self.__class__.__name__

    def get_listing_type_display(self):
        # return self.listing_class._meta.verbose_name
        return self.get_real_instance().listing_class._meta.verbose_name

    def get_listing_type_display_plural(self):
        # return self.listing_class._meta.verbose_name_plural
        return self.get_real_instance().listing_class._meta.verbose_name_plural

    @cached_property
    def all_images(self):
        return Photo.objects.filter(album__listing__pk=self.pk)

    @classmethod
    def get_list_url_name(cls):
        url_name = f'{cls.__name__.lower()}_list'
        return f'{url_name}'

    @classmethod
    def get_list_url(cls):
        url_name = cls.get_list_url_name()
        return reverse(f'listings:{url_name}')

    # https://stackoverflow.com/questions/21063078/convert-a-subclass-model-instance-to-another-subclass-model-instance-in-django
    def convert(self, to_type):
        instance = self
        # print(f'[{instance.id}]\t {instance}')

        # create new instance with same parent ID
        new_instance = to_type(listing_ptr_id=instance.id)

        # update parent fields
        new_instance.__dict__.update(instance.__dict__)

        # delete the subclass while keeping the parent
        instance.delete(keep_parents=True)

        # save new instance
        new_instance.save()

    def get_real_instance(self):
        """ get object child instance """

        def get_subclasses(cls):
            subclasses = cls.__subclasses__()
            result = []
            for subclass in subclasses:
                if not subclass._meta.abstract:
                    result.append(subclass)
                else:
                    result += get_subclasses(subclass)
            return result

        if hasattr(self, '_real_instance'):  # try looking in our cache
            return self._real_instance

        subclasses = get_subclasses(self.__class__)

        if not subclasses:  # already real_instance
            self._real_instance = self
            return self._real_instance
        else:
            subclasses_names = [cls.__name__.lower() for cls in subclasses]
            for subcls_name in subclasses_names:
                if hasattr(self, subcls_name):
                    return getattr(self, subcls_name, self)
            return self
示例#32
0
文件: test_hstore.py 项目: 01-/django
 def test_model_field_formfield(self):
     model_field = HStoreField()
     form_field = model_field.formfield()
     self.assertIsInstance(form_field, forms.HStoreField)
示例#33
0
class Preprocessed_Data(models.Model):
    pp_recording = models.ForeignKey(Preprocessed_Recording, on_delete=models.CASCADE)
    store = HStoreField()