class Idea(CreationModificationDateBase, UrlBase): uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) author = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_("Author"), on_delete=models.SET_NULL, blank=True, null=True, related_name="authored_ideas2", ) title = models.CharField(_("Title"), max_length=200) content = models.TextField(_("Content")) picture = models.ImageField(_("Picture"), upload_to=upload_to) picture_social = ImageSpecField( source="picture", processors=[ResizeToFill(1024, 512)], format="JPEG", options={"quality": 100}, ) picture_large = ImageSpecField(source="picture", processors=[ResizeToFill(800, 400)], format="PNG") picture_thumbnail = ImageSpecField(source="picture", processors=[ResizeToFill(728, 250)], format="PNG") categories = models.ManyToManyField( "categories2.Category", verbose_name=_("Categories"), related_name="category_ideas", ) rating = models.PositiveIntegerField(_("Rating"), choices=RATING_CHOICES, blank=True, null=True) class Meta: verbose_name = _("Idea") verbose_name_plural = _("Ideas") def __str__(self): return self.title def get_url_path(self): return reverse("ideas:idea_detail", kwargs={"pk": self.pk}) @property def structured_data(self): from django.utils.translation import get_language lang_code = get_language() data = { "@type": "CreativeWork", "name": self.translated_title, "description": self.translated_content, "inLanguage": lang_code, } if self.author: data["author"] = { "@type": "Person", "name": self.author.get_full_name() or self.author.username, } if self.picture: data["image"] = self.picture_social.url return data def delete(self, *args, **kwargs): from django.core.files.storage import default_storage if self.picture: with contextlib.suppress(FileNotFoundError): default_storage.delete(self.picture_social.path) default_storage.delete(self.picture_large.path) default_storage.delete(self.picture_thumbnail.path) self.picture.delete() super().delete(*args, **kwargs)
class Banner(models.Model): summary = models.CharField(verbose_name=_(u'描述'), max_length=100, default='') click = models.URLField(verbose_name=_(u'网址'), default='') ordering = models.IntegerField(_(u'排序'), default='1') cover = ProcessedImageField(verbose_name=_(u'图片'), upload_to='banner', processors=[ResizeToFill(720, 240)], format='JPEG', null=True, help_text=u'图片尺寸最好为720x240') class Meta: ordering = ('pk',) verbose_name = _(u'横幅广告') verbose_name_plural = _(u'横幅广告') def __unicode__(self): return self.summary def __str__(self): return self.__unicode__()
class TechnicalSolutions(models.Model): """ Готовые технические решения (группа материалов собранных в готовый к применению продукт "под ключ" и продвигаемый на рынок) """ name = models.CharField(verbose_name='название материала', max_length=128, unique=True) slug = models.SlugField(verbose_name='слаг', max_length=128, unique=True) measure = models.ForeignKey(MeasureTypes, verbose_name='Единица измерения', on_delete=models.CASCADE, default=1) image = ProcessedImageField( verbose_name='картинка продукта', upload_to=image_upload_to, processors=[ResizeToFill(370, 220)], default='products_images/default-product-image.png', blank=True) # image = models.ImageField(verbose_name='картинка продукта', upload_to=image_upload_to, # default='products_images/default-product-image.png', blank=True) alt_desc = models.CharField(verbose_name='alt фотографии', max_length=500, blank=True) short_desc = models.TextField(verbose_name='краткое описание материала', blank=True, null=True) description = models.TextField(verbose_name='описание материала', blank=True) price = models.DecimalField(verbose_name='цена', max_digits=8, decimal_places=2, default=0) quantity = models.IntegerField(verbose_name='объем работ', default=1) created = models.DateTimeField(auto_now_add=True, auto_now=False) updated = models.DateTimeField(verbose_name='обновлен', auto_now_add=False, auto_now=True) is_active = models.BooleanField(verbose_name='активен', default=False) def get_absolute_url(self): return reverse('products:product', args=[str(self.pk)]) def get_items(self): """Выводит все экземпляры класса""" return self.objects.all().order_by('pk') def get_active_items(self): """Выводит активные экземпляры класса""" return self.objects.filter(is_active=True) def __str__(self): return f"{self.name}" def get_projects(self): """Выводит уникальные связанные экземпляры класса Project""" return self.projects.select_related().distinct('project_id') def get_active_projects(self): """Выводит уникальные связанные экземпляры класса Project""" return self.projects.select_related().distinct('project_id').filter( project__status='завершен') def get_works(self): return self.works.select_related().order_by('pk') def get_materials(self): return self.materials.select_related().order_by('pk') @cached_property def get_docs_cached(self): return self.docs.select_related() def get_researches(self): if settings.LOW_CACHE: key = 'researches' researches = cache.get(key) if researches is None: researches = self.get_docs_cached.filter(type__in=( 2, 3, )) cache.set(key, researches) return researches else: return self.get_docs_cached.filter(type__in=( 2, 3, )) def get_documents(self): if settings.LOW_CACHE: key = 'documents' documents = cache.get(key) if documents is None: documents = self.get_docs_cached.filter(type__in=( 1, 4, )) cache.set(key, documents) return documents else: return self.get_docs_cached.filter(type__in=( 1, 4, )) def get_publications(self): if settings.LOW_CACHE: key = 'publications' publications = cache.get(key) if publications is None: publications = self.get_docs_cached.filter(type__id=5) cache.set(key, publications) return publications else: return self.get_docs_cached.filter(type__id=5) class Meta: verbose_name = 'Техническое решение' verbose_name_plural = 'Технические решения'
class Offer(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) entity = models.ForeignKey(Entity, null=False, blank=False, related_name='offers', on_delete=CASCADE) title = models.CharField(null=True, blank=True, verbose_name='Nombre', max_length=250) description = models.TextField(null=True, blank=True, verbose_name='Descripción') banner_image = ProcessedImageField( null=True, blank=True, upload_to=RandomFileName('offers/'), verbose_name='Imagen principal', processors=[ResizeToFit(756, 512, upscale=False)], format='JPEG') banner_thumbnail = ImageSpecField( source='banner_image', processors=[ResizeToFill(400, 200, upscale=False)], format='JPEG', options={'quality': 70}) published_date = models.DateTimeField(auto_now_add=True) discount_percent = models.FloatField( null=True, blank=True, verbose_name='Porcentaje de descuento', default=0) discounted_price = models.FloatField(null=True, blank=True, verbose_name='Precio con descuento', default=0) active = models.BooleanField(default=True, null=False, verbose_name='Activa') begin_date = models.DateField(null=True, blank=True, verbose_name='Fecha de inicio') end_date = models.DateField(null=True, blank=True, verbose_name='Fecha de fin') objects = OffersManager() @property def status(self): today = datetime.date.today() if (self.begin_date > today) or (self.begin_date <= today and self.end_date >= today and self.active == False): return 'future' elif self.begin_date <= today and self.end_date >= today and self.active: return 'current' else: return 'past' class Meta: verbose_name = 'Oferta' verbose_name_plural = 'Ofertas' ordering = ['-published_date'] def __unicode__(self): return self.title if self.title else str(self.published_date)
class Profile(models.Model): ''' 该接口更新接受PUT方法 性别字段英文对应汉字为: male:男 female:女 提交的数据要用英文.获取时候api也是英文, 要客户端自己做下转换. ''' GENDER_CHOICES = (('', '未知'), ('male', '男'), ('female', '女')) owner = models.OneToOneField(settings.AUTH_USER_MODEL, unique=True, db_index=True, related_name='profile', on_delete=models.CASCADE) name = models.CharField(verbose_name=_(u'姓名'), blank=True, max_length=100, db_index=True) nick = models.CharField(verbose_name=_(u'昵称'), blank=True, null=True, max_length=100, db_index=True, default='') mobile = models.CharField(verbose_name=_(u'电话号码'), max_length=50, default='') gender = models.CharField(verbose_name=_(u'性别'), max_length=10, choices=GENDER_CHOICES, default=u'male') credit = models.IntegerField(_(u'用户积分'), default='50') avatar = ProcessedImageField(verbose_name=_(u'头像'), upload_to='avatar', processors=[ResizeToFill(320, 320)], format='JPEG', null=True, default='avatar/default.jpg') birthday = models.DateField(_(u'生日'), blank=True, null=True) balance = models.DecimalField(verbose_name=_(u'数字币余额'), max_digits=10, decimal_places=2, default=0.00) expired = models.DateTimeField(verbose_name=_(u'到期时间'), blank=True, null=True) # @property # def qrcode(self, request): # reverse('q', args=[short_url.encode_url(self.pk)], request=request) def __str__(self): return self.name def generate_key(self): return binascii.hexlify(os.urandom(20)).decode() class Meta: verbose_name = _(u'用户信息') verbose_name_plural = _(u'用户信息')
class Project(models.Model): """ Модель проекта строительства со статусом """ DEVELOPMENT = 'разработка' EXPERTISE = 'экспертиза' TENDER = 'аукцион' EXECUTING = 'строительство' FINISHING = 'сдача' PAYMENT = 'выплата' DONE = 'завершен' STATUS_CHOICES = ( (DEVELOPMENT, 'разработка'), (EXPERTISE, 'экспертиза'), (TENDER, 'аукцион'), (EXECUTING, 'строительство'), (FINISHING, 'сдача'), (PAYMENT, 'выплата'), (DONE, 'завершен'), ) name = models.CharField(verbose_name='Название проекта', max_length=256, unique=True) slug = models.SlugField(verbose_name='слаг', max_length=128, blank=True) description = models.TextField(verbose_name='описание', blank=True) image = ProcessedImageField(verbose_name='Аватар', upload_to='projects_images/avatars', processors=[ResizeToFill(530, 530)], default='projects_images/avatars/default_bridge.png') # image = models.ImageField(verbose_name='Аватар', upload_to='projects_images/avatars', # default='users/avatar/no_avatar.png', blank=True) status = models.CharField(verbose_name='Статус', max_length=24, choices=STATUS_CHOICES) creation_date = models.DateTimeField(verbose_name='создан', auto_now_add=True, auto_now=False) updated = models.DateTimeField(verbose_name='обновлен', auto_now=True) city = models.CharField(verbose_name='город', max_length=512, blank=True, null=True) address = models.CharField(verbose_name='адрес', max_length=512, blank=True, null=True) coordinate = models.CharField(verbose_name='координаты', max_length=34, null=True, blank=True) map_mark = models.SlugField(verbose_name='id метки на карте', max_length=128, blank=True) is_active = models.BooleanField(verbose_name='активен', default=False) def get_absolute_url(self): return reverse('projects:project', args=[str(self.pk)]) def get_absolute_discuss_url(self): return reverse('projects:project_discuss_items', args=[str(self.id)]) def __str__(self): return f"{self.name} ({self.city})" def get_pictures(self): return self.images.select_related() def get_products(self): return self.solutions.select_related() def get_companies(self): return self.companies.select_related() def get_managers(self): return self.managers.select_related() def get_finished_projects(self): pass def get_comments(self): return self.comments.select_related() class Meta: ordering = ('-updated',) verbose_name = 'Проект' verbose_name_plural = 'Проекты' default_permissions = ('add', 'change', 'delete')
class Entity(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user = models.OneToOneField(User, null=False, blank=False) city = models.ForeignKey(City, null=False, blank=False) cif = models.CharField(null=True, blank=True, verbose_name='NIF/CIF', max_length=50) email = models.CharField(null=False, blank=False, verbose_name='Email', max_length=250) name = models.CharField(null=True, blank=True, verbose_name='Nombre', max_length=250) description = models.TextField(null=True, blank=True, verbose_name='Descripción') short_description = models.TextField(null=True, blank=True, verbose_name='Descripción corta') phone_number = models.CharField(null=True, blank=True, verbose_name='Teléfono', max_length=25) address = models.TextField(null=True, blank=True, verbose_name='Dirección') logo = ProcessedImageField(null=True, blank=True, upload_to=RandomFileName('entities/'), verbose_name='Imagen de perfil', processors=[ResizeToFit(512, 512, upscale=False)], format='JPEG') logo_thumbnail = ImageSpecField(source='logo', processors=[ResizeToFill(150, 150, upscale=False)], format='JPEG', options={'quality': 70}) registered = models.DateTimeField(auto_now_add=True) latitude = models.FloatField(null=False, verbose_name='Latitud', default=0) longitude = models.FloatField(null=False, verbose_name='Longitud', default=0) categories = models.ManyToManyField(Category, blank=True, verbose_name='Categorías') # Currency fields bonus_percent_entity = models.FloatField(default=0, verbose_name='Porcentaje de bonificación a entidades', validators = [MinValueValidator(0), MaxValueValidator(100)]) bonus_percent_general = models.FloatField(default=0, verbose_name='Porcentaje de bonificación general', validators = [MinValueValidator(0), MaxValueValidator(100)]) max_percent_payment = models.FloatField(default=0, verbose_name='Máximo porcentaje de pago aceptado', validators = [MinValueValidator(0), MaxValueValidator(100)]) num_workers = models.IntegerField(default=0, verbose_name='Número de trabajadores', validators = [MinValueValidator(0)]) legal_form = models.TextField(null=True, blank=True, verbose_name='Formulario legal') # Social links facebook_link = models.CharField(null=True, blank=True, verbose_name='Página de Facebook', max_length=250) webpage_link = models.CharField(null=True, blank=True, verbose_name='Página web', max_length=250) twitter_link = models.CharField(null=True, blank=True, verbose_name='Perfil de Twitter', max_length=250) telegram_link = models.CharField(null=True, blank=True, verbose_name='Canal de Telegram', max_length=250) instagram_link = models.CharField(null=True, blank=True, verbose_name='Perfil de Instagram', max_length=250) inactive = models.BooleanField(default=False, verbose_name='Inactiva') hidden = models.BooleanField(default=False, verbose_name='Oculta') gallery = models.OneToOneField(Gallery, blank=True, null=True, on_delete=models.SET_NULL) objects = EntityManager() @property def display_name(self): return self.name @property def first_photo_url(self): if self.gallery and self.gallery.photos.count() > 0: image = self.gallery.photos.all().first() if image: return image.image.url return None @property def qr_code(self): return settings.BASESITE_URL + reverse('entity_qr_detail', kwargs={'pk': self.pk} ) def bonus(self, total_amount, bonusable_type=None): percent = self.bonus_percent_general if bonusable_type == 'entity': percent = self.bonus_percent_entity return round(total_amount * (percent / 100.0), 2) def max_accepted_currency(self, total_amount): return round(total_amount * (self.max_percent_payment / 100.0), 2) class Meta: verbose_name = 'Entidad' verbose_name_plural = 'Entidades' ordering = ['name'] def __unicode__(self): return self.name if self.name else 'Entidad'
class House(models.Model): HOUSE_TYPE_APARTMENT = 'AP' HOUSE_TYPE_HOUSING = 'HO' HOUSE_TYPE_ONEROOM = 'OR' HOUSE_TYPE_CHOICES = ( (HOUSE_TYPE_APARTMENT, '아파트'), (HOUSE_TYPE_HOUSING, '주택'), (HOUSE_TYPE_ONEROOM, '원룸'), ) house_type = models.CharField( verbose_name='숙소 타입', help_text='숙소를 선택 하세요. 디비에는 AP HO OR 등으로 저장.(기본값은 주택)', max_length=2, choices=HOUSE_TYPE_CHOICES, default=HOUSE_TYPE_HOUSING) name = models.CharField( verbose_name='숙소 이름', help_text='숙소의 이름을 입력하세요.', max_length=100, ) description = models.TextField( verbose_name='숙소 설명', help_text='숙소를 설명 하세요.', ) room = models.PositiveSmallIntegerField( verbose_name='방 수', help_text='방 수를 입력 하세요.', ) bed = models.PositiveSmallIntegerField( verbose_name='침대 수', help_text='침대 수를 입력 하세요.', ) bathroom = models.PositiveSmallIntegerField( verbose_name='욕실 수', help_text='욕실 수를 입력 하세요.', ) personnel = models.PositiveSmallIntegerField( verbose_name='숙박 인원', help_text='숙박 인원 입력 하세요.', ) amenities = models.ManyToManyField( 'Amenities', verbose_name='편의 물품', help_text='편의 물품의 종류를 선택하세요.', related_name='houses_with_amenities', blank=True, ) facilities = models.ManyToManyField( 'Facilities', verbose_name='편의 시설', help_text='편의 시설을 선택하세요.', related_name='houses_with_facilities', blank=True, ) minimum_check_in_duration = models.PositiveSmallIntegerField( verbose_name='최소 체크인 기간', help_text='체크인 할 수 있는 최소 기간을 입력 하세요.', ) maximum_check_in_duration = models.PositiveSmallIntegerField( verbose_name='최대 체크인 기간', help_text='체크인 할 수 있는 최대 기간을 입력 하세요.', ) maximum_check_in_range = models.PositiveSmallIntegerField( verbose_name='체크인 가능한 한계 시간', help_text='오늘을 기준으로 체크인이 가능한 날 수 적어주세요', ) price_per_night = models.PositiveIntegerField( verbose_name='하루 요금', help_text='하루 요금을 적어 주세요.', ) created_date = models.DateField( verbose_name='등록일', help_text='날짜로 입력 가능 합니다.(기본값은 오늘)', auto_now_add=True, ) modified_date = models.DateField(verbose_name='수정일', help_text='날짜로 입력 가능 합니다.(기본값은 오늘)', auto_now=True) disable_days = models.ManyToManyField( 'HouseDisableDay', verbose_name='쉬는날', help_text='쉬는날을 선택하세요.', related_name='houses_with_disable_day', blank=True, ) reserve_days = models.ManyToManyField( 'HouseReserveDay', verbose_name='예약된 날', help_text='이미 예약된 날입니다.', related_name='houses_with_reserve_day', blank=True, ) host = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name='호스트', help_text='숙소를 등록하는 호스트입니다.', related_name='houses_with_host', on_delete=models.CASCADE, ) country = models.CharField( verbose_name='국가', help_text='특별시/광역시/도 을 입력 하세요 (서울특별시)', max_length=100, blank=True, ) city = models.CharField( verbose_name='시/도', help_text='특별시/광역시/도 을 입력 하세요 (서울특별시)', max_length=100, blank=True, ) district = models.CharField( verbose_name='시/군/구', help_text='시/군/구 를 입력 하세요 (관악구)', max_length=100, blank=True, ) dong = models.CharField( verbose_name='동/읍/면', help_text='상세 주소를 입력 하세요 (신림동)', max_length=100, blank=True, ) address1 = models.CharField( verbose_name='상세 주소1', help_text='상세 주소1을 입력 하세요 (790-2)', max_length=100, blank=True, ) latitude = models.DecimalField( verbose_name='위도', help_text='위도를 소수점(14자리) 입력 가능 (xx.12345678901234)', decimal_places=14, max_digits=16) longitude = models.DecimalField( verbose_name='경도', help_text='경도를 소수점(14자리) 입력 가능 (xxx.12345678901234)', decimal_places=14, max_digits=17) img_cover = models.ImageField(upload_to=dynamic_img_cover_path, blank=True, default='') img_cover_thumbnail = ImageSpecField( source='img_cover', processors=[ResizeToFill(308, 206)], format='png', options={'quality': 100}, ) class Meta: verbose_name_plural = '숙소' def __str__(self): return f'{[self.pk]} {self.name}'
class User(AbstractBaseUser, PermissionsMixin): """ An abstract base class implementing a fully featured User model with admin-compliant permissions. Username and password are required. Other fields are optional. """ VARIFICATION_CHOICES = ( ('Email', 'Email'), ('Mobile', 'Mobile'), ) GENDER_CHOICES = ( ('male', 'male'), ('female', 'female'), ) username = models.CharField( _('username'), null=True, blank=True, max_length=30, help_text=_('Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.'), validators=[ validators.RegexValidator( r'^[\w.@+-]+$', _('Enter a valid username. This value may contain only ' 'letters, numbers ' 'and @/./+/-/_ characters.') ), ], error_messages={ 'unique': _("A user with that username already exists."), }, ) first_name = models.CharField(_('first name'), max_length=30) last_name = models.CharField(_('last name'), max_length=30) preferred_name = models.CharField(_('preferred name'), max_length=30) email = models.EmailField(_('email address'), unique=True, ) created_timestamp = models.DateTimeField(auto_now_add=True) modified_timestamp = models.DateTimeField(auto_now=True) created_by = models.ForeignKey("self", null=True, blank=True, related_name='created_user') modified_by = models.ForeignKey("self", null=True, blank=True, related_name='modified_user') verification = models.CharField(_('verification'), max_length=150, choices=VARIFICATION_CHOICES, default='1') gender = models.CharField(_('gender'), max_length=100, choices=GENDER_CHOICES, default='1') profile_pic = models.ImageField(upload_to='profile_pic', null=True, blank=True, ) profile_pic_thumbnail = ImageSpecField(source='profile_pic', processors=[ResizeToFill(245, 62)], format='JPEG', options={'quality': 60}) active_position = models.ForeignKey('positions.Positions', related_name='current_user_position',null=True,blank=True) is_staff = models.BooleanField( _('staff status'), default=False, help_text=_('Designates whether the user can log into this admin site.'), ) is_active = models.BooleanField( _('active'), default=True, help_text=_( 'Designates whether this user should be treated as active. ' 'Unselect this instead of deleting accounts.' ), ) is_varified = models.BooleanField( _('varified'), default=False, help_text=_( 'Designates whether this user has verified email/mobile. ' ), ) date_of_birth = models.DateField(_('date of birth'), default=timezone.now) start_date = models.DateTimeField(_('start date'), default=timezone.now) objects = UserManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['username'] def __str__(self): return self.username class Meta: verbose_name = _('user') verbose_name_plural = _('users') def get_full_name(self): """ Returns the first_name plus the last_name, with a space in between. """ full_name = '%s %s' % (self.first_name, self.last_name) return full_name.strip() def get_short_name(self): "Returns the short name for the user." return self.first_name def email_user(self, subject, message, from_email=None, **kwargs): """ Sends an email to this User. """ send_mail(subject, message, from_email, [self.email], **kwargs) def get_position(self): """ :return:high priority position of user """ all_positions = self.user_current_position.select_related('position').order_by('position__priority').first() if all_positions: return all_positions.position else: return None def has_permission(self,permission): arr = permission.split('.') module = arr[0] permi = arr[1] return permission
def test_resizetofill(): img = ResizeToFill(100, 100).process(create_image()) eq_(img.size, (100, 100))
class Member(BaseModel): """ 科研队伍 """ MEMBER_TYPE = ( ('teacher', '导师'), ('student', '学生'), ) GENDER_CHOICES = (("male", u"男"), ("female", u"女")) name = models.CharField('名称', help_text='名称', max_length=128, null=True, blank=True) birthday = models.DateField("出生年月", help_text="出生年月", null=True, blank=True) age = models.IntegerField('年龄', help_text="年龄", null=True, blank=True) gender = models.CharField('性别', help_text="性别", max_length=6, choices=GENDER_CHOICES, default="male") phone = models.CharField('电话', help_text="电话", null=True, blank=True, max_length=11) email = models.EmailField('邮箱', help_text="邮箱", max_length=100, null=True, blank=True) member_type = models.CharField("成员类型", help_text="成员类型", max_length=16, choices=MEMBER_TYPE, default=MEMBER_TYPE[1]) # 一对多 category = models.ForeignKey(Classification, verbose_name='成员分类', on_delete=models.CASCADE) member_title = models.CharField('成员头衔', help_text='成员头衔', max_length=128, null=True, blank=True) avatar = ProcessedImageField(verbose_name="头像", help_text='头像', upload_to=user_avatar_path, default='avatar/default.jpg', processors=[ResizeToFill(120, 120)], format='JPEG', options={'quality': 60}, null=True, blank=True) introduction = models.TextField('介绍', help_text='介绍', null=True, blank=True) # member_id = models.AutoField('索引', help_text='索引', primary_key=True) member_id = models.IntegerField('索引', help_text='索引', default=0) class Meta: verbose_name = "科研队伍" verbose_name_plural = verbose_name ordering = ['-create_time', 'name'] def __str__(self): return self.name
class Person(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) user = models.OneToOneField(User, null=False, blank=False) city = models.ForeignKey(City, null=False, blank=False) nif = models.CharField(null=True, blank=True, verbose_name='NIF/CIF', max_length=50) email = models.CharField(null=False, blank=False, verbose_name='Email', max_length=250) name = models.CharField(null=True, blank=True, verbose_name='Nombre', max_length=250) surname = models.CharField(null=True, blank=True, verbose_name='Apellidos', max_length=250) address = models.TextField(null=True, blank=True, verbose_name='Dirección') profile_image = ProcessedImageField( null=True, blank=True, upload_to=RandomFileName('profiles/'), verbose_name='Imagen de perfil', processors=[ResizeToFit(512, 512, upscale=False)], format='JPEG') profile_thumbnail = ImageSpecField( source='profile_image', processors=[ResizeToFill(150, 150, upscale=False)], format='JPEG', options={'quality': 70}) registered = models.DateTimeField(auto_now_add=True) fav_entities = models.ManyToManyField(Entity, blank=True, verbose_name="Favoritos") is_guest_account = models.BooleanField(default=False, verbose_name='Es usuario invitado') expiration_date = models.DateField(null=True, blank=True, verbose_name='Fecha de expiración') class Meta: verbose_name = 'Persona' verbose_name_plural = 'Personas' ordering = ['registered'] @property def display_name(self): return "{} {}".format(self.name, self.surname) @property def full_name(self): return '{} {}'.format(self.name if self.name else '', self.surname if self.surname else '') def __unicode__(self): return '{} {}'.format(self.name if self.name else '', self.surname if self.surname else '')
class Community(models.Model): moderated_object = GenericRelation(ModeratedObject, related_query_name='communities') creator = models.ForeignKey(User, on_delete=models.CASCADE, related_name='created_communities', null=False, blank=False) name = models.CharField(_('name'), max_length=settings.COMMUNITY_NAME_MAX_LENGTH, blank=False, null=False, unique=True, validators=(community_name_characters_validator,)) title = models.CharField(_('title'), max_length=settings.COMMUNITY_TITLE_MAX_LENGTH, blank=False, null=False, ) description = models.CharField(_('description'), max_length=settings.COMMUNITY_DESCRIPTION_MAX_LENGTH, blank=False, null=True, ) rules = models.TextField(_('rules'), max_length=settings.COMMUNITY_RULES_MAX_LENGTH, blank=False, null=True) avatar = ProcessedImageField(verbose_name=_('avatar'), blank=False, null=True, format='JPEG', options={'quality': 90}, processors=[ResizeToFill(500, 500)], upload_to=upload_to_community_avatar_directory) cover = ProcessedImageField(verbose_name=_('cover'), blank=False, null=True, format='JPEG', options={'quality': 90}, upload_to=upload_to_community_cover_directory, processors=[ResizeToFit(width=1024, upscale=False)]) created = models.DateTimeField(editable=False) starrers = models.ManyToManyField(User, related_name='favorite_communities') banned_users = models.ManyToManyField(User, related_name='banned_of_communities') COMMUNITY_TYPE_PRIVATE = 'T' COMMUNITY_TYPE_PUBLIC = 'P' COMMUNITY_TYPES = ( (COMMUNITY_TYPE_PUBLIC, 'Public'), (COMMUNITY_TYPE_PRIVATE, 'Private'), ) type = models.CharField(editable=False, blank=False, null=False, choices=COMMUNITY_TYPES, default='P', max_length=2) color = models.CharField(_('color'), max_length=COLOR_ATTR_MAX_LENGTH, blank=False, null=False, validators=[hex_color_validator]) user_adjective = models.CharField(_('user adjective'), max_length=settings.COMMUNITY_USER_ADJECTIVE_MAX_LENGTH, blank=False, null=True) users_adjective = models.CharField(_('users adjective'), max_length=settings.COMMUNITY_USERS_ADJECTIVE_MAX_LENGTH, blank=False, null=True) invites_enabled = models.BooleanField(_('invites enabled'), default=True) # This only happens if the community was reported and found with critical severity content is_deleted = models.BooleanField( _('is deleted'), default=False, ) class Meta: verbose_name_plural = 'communities' @classmethod def is_user_with_username_invited_to_community_with_name(cls, username, community_name): CommunityInvite = get_community_invite_model() return CommunityInvite.is_user_with_username_invited_to_community_with_name(username=username, community_name=community_name) @classmethod def is_user_with_username_member_of_community_with_name(cls, username, community_name): return cls.objects.filter(name=community_name, memberships__user__username=username).exists() @classmethod def is_user_with_username_administrator_of_community_with_name(cls, username, community_name): return cls.objects.filter(name=community_name, memberships__user__username=username, memberships__is_administrator=True).exists() @classmethod def is_user_with_username_moderator_of_community_with_name(cls, username, community_name): return cls.objects.filter(name=community_name, memberships__user__username=username, memberships__is_moderator=True).exists() @classmethod def is_user_with_username_banned_from_community_with_name(cls, username, community_name): return cls.objects.filter(name=community_name, banned_users__username=username).exists() @classmethod def is_community_with_name_invites_enabled(cls, community_name): return cls.objects.filter(name=community_name, invites_enabled=True).exists() @classmethod def is_community_with_name_private(cls, community_name): return cls.objects.filter(name=community_name, type='T').exists() @classmethod def community_with_name_exists(cls, community_name): query = Q(name=community_name, is_deleted=False) return cls.objects.filter(query).exists() @classmethod def get_community_with_name_for_user_with_id(cls, community_name, user_id): query = Q(name=community_name, is_deleted=False) query.add(~Q(banned_users__id=user_id), Q.AND) return cls.objects.get(query) @classmethod def search_communities_with_query(cls, query): query = cls._make_search_communities_query(query=query) return cls.objects.filter(query) @classmethod def _make_search_communities_query(cls, query): communities_query = Q(name__icontains=query) communities_query.add(Q(title__icontains=query), Q.OR) communities_query.add(Q(is_deleted=False), Q.AND) return communities_query @classmethod def get_trending_communities_for_user_with_id(cls, user_id, category_name=None): trending_communities_query = cls._make_trending_communities_query(category_name=category_name) trending_communities_query.add(~Q(banned_users__id=user_id), Q.AND) return cls._get_trending_communities_with_query(query=trending_communities_query) @classmethod def get_trending_communities(cls, category_name=None): trending_communities_query = cls._make_trending_communities_query(category_name=category_name) return cls._get_trending_communities_with_query(query=trending_communities_query) @classmethod def _get_trending_communities_with_query(cls, query): return cls.objects.annotate(Count('memberships')).filter(query).order_by( '-memberships__count', '-created') @classmethod def _make_trending_communities_query(cls, category_name=None): trending_communities_query = Q(type=cls.COMMUNITY_TYPE_PUBLIC, is_deleted=False) if category_name: trending_communities_query.add(Q(categories__name=category_name), Q.AND) return trending_communities_query @classmethod def create_community(cls, name, title, creator, color, type=None, user_adjective=None, users_adjective=None, avatar=None, cover=None, description=None, rules=None, categories_names=None, invites_enabled=None): # If its a private community and no invites_enabled if type is Community.COMMUNITY_TYPE_PRIVATE and invites_enabled is None: invites_enabled = False else: # The default for this field is not working when passed None? invites_enabled = True community = cls.objects.create(title=title, name=name, creator=creator, avatar=avatar, cover=cover, color=color, user_adjective=user_adjective, users_adjective=users_adjective, description=description, type=type, rules=rules, invites_enabled=invites_enabled) CommunityMembership.create_membership(user=creator, is_administrator=True, is_moderator=False, community=community) if categories_names: community.set_categories_with_names(categories_names=categories_names) community.save() return community @classmethod def is_name_taken(cls, name): return cls.objects.filter(name__iexact=name).exists() EXCLUDE_COMMUNITY_ADMINISTRATORS_KEYWORD = 'administrators' EXCLUDE_COMMUNITY_MODERATORS_KEYWORD = 'moderators' @classmethod def get_community_with_name_members(cls, community_name, members_max_id=None, exclude_keywords=None): community_members_query = Q(communities_memberships__community__name=community_name) if members_max_id: community_members_query.add(Q(id__lt=members_max_id), Q.AND) if exclude_keywords: community_members_query.add( cls._get_exclude_members_query_for_keywords(exclude_keywords=exclude_keywords), Q.AND) return User.objects.filter(community_members_query) @classmethod def search_community_with_name_members(cls, community_name, query, exclude_keywords=None): db_query = Q(communities_memberships__community__name=community_name) community_members_query = Q(communities_memberships__user__username__icontains=query) community_members_query.add(Q(communities_memberships__user__profile__name__icontains=query), Q.OR) db_query.add(community_members_query, Q.AND) if exclude_keywords: db_query.add( cls._get_exclude_members_query_for_keywords(exclude_keywords=exclude_keywords), Q.AND) return User.objects.filter(db_query) @classmethod def _get_exclude_members_query_for_keywords(cls, exclude_keywords): query = Q() if cls.EXCLUDE_COMMUNITY_ADMINISTRATORS_KEYWORD in exclude_keywords: query.add(Q(communities_memberships__is_administrator=False), Q.AND) if cls.EXCLUDE_COMMUNITY_MODERATORS_KEYWORD in exclude_keywords: query.add(Q(communities_memberships__is_moderator=False), Q.AND) return query @classmethod def get_community_with_name_administrators(cls, community_name, administrators_max_id=None): community_administrators_query = Q(communities_memberships__community__name=community_name, communities_memberships__is_administrator=True) if administrators_max_id: community_administrators_query.add(Q(communities_memberships__user__id__lt=administrators_max_id), Q.AND) return User.objects.filter(community_administrators_query) @classmethod def search_community_with_name_administrators(cls, community_name, query): db_query = Q(communities_memberships__community__name=community_name, communities_memberships__is_administrator=True) community_members_query = Q(communities_memberships__user__username__icontains=query) community_members_query.add(Q(communities_memberships__user__profile__name__icontains=query), Q.OR) db_query.add(community_members_query, Q.AND) return User.objects.filter(db_query) @classmethod def get_community_with_name_moderators(cls, community_name, moderators_max_id=None): community_moderators_query = Q(communities_memberships__community__name=community_name, communities_memberships__is_moderator=True) if moderators_max_id: community_moderators_query.add(Q(communities_memberships__user__id__lt=moderators_max_id), Q.AND) return User.objects.filter(community_moderators_query) @classmethod def search_community_with_name_moderators(cls, community_name, query): db_query = Q(communities_memberships__community__name=community_name, communities_memberships__is_moderator=True) community_members_query = Q(communities_memberships__user__username__icontains=query) community_members_query.add(Q(communities_memberships__user__profile__name__icontains=query), Q.OR) db_query.add(community_members_query, Q.AND) return User.objects.filter(db_query) @classmethod def get_community_with_name_banned_users(cls, community_name, users_max_id): community = Community.objects.get(name=community_name) community_members_query = Q() if users_max_id: community_members_query.add(Q(id__lt=users_max_id), Q.AND) return community.banned_users.filter(community_members_query) @classmethod def search_community_with_name_banned_users(cls, community_name, query): community = Community.objects.get(name=community_name) community_banned_users_query = Q(username__icontains=query) community_banned_users_query.add(Q(profile__name__icontains=query), Q.OR) return community.banned_users.filter(community_banned_users_query) @property def members_count(self): return self.memberships.all().count() def get_staff_members(self): User = get_user_model() staff_members_query = Q(communities_memberships__community_id=self.pk) staff_members_query.add( Q(communities_memberships__is_administrator=True) | Q(communities_memberships__is_moderator=True), Q.AND) return User.objects.filter(staff_members_query) def is_private(self): return self.type is self.COMMUNITY_TYPE_PRIVATE def update(self, title=None, name=None, description=None, color=None, type=None, user_adjective=None, users_adjective=None, rules=None, categories_names=None, invites_enabled=None): if name: self.name = name.lower() if title: self.title = title if type: self.type = type if color: self.color = color if description is not None: self.description = description if rules is not None: self.rules = rules if user_adjective is not None: self.user_adjective = user_adjective if users_adjective is not None: self.users_adjective = users_adjective if invites_enabled is not None: self.invites_enabled = invites_enabled if categories_names is not None: self.set_categories_with_names(categories_names=categories_names) self.save() def add_moderator(self, user): user_membership = self.memberships.get(user=user) user_membership.is_moderator = True user_membership.save() return user_membership def remove_moderator(self, user): user_membership = self.memberships.get(user=user) user_membership.is_moderator = False user_membership.save() return user_membership def add_administrator(self, user): user_membership = self.memberships.get(user=user) user_membership.is_administrator = True user_membership.save() return user_membership def remove_administrator(self, user): user_membership = self.memberships.get(user=user) user_membership.is_administrator = False user_membership.save() return user_membership def add_member(self, user): user_membership = CommunityMembership.create_membership(user=user, community=self) return user_membership def remove_member(self, user): user_membership = self.memberships.get(user=user) user_membership.delete() def set_categories_with_names(self, categories_names): self.clear_categories() Category = get_category_model() categories = Category.objects.filter(name__in=categories_names) self.categories.set(categories) def clear_categories(self): self.categories.clear() def create_invite(self, creator, invited_user): CommunityInvite = get_community_invite_model() return CommunityInvite.create_community_invite(creator=creator, invited_user=invited_user, community=self) def create_user_ban_log(self, source_user, target_user): return self._create_log(action_type='B', source_user=source_user, target_user=target_user) def create_user_unban_log(self, source_user, target_user): return self._create_log(action_type='U', source_user=source_user, target_user=target_user) def create_add_administrator_log(self, source_user, target_user): return self._create_log(action_type='AA', source_user=source_user, target_user=target_user) def create_remove_administrator_log(self, source_user, target_user): return self._create_log(action_type='RA', source_user=source_user, target_user=target_user) def create_add_moderator_log(self, source_user, target_user): return self._create_log(action_type='AM', source_user=source_user, target_user=target_user) def create_remove_moderator_log(self, source_user, target_user): return self._create_log(action_type='RM', source_user=source_user, target_user=target_user) def create_remove_post_log(self, source_user, target_user): return self._create_log(action_type='RP', source_user=source_user, target_user=target_user) def create_remove_post_comment_log(self, source_user, target_user): return self._create_log(action_type='RPC', source_user=source_user, target_user=target_user) def create_remove_post_comment_reply_log(self, source_user, target_user): return self._create_log(action_type='RPCR', source_user=source_user, target_user=target_user) def create_disable_post_comments_log(self, source_user, target_user, post): return self._create_log(action_type='DPC', post=post, source_user=source_user, target_user=target_user) def create_enable_post_comments_log(self, source_user, target_user, post): return self._create_log(action_type='EPC', post=post, source_user=source_user, target_user=target_user) def create_open_post_log(self, source_user, target_user, post): return self._create_log(action_type='OP', post=post, source_user=source_user, target_user=target_user) def create_close_post_log(self, source_user, target_user, post): return self._create_log(action_type='CP', post=post, source_user=source_user, target_user=target_user) def _create_log(self, action_type, source_user, target_user, post=None): CommunityModeratorUserActionLog = get_community_log_model() return CommunityModeratorUserActionLog.create_community_log(community=self, post=post, target_user=target_user, action_type=action_type, source_user=source_user) def save(self, *args, **kwargs): ''' On save, update timestamps ''' if not self.id: self.created = timezone.now() self.name = self.name.lower() if self.user_adjective: self.user_adjective = self.user_adjective.title() if self.users_adjective: self.users_adjective = self.users_adjective.title() return super(Community, self).save(*args, **kwargs) def soft_delete(self): self.is_deleted = True for post in self.posts.all().iterator(): post.soft_delete() self.save() def unsoft_delete(self): self.is_deleted = False for post in self.posts: post.unsoft_delete() self.save() def count_pending_moderated_objects(self): ModeratedObject = get_moderated_object_model() return self.moderated_objects.filter(status=ModeratedObject.STATUS_PENDING).count() def __str__(self): return self.name