def base_manager(self): base_manager_name = self.base_manager_name if not base_manager_name: # Get the first parent's base_manager_name if there's one. for parent in self.model.mro()[1:]: if hasattr(parent, '_meta'): if parent._base_manager.name != '_base_manager': base_manager_name = parent._base_manager.name break if base_manager_name: try: return self.managers_map[base_manager_name] except KeyError: raise ValueError( "%s has no manager named %r" % ( self.object_name, base_manager_name, ) ) manager = Manager() manager.name = '_base_manager' manager.model = self.model manager.auto_created = True return manager
def manager_class(model, queryset_class=None, class_name=None, use_for_related_fields=False): """ Return the manager class for model. If an optional queryset is given, returns a new class using the Manager.from_queryset() API. """ for cls in model.mro(): if not issubclass(model, Model): continue try: mgm = cls.objects break except AttributeError: pass else: mgm = Manager() if not isinstance(mgm, BaseManager): raise TypeError('unexpected manager class: %s' % mgm.__class__.__name__) if queryset_class is not None: mgm = mgm.from_queryset(queryset_class, class_name=class_name) if use_for_related_fields: mgm.use_for_related_fields = True return mgm
def test_consider_real_django_fields_only(self): id_ = ModelWithImpostorField._meta.get_field('id') with patch.object(mommy.Mommy, 'get_fields') as mock: f = Manager() f.name = 'foo' mock.return_value = [id_, f] try: mommy.make(ModelWithImpostorField) except TypeError: self.fail('TypeError raised')
def test_consider_real_django_fields_only(self): id_ = models.ModelWithImpostorField._meta.get_field("id") with patch.object(mommy.Mommy, "get_fields") as mock: f = Manager() f.name = "foo" mock.return_value = [id_, f] try: mommy.make(models.ModelWithImpostorField) except TypeError: self.fail("TypeError raised")
def base_manager(self): base_manager_name = self.base_manager_name if not base_manager_name: # Get the first parent's base_manager_name if there's one. for parent in self.model.mro()[1:]: if hasattr(parent, '_meta'): if parent._base_manager.name != '_base_manager': base_manager_name = parent._base_manager.name break if base_manager_name: try: return self.managers_map[base_manager_name] except KeyError: raise ValueError( "%s has no manager named %r" % ( self.object_name, base_manager_name, ) ) # Deprecation shim for `use_for_related_fields`. for i, base_manager_class in enumerate(self.default_manager.__class__.mro()): if getattr(base_manager_class, 'use_for_related_fields', False): if not getattr(base_manager_class, 'silence_use_for_related_fields_deprecation', False): warnings.warn( "use_for_related_fields is deprecated, instead " "set Meta.base_manager_name on '{}'.".format(self.model._meta.label), RemovedInDjango20Warning, 2 ) if i == 0: manager = self.default_manager else: manager = base_manager_class() manager.name = '_base_manager' manager.model = self.model return manager manager = Manager() manager.name = '_base_manager' manager.model = self.model manager.auto_created = True return manager
:type permission: str This method only works with permissions that are defined in :data:`~bridgekeeper.perms`; regular Django row-level permission checkers can't be invoked on the QuerySet level. It is a convenience wrapper around :meth:`~bridgekeeper.rules.Rule.filter`. """ try: rule = self.__permission_map[permission] except KeyError: raise ValueError("Permission {} does not exist, or is not " "registered in Bridgekeeper".format(permission)) return rule.filter(user, self) #: Django model manager using :class:`PermissionQuerySet`. #: #: For easy access to :class:`PermissionQuerySet` on your models, #: assign this manager to the ``objects`` property:: #: #: class MyModel(models.Model): #: ... # your fields here #: #: objects = PermissionManager() PermissionManager = Manager.from_queryset(PermissionQuerySet, class_name="PermissionManager")
class RobotManager(Manager.from_queryset(RobotQuerySet)): pass
class WrongActiveModel(models.ActiveModel): objects = Manager()
# Closest equivalent to SUM in Django from django.db.models import Manager result = Manager.raw( u"""select SUM(royalty_price*conversion_to_usd)from sales_raw where date='2012-06-01'""" )
class Profile(Model): user = FK(to=User, related_name='profiles', on_delete=CASCADE, default=1) status = CharField(max_length=50, choices=STATUS, default='npc') is_alive = BooleanField(default=True) is_active = BooleanField(default=True) image = ImageField( default='profile_pics/profile_default.jpg', upload_to='profile_pics', blank=True, null=True, storage=ReplaceFileStorage(), ) # Character name copied from Character (by signal) to avoid queries character_name_copy = CharField(max_length=100, blank=True, null=True) objects = Manager() non_gm = NonGMProfileManager() gm_controlled = GMControlledProfileManager() players = PlayerProfileManager() active_players = ActivePlayerProfileManager() npcs = NPCProfileManager() living = LivingProfileManager() contactables = ContactableProfileManager() class Meta: ordering = ['-status', '-is_active', 'character_name_copy'] def __str__(self): return self.character_name_copy or self.user.username def save(self, *args, **kwargs): first_save = True if not self.pk else False super().save(*args, **kwargs) if first_save and self.image: img = Image.open(self.image.path) if img.height > 300 or img.width > 300: output_size = (300, 300) img.thumbnail(output_size) img.save(self.image.path) def characters_all_known_annotated_if_indirectly(self): from prosoponomikon.models import Character if self.can_view_all: qs = Character.objects.all() else: known_dir = self.characters_known_directly.all() known_indir = self.characters_known_indirectly.all() known_only_indir = known_indir.exclude(id__in=known_dir) all_known = (known_dir | known_indir).distinct() qs = all_known.annotate(only_indirectly=Case( When(id__in=known_only_indir, then=Value(1)), default=Value(0), output_field=IntegerField(), )) qs = qs.prefetch_related('known_directly', 'known_indirectly') qs = qs.select_related('profile') qs = qs.exclude(id=self.character.id) return qs def locations_all_known_annotated_if_indirectly(self): if self.can_view_all: from toponomikon.models import Location qs = Location.objects.all() else: known_dir = self.locs_known_directly.all() known_indir = self.locs_known_indirectly.all() known_only_indir = known_indir.exclude(id__in=known_dir) all_known = (known_dir | known_indir).distinct() qs = all_known.annotate(only_indirectly=Case( When(id__in=known_only_indir, then=Value(1)), default=Value(0), output_field=IntegerField(), )) qs = qs.prefetch_related('known_directly', 'known_indirectly') qs = qs.select_related('main_image__image') return qs def characters_groups_authored_with_characters(self): characters = self.characters_all_known_annotated_if_indirectly() character_groups = self.character_groups_authored.all() character_groups = character_groups.prefetch_related( Prefetch('characters', queryset=characters), 'characters__profile__user', 'characters__known_directly', 'characters__known_indirectly', 'characters__first_name') return character_groups def skills_acquired_with_skill_levels(self): from rules.models import Skill, SkillLevel skills = Skill.objects.filter(skill_levels__acquired_by=self) skill_levels = SkillLevel.objects.filter(acquired_by=self) skills = skills.prefetch_related( Prefetch('skill_levels', queryset=skill_levels)) return skills.distinct() @property def undone_demands(self): demands = self.received_demands.exclude(author=self) return demands.exclude(is_done=True) @property def unseen_announcements(self): from communications.models import Announcement, Statement unseen_statements = Statement.objects.exclude(seen_by=self) return Announcement.objects.filter(known_directly=self, statements__in=unseen_statements) @property def unseen_debates(self): from communications.models import Statement, Debate unseen_remarks = Statement.objects.exclude(seen_by=self) return Debate.objects.filter(known_directly=self, statements__in=unseen_remarks).distinct() @property def can_view_all(self): return self.status in ['gm', 'spectator'] @property def can_action(self): return self.status in ['gm', 'player']
# Closest equivalent to SUM in Django from django.db.models import Manager result = Manager.raw(u"""select SUM(royalty_price*conversion_to_usd)from sales_raw where date='2012-06-01'""")
class RawMasterMixin(Model): """Base class for MasterMixin. **Users shouldn't use this class directly.**""" CQRS_ID = None """Unique CQRS identifier for all microservices.""" CQRS_PRODUCE = True """If false, no cqrs data is sent through the transport.""" CQRS_FIELDS = ALL_BASIC_FIELDS """ List of fields to include in the CQRS payload. You can also set the fields attribute to the special value '__all__' to indicate that all fields in the model should be used. """ CQRS_SERIALIZER = None """ Optional serializer used to create the instance representation. Must be expressed as a module dotted path string like `mymodule.serializers.MasterModelSerializer`. """ CQRS_TRACKED_FIELDS = None """ List of fields of the main model for which you want to track the changes and send the previous values via transport. You can also set the field attribute to the special value "__all__" to indicate that all fields in the model must be used. """ objects = Manager() cqrs = MasterManager() """Manager that adds needed CQRS queryset methods.""" cqrs_revision = IntegerField( default=0, help_text="This field must be incremented on any model update. " "It's used to for CQRS sync.", ) cqrs_updated = DateTimeField( auto_now=True, help_text="This field must be incremented on every model update. " "It's used to for CQRS sync.", ) class Meta: abstract = True @property def cqrs_saves_count(self): """Shows how many times this instance has been saved within the transaction.""" return getattr(self, '_cqrs_saves_count', 0) @property def is_initial_cqrs_save(self): """This flag is used to check if instance has already been registered for CQRS update.""" return self.cqrs_saves_count < 2 def reset_cqrs_saves_count(self): """This method is used to automatically reset instance CQRS counters on transaction commit. But this can also be used to control custom behaviour within transaction or in case of rollback, when several sequential transactions are used to change the same instance. """ if hasattr(self, '_cqrs_saves_count'): self._cqrs_saves_count = 0 def save(self, *args, **kwargs): using = kwargs.get('using') or router.db_for_write(self.__class__, instance=self) connection = transaction.get_connection(using) if connection.in_atomic_block: _cqrs_saves_count = self.cqrs_saves_count self._cqrs_saves_count = _cqrs_saves_count + 1 else: self.reset_cqrs_saves_count() if self.is_initial_cqrs_save and (not self._state.adding): self.cqrs_revision = F('cqrs_revision') + 1 self._save_tracked_fields() return super(RawMasterMixin, self).save(*args, **kwargs) def _save_tracked_fields(self): if hasattr(self, FIELDS_TRACKER_FIELD_NAME): tracker = getattr(self, FIELDS_TRACKER_FIELD_NAME) setattr(self, TRACKED_FIELDS_ATTR_NAME, tracker.changed()) def to_cqrs_dict(self, using=None, sync=False): """CQRS serialization for transport payload. :param using: The using argument can be used to force the database to use, defaults to None :type using: str, optional :type sync: bool, optional :return: The serialized instance data. :rtype: dict """ if self.CQRS_SERIALIZER: data = self._class_serialization(using, sync=sync) else: self._refresh_f_expr_values(using) data = self._common_serialization(using) return data def get_tracked_fields_data(self): """CQRS serialization for tracked fields to include in the transport payload. :return: Previous values for tracked fields. :rtype: dict """ return getattr(self, TRACKED_FIELDS_ATTR_NAME, None) def cqrs_sync(self, using=None, queue=None): """Manual instance synchronization. :param using: The using argument can be used to force the database to use, defaults to None :type using: str, optional :param queue: Syncing can be executed just for a single queue, defaults to None (all queues) :type queue: str, optional :return: True if instance can be synced, False otherwise. :rtype: bool """ if self._state.adding: return False if not self.CQRS_SERIALIZER: try: self.refresh_from_db() except self._meta.model.DoesNotExist: return False MasterSignals.post_save( self._meta.model, instance=self, using=using, queue=queue, sync=True, ) return True def is_sync_instance(self): """ This method can be overridden to apply syncing only to instances by some rules. For example, only objects with special status or after some creation date, etc. :return: True if this instance needs to be synced, False otherwise :rtype: bool """ return True @classmethod def relate_cqrs_serialization(cls, queryset): """ This method shoud be overriden to optimize database access for example using `select_related` and `prefetch_related` when related models must be included into the master model representation. :param queryset: The initial queryset. :type queryset: django.db.models.QuerySet :return: The optimized queryset. :rtype: django.db.models.QuerySet """ return queryset @classmethod def call_post_bulk_create(cls, instances, using=None): """ Post bulk create signal caller (django doesn't support it by default). .. code-block:: python # On PostgreSQL instances = model.objects.bulk_create(instances) model.call_post_bulk_create(instances) """ post_bulk_create.send(cls, instances=instances, using=using) @classmethod def call_post_update(cls, instances, using=None): """ Post bulk update signal caller (django doesn't support it by default). .. code-block:: python # Used automatically by cqrs.bulk_update() qs = model.objects.filter(k1=v1) model.cqrs.bulk_update(qs, k2=v2) """ post_update.send(cls, instances=instances, using=using) def _common_serialization(self, using): opts = self._meta if isinstance(self.CQRS_FIELDS, str) and self.CQRS_FIELDS == ALL_BASIC_FIELDS: included_fields = None else: included_fields = self.CQRS_FIELDS data = {} for f in opts.fields: if included_fields and (f.name not in included_fields): continue value = f.value_from_object(self) if value is not None and isinstance(f, (DateField, DateTimeField)): value = str(value) data[f.name] = value # We need to include additional fields for synchronisation, f.e. to prevent de-duplication data['cqrs_revision'] = self.cqrs_revision data['cqrs_updated'] = str(self.cqrs_updated) return data def _class_serialization(self, using, sync=False): if sync: instance = self else: db = using if using is not None else self._state.db qs = self.__class__._default_manager.using(db).filter(pk=self.pk) instance = self.relate_cqrs_serialization(qs).first() if not instance: raise RuntimeError( "Couldn't serialize CQRS class ({}).".format(self.CQRS_ID)) data = self._cqrs_serializer_cls(instance).data data['cqrs_revision'] = instance.cqrs_revision data['cqrs_updated'] = str(instance.cqrs_updated) return data def _refresh_f_expr_values(self, using): opts = self._meta fields_to_refresh = [] if isinstance(self.cqrs_revision, CombinedExpression): fields_to_refresh.append('cqrs_revision') if isinstance(self.CQRS_FIELDS, str) and self.CQRS_FIELDS == ALL_BASIC_FIELDS: included_fields = None else: included_fields = self.CQRS_FIELDS for f in opts.fields: if included_fields and (f.name not in included_fields): continue value = f.value_from_object(self) if value is not None and isinstance(value, CombinedExpression): fields_to_refresh.append(f.name) if fields_to_refresh: self.refresh_from_db(fields=fields_to_refresh) @property def _cqrs_serializer_cls(self): """ Serialization class loader. """ if hasattr(self.__class__, '_cqrs_serializer_class'): return self.__class__._cqrs_serializer_class try: serializer = import_string(self.CQRS_SERIALIZER) self.__class__._cqrs_serializer_class = serializer return serializer except ImportError: raise ImportError( "Model {}: CQRS_SERIALIZER can't be imported.".format( self.__class__)) def get_custom_cqrs_delete_data(self): """ This method should be overridden when additional data is needed in DELETE payload. """ pass
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, on_delete=models.CASCADE) root_department = models.ForeignKey(Department, null=True, related_name='descendant_units', on_delete=models.CASCADE) 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, on_delete=models.CASCADE) address_zip = models.CharField(max_length=10, null=True) data_source = models.CharField(max_length=50, 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=dict, null=True) # Cached fields for better performance root_service_nodes = models.CharField(max_length=50, null=True) objects = Manager() 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) def service_names(self): return "\n".join((service.name for service in self.services.all())) def highlight_names(self): UnitConnection = apps.get_model(app_label='services', model_name='UnitConnection') return "\n".join((connection.name for connection in self.connections.filter( section_type=UnitConnection.HIGHLIGHT_TYPE)))
class ExtManager(Manager.from_queryset(ExtQuerySet)): """ A subclassable Manager """ pass
class Post(Model): """ A Post can either be a Thread or Reply. It's a Reply iff it has a parent_thread. This is basically a poor man's Single Table Inheritance implementation: - CheckConstraints at least provide some guarantees. - thread_objects/reply_objects help avoid mistakes when querying one of the two. In return we can cleanly implement universal "link to post" regardless of if the post is a thread or reply. (if someone finds a cleaner way to model this in Django, I'm all ears tbh) """ subject = CharField(max_length=100, blank=True) comment = TextField(max_length=2500, blank=True) parent_thread = ForeignKey( "self", on_delete=CASCADE, null=True, blank=True, related_name="replies" ) board = ForeignKey( Board, on_delete=CASCADE, related_name="threads", null=True, blank=True ) created_at = DateTimeField(auto_now_add=True) # Of course there's pic and thumbnail pic = ImageField( upload_to=_upload_to, height_field="pic_height", width_field="pic_width", null=True, blank=True, ) pic_height = PositiveIntegerField(null=True) pic_width = PositiveIntegerField(null=True) thumbnail = ImageField( upload_to="thumbnails/", height_field="thumbnail_height", width_field="thumbnail_width", null=True, blank=True, ) thumbnail_height = PositiveIntegerField(null=True) thumbnail_width = PositiveIntegerField(null=True) objects = Manager() thread_objects = ThreadManager() reply_objects = ReplyManager() class Meta: db_table = "post" constraints = [ CheckConstraint( name="has_subject_iff_is_thread", check=( (Q(parent_thread__isnull=True) & ~Q(subject="")) | Q(parent_thread__isnull=False, subject="") ), ), CheckConstraint( name="has_board_iff_is_thread", check=( Q(parent_thread__isnull=True, board__isnull=False) | Q(parent_thread__isnull=False, board__isnull=True) ), ), CheckConstraint( name="has_pic_if_is_thread", check=( Q(parent_thread__isnull=True, pic__isnull=False) | Q(parent_thread__isnull=False) ), ), ] @property def is_thread(self): return self.parent_thread is None @property def pic_public_url(self): # BIIIIG assumption that I name each env's bucket after their domain name. # TODO make this support plain old FileSystemStorage backend. return ( f"https://{settings.AWS_STORAGE_BUCKET_NAME}/{self.pic.name}" if self.pic else "" ) def __str__(self): if self.is_thread: return f"Thread ({self.id}) {self.subject[:50]}" else: return f"Reply ({self.id}) {self.comment[:50]}" def get_absolute_url(self): if self.is_thread: thread_url = reverse( "thread", kwargs={"board_id": self.board_id, "thread_id": self.id} ) return f"{thread_url}#p{self.id}" else: thread = self.parent_thread thread_url = reverse( "thread", kwargs={"board_id": thread.board_id, "thread_id": thread.id} ) return f"{thread_url}#p{self.id}"
def register(model, model_document): default_manager = type(getattr(model, "objects", Manager())) if isinstance(default_manager, SearchManagerBase): # Already patched! # FIXME: Use the registry instead? return document_class = document_from_model_document(model, model_document) def _do_search(query, **options): """ Return a list of model instance_ids from the results of the specified query """ index = model_document.index() documents = index.search(query, document_class=document_class, **options) return [x.instance_id for x in documents] class SearchQueryset(models.QuerySet): def search(self, query, ordered_ids=None, **options): keys = _do_search(query, **options) if ordered_ids is not None: ordered_ids.extend(keys) return self.filter(pk__in=keys) def search_and_rank(self, query, **options): keys = _do_search(query, **options) return sorted(self.filter(pk__in=keys), key=lambda x: keys.index(x.pk)) class SearchManager(default_manager, SearchManagerBase): def get_queryset(self): qs = SearchQueryset(model, using=self._db) # Apply any filtering from any parent manager parent_qs = super().get_queryset() qs.query = parent_qs.query return qs def search(self, query, ordered_ids=None, **options): return self.get_queryset().search(query=query, ordered_ids=ordered_ids, **options) def search_and_rank(self, query, **options): return self.get_queryset().search_and_rank(query=query, **options) # FIXME: Is this safe? I feel like it should be but 'objects' is # a ManagerDescriptor so this might not be doing what I think it # is. model.objects.__class__ = SearchManager def delete_decorator(func): from djangae.contrib.search.models import DocumentRecord @wraps(func) def wrapped(self, *args, **kwargs): instance_id = self.pk func(self, *args, **kwargs) results = DocumentRecord.objects.filter( data__instance_id=instance_id).values_list("pk", flat=True) for result in results: model_document.index().remove(result) return wrapped model.delete = delete_decorator(model.delete) def save_decorator(func): @wraps(func) def wrapped(self, *args, **kwargs): func(self, *args, **kwargs) # Force un-indexing before re-index delete_decorator(lambda self: None)(self) attrs = { f: model._meta.get_field(f).value_from_object(self) for f in model_document._meta().all_fields } attrs["instance_id"] = self.pk doc = document_class(**attrs) model_document.index().add(doc) return wrapped model.save = save_decorator(model.save)
class MaterialManager(Manager.from_queryset(MaterialQuerySet)): pass
class Project(models.Model): STAGES = ( ('T', 'Tender'), ('J', 'Job In Hand'), ) STATUS = (('TR', 'Tender'), ('JC', 'JIH-Main Contractor'), ('J1', 'JIH-Stage 1'), ('J2', 'JIH-Stage 2'), ('J3', 'JIH-Stage 3'), ('J4', 'JIH-Stage 4'), ('CL', 'Closed'), ('CA', 'Cancelled')) reference_no = models.CharField(max_length=60, blank=True) name = models.CharField(max_length=60) stage = models.CharField(max_length=1, choices=STAGES, default='T') status = models.CharField(max_length=2, choices=STATUS, default='TR') segment = models.ForeignKey(ProjectSegment, on_delete=models.PROTECT) value = models.DecimalField(max_digits=20, decimal_places=3) location = models.TextField(blank=True) latitude = models.CharField(max_length=100, blank=True, null=True) longitude = models.CharField(max_length=100, blank=True, null=True) country = models.ForeignKey(Country, on_delete=models.PROTECT) companies_linked = models.ManyToManyField(Company, blank=True) intro_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT) intro_date = models.DateField() completion = models.DecimalField(max_digits=20, decimal_places=3, blank=True) exp_start_date = models.DateField(blank=True, null=True) exp_end_date = models.DateField(blank=True, null=True) main_contractor = models.ForeignKey(Customer, on_delete=models.PROTECT, related_name='main_contractors', blank=True, null=True) main_sub_contractor = models.ForeignKey(Customer, on_delete=models.PROTECT, related_name='sub_contractors', blank=True, null=True) client = models.ForeignKey(Customer, on_delete=models.PROTECT, related_name='clients', blank=True, null=True) design_consultant = models.ForeignKey(Customer, on_delete=models.PROTECT, related_name='design_consultants', blank=True, null=True) supervision_consultant = models.ForeignKey( Customer, on_delete=models.PROTECT, related_name='supervision_consultants', blank=True, null=True) objects = Manager() query_objects = CustomProjectQueryset.as_manager() class Meta: ordering = ['-id']
from django.db.models import Manager from .querysets import OrderableQueryset OrderableManager = Manager.from_queryset(OrderableQueryset)
class ReplicaMixin(Model, metaclass=ReplicaMeta): """ Mixin for the replica CQRS model, that will receive data updates from master. Models, using this mixin should be readonly, but this is not enforced (f.e. for admin). """ CQRS_ID = None """Unique CQRS identifier for all microservices.""" CQRS_MAPPING = None """Mapping of master data field name to replica model field name.""" CQRS_CUSTOM_SERIALIZATION = False """Set it to True to skip default data check.""" CQRS_SELECT_FOR_UPDATE = False """Set it to True to acquire lock on instance creation/update.""" CQRS_NO_DB_OPERATIONS = False """Set it to True to disable any default DB operations for this model.""" objects = Manager() cqrs = ReplicaManager() """Manager that adds needed CQRS queryset methods.""" cqrs_revision = IntegerField() cqrs_updated = DateTimeField() class Meta: abstract = True @classmethod def cqrs_save(cls, master_data, previous_data=None, sync=False): """ This method saves (creates or updates) model instance from CQRS master instance data. This method must not be overridden. Otherwise, sync checks need to be implemented manually. :param dict master_data: CQRS master instance data. :param dict previous_data: Previous values for tracked fields. :param bool sync: Sync package flag. :return: Model instance. :rtype: django.db.models.Model """ if cls.CQRS_NO_DB_OPERATIONS: raise NotImplementedError return cls.cqrs.save_instance(master_data, previous_data, sync) @classmethod def cqrs_create(cls, sync, mapped_data, previous_data=None): """ This method creates model instance from CQRS mapped instance data. It must be overridden by replicas of master models with custom serialization. :param bool sync: Sync package flag. :param dict mapped_data: CQRS mapped instance data. :param dict previous_data: Previous mapped values for tracked fields. :return: Model instance. :rtype: django.db.models.Model """ return cls._default_manager.create(**mapped_data) def cqrs_update(self, sync, mapped_data, previous_data=None): """ This method updates model instance from CQRS mapped instance data. It must be overridden by replicas of master models with custom serialization. :param bool sync: Sync package flag. :param dict mapped_data: CQRS mapped instance data. :param dict previous_data: Previous mapped values for tracked fields. :return: Model instance. :rtype: django.db.models.Model """ for key, value in mapped_data.items(): setattr(self, key, value) self.save() return self @classmethod def cqrs_delete(cls, master_data): """ This method deletes model instance from mapped CQRS master instance data. :param dict master_data: CQRS master instance data. :return: Flag, if delete operation is successful (even if nothing was deleted). :rtype: bool """ if cls.CQRS_NO_DB_OPERATIONS: raise NotImplementedError return cls.cqrs.delete_instance(master_data)
self._result_cache = list(self.iterator()) has_prefetch_relateds = len(self._prefetch_related_lookups) > 0 has_prefetch_models = len(self._our_prefetches) > 0 needs_prefetches = has_prefetch_relateds or has_prefetch_models if needs_prefetches and not self._prefetch_done: self._prefetch_related_objects() def iterator(self): iterator = super(InheritingQuerySet, self).iterator() relations_for_attrgetter = tuple(x.replace(LOOKUP_SEP, '.') for x in lookups_to_text(self._our_joins)) print(relations_for_attrgetter) attrgetters = tuple(attrgetter(x) for x in relations_for_attrgetter) for obj in iterator: yield dig_for_obj(obj=obj, attrgetters=attrgetters) # def _prefetch_related_objects(self): things = defaultdict(list) for index, thing in enumerate(self._result_cache, start=0): things[thing.__class__].append(thing) for klass, instances in things.items(): prefetches = self._prefetch_related_lookups[:] if klass in self._our_prefetches: prefetches.extend(self._our_prefetches[klass]) prefetch_related_objects(instances, prefetches) return None InheritingManager = Manager.from_queryset(InheritingQuerySet)
from mozillians.phonebook.validators import (validate_email, validate_twitter, validate_website, validate_username_not_url, validate_phone_number, validate_linkedin, validate_discord) from mozillians.users import get_languages_for_locale from mozillians.users.managers import (EMPLOYEES, MOZILLIANS, PRIVACY_CHOICES, PRIVACY_CHOICES_WITH_PRIVATE, PRIVATE, PUBLIC, PUBLIC_INDEXABLE_FIELDS, UserProfileQuerySet) from mozillians.users.tasks import send_userprofile_to_cis COUNTRIES = product_details.get_regions('en-US') AVATAR_SIZE = (300, 300) logger = logging.getLogger(__name__) ProfileManager = Manager.from_queryset(UserProfileQuerySet) def _calculate_photo_filename(instance, filename): """Generate a unique filename for uploaded photo.""" return os.path.join(settings.USER_AVATAR_DIR, str(uuid.uuid4()) + '.jpg') class PrivacyField(models.PositiveSmallIntegerField): def __init__(self, *args, **kwargs): myargs = {'default': MOZILLIANS, 'choices': PRIVACY_CHOICES} myargs.update(kwargs) super(PrivacyField, self).__init__(*args, **myargs)
class Content(models.Model): """ Common fields for all content files. Field info: status - privacy - PRIVATE, RESTRICTED, PUBLIC uid - unique random identifier string user - Django User, if relevant group - originalfilename - original filename filesize - file size of original file in bytes filetime - creation time of original file (e.g. EXIF timestamp) mimetype - Official MIME Media Type (e.g. image/jpeg, video/mp4) file - original file object preview - thumbnail object if relevant md5 - md5 of original file in hex-format sha1 - sha1 of original file in hex-format created - creation timestamp updated - last update timestamp opens - optional timestamp after which this Content is available expires - optional timestamp after which this object isn't available peers = Content's peers, if relevant parent - Content's parent Content, if relevant linktype - information of the type of child-parent relation point = models.PointField(geography=True, blank=True, null=True) It would be useful to save Uploadinfo, if the content is saved via HTTP like this: Uploadinfo.create(c, request).save() title - title text of this Content, a few words max caption - descriptive text of this Content author - Content author's name or nickname keywords - comma separated list of keywords/tags place - country, state/province, city, address or other textual description """ status = models.CharField(max_length=40, default="UNPROCESSED", editable=False) privacy = models.CharField(max_length=40, default="PRIVATE", verbose_name=_("Privacy"), choices=CONTENT_PRIVACY_CHOICES) uid = models.CharField(max_length=40, unique=True, db_index=True, default=get_uid, editable=False) user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL) group = models.ForeignKey(Group, blank=True, null=True, on_delete=models.SET_NULL) originalfilename = models.CharField(max_length=256, null=True, verbose_name=_("Original file name"), editable=False) filesize = models.IntegerField(null=True, editable=False) filetime = models.DateTimeField(blank=True, null=True, editable=False) mimetype = models.CharField(max_length=200, null=True, editable=False) file = models.FileField( storage=content_storage, upload_to=upload_split_by_1000) # , editable=False) preview = models.ImageField(storage=preview_storage, blank=True, upload_to=upload_split_by_1000, editable=False) md5 = models.CharField(max_length=32, null=True, editable=False) sha1 = models.CharField(max_length=40, null=True, editable=False) # license # origin, e.g. City museum, John Smith's photo album # Links and relations to other content files peers = models.ManyToManyField("self", blank=True, editable=False) parent = models.ForeignKey("self", blank=True, null=True, editable=False, on_delete=models.SET_NULL) linktype = models.CharField(max_length=500, blank=True) # point (geography) is used for e.g. distance calculations point = models.PointField(geography=True, blank=True, null=True) # point_geom (geometry) is used to enable e.g. within queries point_geom = models.PointField(blank=True, null=True) # TODO: to be removed (text fields are implemented elsewhere title = models.CharField(max_length=200, blank=True, verbose_name=_("Title")) # TODO: to be removed (text fields are implemented elsewhere caption = models.TextField(blank=True, verbose_name=_("Caption")) # TODO: to be removed (text fields are implemented elsewhere author = models.CharField(max_length=200, blank=True, verbose_name=_("Author")) # TODO: to be removed (text fields are implemented elsewhere keywords = models.CharField(max_length=500, blank=True, verbose_name=_("Keywords")) # TODO: to be removed (text fields are implemented elsewhere place = models.CharField(max_length=500, blank=True, verbose_name=_("Place")) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) opens = models.DateTimeField(blank=True, null=True) expires = models.DateTimeField(blank=True, null=True) # In referencing model add e.g. `files = GenericRelation(Content)` content_type = models.ForeignKey(ContentType, blank=True, null=True, default=None, on_delete=models.SET_NULL) object_id = models.PositiveIntegerField(blank=True, null=True) content_object = GenericForeignKey("content_type", "object_id") objects = Manager() # TODO: replace this with property stuff def latlon(self): # FIXME: should this be lonlat? return self.point.coords if self.point else None def set_latlon(self, lat, lon): p = Point(lon, lat) self.point = p self.point_geom = p def save_file(self, originalfilename: str, filecontent: UploadedFile | io.IOBase | str): """ Save filecontent to the filesystem and fill filename, filesize fields. filecontent may be - open file handle (opened in "rb"-mode) - existing file name (full path) - raw file data """ # TODO: check functionality with very large files self.originalfilename = os.path.basename(originalfilename) self.save() # Must save here to get self.id root, ext = os.path.splitext(originalfilename) filename = "{:09d}-{}{}".format(self.id, self.uid, ext.lower()) if isinstance(filecontent, UploadedFile): # Is an open file self.file.save(filename, File(filecontent)) elif isinstance(filecontent, io.IOBase): # Is open file self.file.save(filename, File(filecontent)) elif len(filecontent) < 1000 and os.path.isfile(filecontent): # Is existing file in file system with open(filecontent, "rb") as f: self.file.save(filename, File(f)) else: # Is just something in the memory self.file.save(filename, ContentFile(filecontent)) self.filesize = self.file.size self.save() def set_file( self, originalfilename: str, filecontent: UploadedFile | io.IOBase | str, mimetype: str = None, md5: str = None, sha1: str = None, ): """ Save Content.file and all it's related fields (filename, filesize, mimetype, md5, sha1). 'filecontent' may be - open file handle (opened in "rb"-mode) - existing file name (full path) - raw file data """ self.save_file(originalfilename, filecontent) if md5 is None or sha1 is None: self.md5, self.sha1 = filetools.hashfile(self.file.path) if mimetype: self.mimetype = mimetype else: info = filetools.fileinfo(self.file.path) mime = info["mimetype"] if mime: self.mimetype = mime else: self.mimetype = mimetypes.guess_type(originalfilename)[0] self.status = "PROCESSED" self.save() def set_fileinfo(self, mime: str = None): """ Create (or update if it already exists) Content.video/audio/image. Save width, height, duration, bitrate where appropriate. """ if mime is None: mime = self.mimetype obj = info = None if mime.startswith("image"): info = filetools.get_imageinfo(self.file.path) try: obj = self.image except Image.DoesNotExist: obj = Image(content=self) elif mime.startswith("video"): ffp = filetools.FFProbe(self.file.path) info = ffp.get_videoinfo() try: obj = self.video except Video.DoesNotExist: obj = Video(content=self) elif mime.startswith("audio"): ffp = filetools.FFProbe(self.file.path) info = ffp.get_audioinfo() try: obj = self.audio except Audio.DoesNotExist: obj = Audio(content=self) if obj and info: obj.set_metadata(info) obj.save() # Save new instance to the database # Save common data into self if "gps" in info: if self.point is None and "lat" in info["gps"]: self.set_latlon(info["gps"]["lat"], info["gps"]["lon"]) if self.filetime is None: if "gps" in info and "gpstime" in info["gps"]: self.filetime = info["gps"]["gpstime"] elif "creation_time" in info: self.filetime = info.get("creation_time") self.save() return obj def get_fileinfo(self): info = filetools.get_imageinfo(self.file.path) return info def generate_thumbnail(self): """ Generates the file to preview field for Videos, Images and PDFs. TODO: use only content.preview for thumbnails, not video/image.thumbnail """ # TODO: create generic thumbnail functions for video, image and pdf if self.mimetype.startswith("image"): try: im = PIL.Image.open(self.file.path) self.image.generate_thumb(im, self.image.thumbnail, THUMBNAIL_PARAMETERS) if self.image.thumbnail: self.preview = self.image.thumbnail self.save() except Image.DoesNotExist: pass elif self.mimetype.startswith("video"): try: if self.video.thumbnail: self.video.thumbnail.delete() self.video.generate_thumb() if self.video.thumbnail: self.preview = self.video.thumbnail self.save() except Video.DoesNotExist: pass elif self.mimetype.startswith("application/pdf"): fd, tmp_name = tempfile.mkstemp() # Remember to close fd! tmp_name += ".png" if do_pdf_thumbnail(self.file.path, tmp_name): postfix = "{}-{}-{}x{}".format(THUMBNAIL_PARAMETERS) filename = "{:09d}-{}-{}.png".format(self.id, self.uid, postfix) if os.path.isfile(tmp_name): with open(tmp_name, "rb") as f: self.preview.save(filename, File(f)) self.save() os.unlink(tmp_name) os.close(fd) else: return None def preview_ext(self): """Return the file extension of preview if it exists.""" # TODO: use pathlib if self.preview: root, ext = os.path.splitext(self.preview.path) else: root, ext = os.path.splitext(self.file.path) return ext.lstrip(".") def thumbnail(self): """ Return thumbnail if it exists. Thumbnail is always an image (can be shown with <img> tag). """ if self.preview: return self.preview if self.mimetype is None: return None elif self.mimetype.startswith("image"): try: return self.image.thumbnail except Image.DoesNotExist: return None elif self.mimetype.startswith("video"): # and self.video.thumbnail: try: return self.video.thumbnail except Video.DoesNotExist: return None else: return None def delete(self, *args, **kwargs): """ Set Content.status = "DELETE". Real deletion (referencing Videos and Audios, Video and AudioInstances) can be done later e.g. with some management command (not implemented yet). """ if kwargs.get("purge", False) is True and self.status == "DELETED": # TODO: # for f in [self.file, self.preview]: # if os.path.isfile(f): # os.unlink(f) # Delete all instance files too print("REALLY DELETING HERE ALL INSTANCES " "AND FILES FROM FILESYSTEM") # Super.delete else: self.status = "DELETED" self.save() def __str__(self): text = self.caption[:50] if self.caption else self.title return f'"{text}" {self.mimetype} ({self.filesize}B)'
class ContentRating(Model): """ This Model contains data related to one rated content, its overall rating, category ratings, word counts, and created and updated dates. """ from capstoneproject.models.models.category_rating import CategoryRating from capstoneproject.models.models.content import Content from capstoneproject.models.models.word_count import WordCount from capstoneproject.models.fields.rating_field import RatingField content = ForeignKey('Content', related_name='content_ratings', on_delete=CASCADE) rating = RatingField(default=0) category_ratings = ManyToManyField(CategoryRating, related_name='content_ratings') word_counts = ManyToManyField(WordCount, related_name='content_ratings') created = DateTimeField(auto_now_add=True) updated = DateTimeField(auto_now=True) content_ratings = Manager() def __str__(self): string = 'Rating\n' string += ' Content: {}\n'.format(self.content) string += ' Overall Rating: {}\n'.format(self.rating) string += ' Category Ratings: {}\n'.format(self.category_ratings) string += ' Word Counts: {}\n'.format(self.word_counts) string += ' Created: {} Updated: {}\n'.format( self.created, self.updated) return string def isRelated(self): """ Determines if any relatives rely on this model instance. :return: True if relatives rely on this model instance. """ return len(self.user_storage.all()) > 0 def isOrphaned(self): """ Determines if no relatives rely on this model instance. :return: True if no relatives rely on this model instance. """ return len(self.user_storage.all()) == 0 def delete_relatives(self): """ Deletes relatives to this model. :return: """ category_ratings = list(self.category_ratings.all()) self.category_ratings.clear() for category_rating in category_ratings: if category_rating.isOrphaned(): category_rating.delete() word_counts = list(self.word_counts.all()) self.word_counts.clear() for word_count in word_counts: if word_count.isOrphaned(): word_count.delete() def delete(self, *args, **kwargs): """ Deletes this model after deleting its relatives. :return: """ self.delete_relatives() old_content = self.content super().delete(*args, **kwargs) if old_content.isOrphaned(): old_content.delete() def get_category_ratings(self): """ Retrieves the CategoryRatings for this Category. :return: a dict of CategoryRatings. """ category_ratings = dict() for cat_rating in self.category_ratings.all(): category_ratings[cat_rating.category.name] = cat_rating.rating return category_ratings def _create_word_count_dict(self): """ Compile a dictionary of the WordCounts for this ContentRating. :return: a dictionary of Words and their Counts. """ word_counts = dict() for wc in self.word_counts.all(): word_counts[wc.word.name] = wc.count return word_counts def get_word_count_category(self): """ Compile a dictionary of the WordCounts for this ContentRating's \ Categories. :return: a dictionary of Categories, Words, and their Counts. """ word_count_category_dict = dict() from capstoneproject.models.models.category import Category for cat in Category.categories.all(): word_count_category_dict[cat.name] = dict() word_count_dict = self._create_word_count_dict() for word, count in word_count_dict.items(): from capstoneproject.models.models.word import Word word_model = Word.words.get_word(word=word) for word_cat in word_model.get_categories(): word_count_category_dict[word_cat][word] = count return word_count_category_dict class Meta: """Settings for the ContentRating model.""" default_manager_name = 'content_ratings'
class Project(models.Model): name = models.CharField(max_length=20, null=True, blank=True, help_text=name_help_text) app_name = models.CharField(max_length=200, null=True) full_name = models.CharField(max_length=300, unique=True, db_index=True) namespace_abbreviation = models.TextField(max_length=255, null=True, blank=True) namespace_uri = models.URLField(null=True, blank=True) namespace_description = models.TextField(null=True, blank=True) abstract = models.TextField(max_length=4000, null=True, blank=True, help_text=abstract_help_text) is_standard = models.BooleanField(default=False) attribution = models.TextField(max_length=1000, null=True, blank=True, help_text=attribution_help_text) website = models.URLField(null=True, blank=True) geographic = models.CharField(max_length=255, null=True, blank=True) temporal = models.CharField(max_length=255, null=True, blank=True) graphic = models.FileField(max_length=255, null=True, blank=True, upload_to="uploads/images/projects") occurrence_table_name = models.CharField( max_length=255, null=True, blank=True, help_text=occurrence_table_name_help_text) is_public = models.BooleanField( default=False, help_text="Is the raw data to be made publicly viewable?") display_summary_info = models.BooleanField( default=True, help_text=display_summary_info_help_text) display_fields = models.TextField(max_length=2000, default="['id',]", null=True, blank=True, help_text=display_fields_help_text) display_filter_fields = models.TextField( max_length=2000, default="[]", null=True, blank=True, help_text=display_filter_fields_help_text) # users = models.ManyToManyField(User, blank=True) terms = models.ManyToManyField('Term', through='ProjectTerm', blank=True) default_app_model = models.TextField(null=True, blank=True) #default_app_model = models.ForeignKey(ContentType, blank=True, null=True, on_delete=models.SET_NULL) #geom = models.PointField(srid=4326, blank=True, null=True) geom = models.CharField(max_length=255, null=True, blank=True) objects = Manager() class Meta: ordering = ["name"] verbose_name_plural = "Projects" verbose_name = "Project" def __str__(self): return self.full_name def record_count(self): if self.is_standard: return 0 else: model = apps.get_model(self.app_name, self.occurrence_table_name) return model.objects.count() def get_terms(self): """ Return a queryset of term objects associated with the project. To get a list of the term names as used by the project use, [term.get_mapping(self.app_name) for term in project_terms] :return: returns a queryset of term objects """ return Term.objects.filter( projects=self) # get a queryset of all terms for a project # [term.get_mapping(self.app_name) for term in project_terms] def get_properties(self): """ Get a list of all the property terms associated with the project. :return: returns a queryset of term objects """ # get a queryset of all terms for a project that are not classes, i.e. get all properties return Term.objects.filter(projects=self).exclude(is_class=True) # [term.get_mapping(self.app_name) for term in project_terms] def get_verbatim_categories(self): """ Get a list of all verbatim class terms associated project. :return: """ # get a queryset of all terms for a project that are classes return Term.objects.filter(projects=self).filter( is_class=True).order_by('term_ordering') def get_term_names(self): """ Get a list of the term names as used by the project :return: returns a list of term names """ term_qs = self.get_terms() return [term.get_mapping(self.app_name) for term in term_qs] def map_terms(self, proj): """ Map terms between two projects :param proj: accept either the project object or the project name as string :return: returns a dictionary with keys for each term in self and corresponding mapped values in proj """ result_dict = {} # initialize dictionary for result term_qs = self.get_terms( ) # get a list of terms related to the project if type( proj ) == str: # test proj argument and if it's a string fetch the object project = Project.objects.get(name=proj) else: project = proj for term in term_qs: try: ProjectTerm.objects.get(term=term, project=project) result_dict[term.get_mapping(self.name)] = term.get_mapping( project.name) except ProjectTerm.DoesNotExist: result_dict[term.get_mapping(self.name)] = None return result_dict
from django.db import connections from django.db.models import QuerySet, Manager from django.db.models.sql.datastructures import EmptyResultSet class FuzzyCountQuerySet(QuerySet): def fuzzy_count(self): cursor = connections[self.db].cursor() try: cursor.execute('SELECT count_estimate(%s);', (cursor.mogrify(*self.query.sql_with_params()).decode(), )) except EmptyResultSet: return 0 return int(cursor.fetchone()[0]) FuzzyCountManager = Manager.from_queryset(FuzzyCountQuerySet)
class Post(models.Model): # **************************************************************************************** seller = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=False, related_name="posts") # **************************************************************************************** title = models.CharField(max_length=100) # **************************************************************************************** def validate_ISBN(value): print(not (f'{value}'.isnumeric())) if (len(value) != 10 and len(value) != 13): raise ValidationError( f'number of digits in {value} is neither 10 nor 13', params={'value': value}, ) elif (not (f'{value}'.isnumeric())): raise ValidationError( f'{value} has non-numeric elements', params={'value': value}, ) ISBN = models.CharField(max_length=13, validators=[validate_ISBN]) # **************************************************************************************** author = models.CharField(max_length=50) # **************************************************************************************** description = models.TextField(max_length=350) # **************************************************************************************** image = models.ImageField(default='default_book.png', upload_to='book_pics') # **************************************************************************************** date_posted = models.DateTimeField(default=timezone.now) # UTC time # **************************************************************************************** edition = models.PositiveSmallIntegerField(blank=True, null=True) # **************************************************************************************** price = models.PositiveSmallIntegerField(default=0) # **************************************************************************************** swappable = models.BooleanField(default=False) # **************************************************************************************** IN_PROGRESS = "In progress" COMPLETE = "Complete" states = ( (IN_PROGRESS, "In progress"), (COMPLETE, "Complete"), ) transaction_state = models.CharField(max_length=50, choices=states, default=IN_PROGRESS) # **************************************************************************************** OTHER = "Other" TEXTBOOK = "Textbook" post_types = ( (OTHER, "Other"), (TEXTBOOK, "Textbook"), ) post_type = models.CharField(max_length=50, choices=post_types, default=OTHER) # **************************************************************************************** bookmarks = models.ManyToManyField(User, related_name="bookmarked_post", through='Bookmark') # **************************************************************************************** objects = Manager() def __str__(self): return (f"Seller: {self.seller} | Title: {self.title} | ID: {self.pk}") class Meta: verbose_name = 'Post' # Name the model will appear under in the Django Admin page. verbose_name_plural = 'Posts'
class FormatManager(Manager.from_queryset(FormatQuerySet)): # type: ignore use_for_related_fields = True
validate_website, validate_username_not_url, validate_phone_number, validate_linkedin, validate_discord) from mozillians.users import get_languages_for_locale from mozillians.users.managers import (EMPLOYEES, MOZILLIANS, PRIVACY_CHOICES, PRIVACY_CHOICES_WITH_PRIVATE, PRIVATE, PUBLIC, PUBLIC_INDEXABLE_FIELDS, UserProfileQuerySet) from mozillians.users.tasks import send_userprofile_to_cis COUNTRIES = product_details.get_regions('en-US') AVATAR_SIZE = (300, 300) logger = logging.getLogger(__name__) ProfileManager = Manager.from_queryset(UserProfileQuerySet) def _calculate_photo_filename(instance, filename): """Generate a unique filename for uploaded photo.""" return os.path.join(settings.USER_AVATAR_DIR, str(uuid.uuid4()) + '.jpg') class PrivacyField(models.PositiveSmallIntegerField): def __init__(self, *args, **kwargs): myargs = {'default': MOZILLIANS, 'choices': PRIVACY_CHOICES} myargs.update(kwargs) super(PrivacyField, self).__init__(*args, **myargs) class UserProfilePrivacyModel(models.Model):
class Event(Model): title = CharField(_("title"), max_length=254) description = TextField(_("description"), blank=True, null=True) location = CharField(_("location"), max_length=254) type = ForeignKey(EventType, on_delete=models.CASCADE, verbose_name=_("event type")) active = BooleanField(default=False) mail_updates = BooleanField(_("send updates via mail"), default=True) objects = ActiveManager() all_objects = Manager() class Meta: verbose_name = _("event") verbose_name_plural = _("events") permissions = [("view_past_event", _("Can view past events"))] db_table = "event" def get_start_time(self): # use shifts.all() in case the shifts have been prefetched return min(s.start_time for s in self.shifts.all()) if self.shifts.all() else None def get_end_time(self): return max(s.end_time for s in self.shifts.all()) if self.shifts.all() else None def get_signup_stats(self) -> "SignupStats": """Return a SignupStats object aggregated over all shifts of this event, or a default""" from ephios.core.signup import SignupStats default_for_no_shifts = SignupStats(0, 0, None, None) return functools.reduce( operator.add, [ shift.signup_method.get_signup_stats() for shift in self.shifts.all() ] or [default_for_no_shifts], ) def __str__(self): return str(self.title) def get_canonical_slug(self): return slugify(self.title) def get_absolute_url(self): from django.urls import reverse return reverse("core:event_detail", kwargs=dict(pk=self.id, slug=self.get_canonical_slug())) def activate(self): from ephios.core import mail if not self.active: with transaction.atomic(): self.active = True self.full_clean() self.save() if self.mail_updates: mail.new_event(self)
class SharedSlugSpace(Model): objects = Manager() name = CharField(max_length=200) # ensure that any subclasses use the base model's manager for testing # slug uniqueness slug = AutoSlugField(populate_from='name', unique=True, manager=objects)
class CommentQuerySet(QuerySet): DEFAULT_COLUMNS = { 'content': 'text', 'author__name': 'author', 'conversation__title': 'conversation', } def approved(self): return self.filter(status=self.model.STATUS.approved) def pending(self): return self.filter(status=self.model.STATUS.pending) def rejected(self): return self.filter(status=self.model.STATUS.rejected) def statistics(self): return [x.statistics() for x in self] def display_dataframe(self, columns=DEFAULT_COLUMNS): qs = self.values_list('id', *columns.keys()) df = pd.DataFrame(list(qs), columns=['id', *columns.values()]) df.index = df.pop('id') return df ConversationManager = Manager.from_queryset(ConversationQuerySet, 'ConversationManager') CommentManager = Manager.from_queryset(CommentQuerySet, 'CommentManager') BoogieManager = Manager.from_queryset(QuerySet)
class Manager(DjangoManager.from_queryset(QuerySet)): pass
from django.db import connections from django.db.models import QuerySet, Manager from django.db.models.sql.datastructures import EmptyResultSet class FuzzyCountQuerySet(QuerySet): def fuzzy_count(self): cursor = connections[self.db].cursor() try: cursor.execute( 'SELECT count_estimate(%s);', (cursor.mogrify(*self.query.sql_with_params()).decode(), )) except EmptyResultSet: return 0 return int(cursor.fetchone()[0]) FuzzyCountManager = Manager.from_queryset(FuzzyCountQuerySet)
class Feriado(Model): feriado = CharField(max_length=100) data = DateField() objetos = Manager()
class Anno(Model): created = DateTimeField(db_index=True, auto_now_add=True, null=False) modified = DateTimeField(auto_now=True, null=False) schema_version = CharField( max_length=128, null=False, default=CATCH_CURRENT_SCHEMA_VERSION) creator_id = CharField(max_length=128, null=False) creator_name = CharField(max_length=128, null=False) anno_id = CharField(max_length=128, primary_key=True) # soft delete anno_deleted = BooleanField(db_index=True, default=False) # comment to a parent annotation anno_reply_to = ForeignKey('Anno', null=True, blank=True, on_delete=CASCADE) anno_tags = ManyToManyField('Tag', blank=True) # permissions are lists of user_ids, blank means public can_read = ArrayField(CharField(max_length=128), null=True, default=list) can_update = ArrayField(CharField(max_length=128), null=True, default=list) can_delete = ArrayField(CharField(max_length=128), null=True, default=list) can_admin = ArrayField(CharField(max_length=128), null=True, default=list) # support for only one _text_ body # max length for body_text is restricted in django request # in settings.DATA_UPLOAD_MAX_MEMORY_SIZE (default is 2.5Mb) body_text = TextField(null=True) # body_format is a mime type, like 'text/html', 'text/richtext', # 'application/rtf', 'application/x-rtf', etc # note that rich text can have binaries embedded (like images) body_format = CharField(max_length=128, null=False, default='text/html') target_type = CharField( max_length=16, choices=RESOURCE_TYPE_CHOICES, default=RESOURCE_TYPE_UNDEFINED) raw = JSONField() # default model manager objects = Manager() # TODO: manager for custom searches # http://stackoverflow.com/a/30941292 # _c_manager = getattr(settings, 'CATCHA_CUSTOM_MANANGER', None) # if _c_manager: # module_name, class_name = _c_manager.rsplit('.', 1) # CustomClass = getattr(importlib.import_modUle(module_name), class_name) # custom_manager = CustomClass() # else: # custom_manager = SearchManager() custom_manager = SearchManager() class Meta: indexes = [ GinIndex( fields=['raw'], name='anno_raw_gin', ), ] def __repr__(self): return '({}_{})'.format(self.schema_version, self.anno_id) def __str__(self): return self.__repr__() @property def total_replies(self): #return self.anno_set.count() return self.anno_set.all().filter(anno_deleted=False).count() @property def replies(self): # exclude deleted replies! # # ATT: this makes marked_for_deletion replies _unaccessible via API_ # return self.anno_set.all().filter(anno_deleted=False).order_by('created') @property def total_targets(self): return self.target_set.count() @property def targets(self): return self.target_set.all() @property def serialized(self): s = self.raw.copy() s['totalReplies'] = self.total_replies s['created'] = self.created.replace(microsecond=0).isoformat() s['modified'] = self.modified.replace(microsecond=0).isoformat() s['id'] = self.anno_id return s def permissions_for_user(self, user): '''list of ops user is allowed to perform in this anno instance. note: implementation of this method makes it impossible to have update, delete, admin open to public. ''' permissions = [] if not self.can_read or user in self.can_read: permissions.append('can_read') if user in self.can_update: permissions.append('can_update') if user in self.can_delete: permissions.append('can_delete') if user in self.can_admin: permissions.append('can_admin') return permissions def mark_as_deleted(self, *args, **kwargs): ''' overwrite delete to perform a soft delete. ''' self.anno_deleted = True def has_permission_for(self, op, user_id): '''check if user has permission for operation.''' if op == 'read': if not self.can_read or user_id in self.can_read: return True permission = getattr(self, 'can_{}'.format(op)) if permission is not None: return (user_id in permission) else: return False
class BMC(CleanSave, TimestampedModel): """A `BMC` represents an existing 'baseboard management controller'. For practical purposes in MAAS, this is any addressable device that can control the power state of Nodes. The BMC associated with a Node is the one expected to control its power. Power parameters that apply to all nodes controlled by a BMC are stored here in the BMC. Those that are specific to different Nodes on the same BMC are stored in the Node model instances. :ivar ip_address: This `BMC`'s IP Address. :ivar power_type: The power type defines which type of BMC this is. Its value must match a power driver class name. :ivar power_parameters: Some JSON containing arbitrary parameters this BMC's power driver requires to function. :ivar objects: The :class:`BMCManager`. """ class Meta(DefaultMeta): unique_together = ("power_type", "power_parameters", "ip_address") objects = Manager() bmcs = BMCManager() bmc_type = IntegerField(choices=BMC_TYPE_CHOICES, editable=False, default=BMC_TYPE.DEFAULT) ip_address = ForeignKey(StaticIPAddress, default=None, blank=True, null=True, editable=False, on_delete=SET_NULL) # The possible choices for this field depend on the power types advertised # by the rack controllers. This needs to be populated on the fly, in # forms.py, each time the form to edit a node is instantiated. power_type = CharField(max_length=10, null=False, blank=True, default='') # JSON-encoded set of parameters for power control, limited to 32kiB when # encoded as JSON. These apply to all Nodes controlled by this BMC. power_parameters = JSONObjectField(max_length=(2**15), blank=True, default='') # Rack controllers that have access to the BMC by routing instead of # having direct layer 2 access. routable_rack_controllers = ManyToManyField( "RackController", blank=True, editable=True, through="BMCRoutableRackControllerRelationship", related_name="routable_bmcs") # Values for Pod's. # 1. Name of the Pod. # 2. List of architectures that a Pod supports. # 3. Capabilities that the Pod supports. # 4. Total cores in the Pod. # 5. Fastest CPU speed in the Pod. # 6. Total amount of memory in the Pod. # 7. Total about in bytes of local storage available in the Pod. # 8. Total number of available local disks in the Pod. # 9. The resource pool machines in the pod should belong to by default. name = CharField(max_length=255, default='', blank=True, unique=True) architectures = ArrayField(TextField(), blank=True, null=True, default=list) capabilities = ArrayField(TextField(), blank=True, null=True, default=list) cores = IntegerField(blank=False, null=False, default=0) cpu_speed = IntegerField(blank=False, null=False, default=0) # MHz memory = IntegerField(blank=False, null=False, default=0) local_storage = BigIntegerField( # Bytes blank=False, null=False, default=0) local_disks = IntegerField(blank=False, null=False, default=-1) iscsi_storage = BigIntegerField( # Bytes blank=False, null=False, default=-1) default_pool = ForeignKey(ResourcePool, default=None, null=True, blank=True, editable=True, on_delete=PROTECT) def __str__(self): return "%s (%s)" % (self.id, self.ip_address if self.ip_address else "No IP") def _as(self, model): """Create a `model` that shares underlying storage with `self`. In other words, the newly returned object will be an instance of `model` and its `__dict__` will be `self.__dict__`. Not a copy, but a reference to, so that changes to one will be reflected in the other. """ new = object.__new__(model) new.__dict__ = self.__dict__ return new def as_bmc(self): """Return a reference to self that behaves as a `BMC`.""" return self._as(BMC) def as_pod(self): """Return a reference to self that behaves as a `Pod`.""" return self._as(Pod) _as_self = { BMC_TYPE.BMC: as_bmc, BMC_TYPE.POD: as_pod, } def as_self(self): """Return a reference to self that behaves as its own type.""" return self._as_self[self.bmc_type](self) def delete(self): """Delete this BMC.""" maaslog.info("%s: Deleting BMC", self) super(BMC, self).delete() def save(self, *args, **kwargs): """Save this BMC.""" super(BMC, self).save(*args, **kwargs) # We let name be blank for the initial save, but fix it before the # save completes. This is because set_random_name() operates by # trying to re-save the BMC with a random hostname, and retrying until # there is no conflict. if self.name == '': self.set_random_name() def set_random_name(self): """Set a random `name`.""" while True: self.name = petname.Generate(2, "-") try: self.save() except ValidationError: pass else: break def clean(self): """ Update our ip_address if the address extracted from our power parameters has changed. """ new_ip = BMC.extract_ip_address(self.power_type, self.power_parameters) current_ip = None if self.ip_address is None else self.ip_address.ip # Set the ip_address field. If we have a bracketed address, assume # it's IPv6, and strip the brackets. if new_ip and new_ip.startswith('[') and new_ip.endswith(']'): new_ip = new_ip[1:-1] if new_ip != current_ip: if new_ip is None: self.ip_address = None else: # Update or create a StaticIPAddress for the new IP. try: # This atomic block ensures that an exception within will # roll back only this block's DB changes. This allows us to # swallow exceptions in here and keep all changes made # before or after this block is executed. with transaction.atomic(): subnet = Subnet.objects.get_best_subnet_for_ip(new_ip) (self.ip_address, _) = StaticIPAddress.objects.get_or_create( ip=new_ip, defaults={ 'alloc_type': IPADDRESS_TYPE.STICKY, 'subnet': subnet, }) except Exception as error: maaslog.info( "BMC could not save extracted IP " "address '%s': '%s'", new_ip, error) @staticmethod def scope_power_parameters(power_type, power_params): """Separate the global, bmc related power_parameters from the local, node-specific ones.""" if not power_type: # If there is no power type, treat all params as node params. return ({}, power_params) power_driver = PowerDriverRegistry.get_item(power_type) if power_driver is None: # If there is no power driver, treat all params as node params. return ({}, power_params) power_fields = power_driver.settings if not power_fields: # If there is no parameter info, treat all params as node params. return ({}, power_params) bmc_params = {} node_params = {} for param_name in power_params: power_field = power_driver.get_setting(param_name) if (power_field and power_field.get('scope') == SETTING_SCOPE.BMC): bmc_params[param_name] = power_params[param_name] else: node_params[param_name] = power_params[param_name] return (bmc_params, node_params) @staticmethod def extract_ip_address(power_type, power_parameters): """ Extract the ip_address from the power_parameters. If there is no power_type, no power_parameters, or no valid value provided in the power_address field, returns None. """ if not power_type or not power_parameters: # Nothing to extract. return None power_driver = PowerDriverRegistry.get_item(power_type) if power_driver is None: maaslog.warning("No power driver for power type %s" % power_type) return None power_type_parameters = power_driver.settings if not power_type_parameters: maaslog.warning("No power driver settings for power type %s" % power_type) return None ip_extractor = power_driver.ip_extractor if not ip_extractor: maaslog.info("No IP extractor configured for power type %s. " "IP will not be extracted." % power_type) return None field_value = power_parameters.get(ip_extractor.get('field_name')) if not field_value: maaslog.warning("IP extractor field_value missing for %s" % power_type) return None extraction_pattern = ip_extractor.get('pattern') if not extraction_pattern: maaslog.warning("IP extractor extraction_pattern missing for %s" % power_type) return None match = re.match(extraction_pattern, field_value) if match: return match.group('address') # no match found - return None return None def get_layer2_usable_rack_controllers(self, with_connection=True): """Return a list of `RackController`'s that have the ability to access this `BMC` directly through a layer 2 connection.""" ip_address = self.ip_address if ip_address is None or ip_address.ip is None or ip_address.ip == '': return set() # The BMC has a valid StaticIPAddress set. Make sure that the subnet # is correct for that BMC. subnet = Subnet.objects.get_best_subnet_for_ip(ip_address.ip) if subnet is not None and self.ip_address.subnet_id != subnet.id: self.ip_address.subnet = subnet self.ip_address.save() # Circular imports. from maasserver.models.node import RackController return RackController.objects.filter_by_url_accessible( ip_address.ip, with_connection=with_connection) def get_routable_usable_rack_controllers(self, with_connection=True): """Return a list of `RackController`'s that have the ability to access this `BMC` through a route on the rack controller.""" routable_racks = [ relationship.rack_controller for relationship in (self.routable_rack_relationships.all( ).select_related("rack_controller")) if relationship.routable ] if with_connection: conn_rack_ids = [client.ident for client in getAllClients()] return [ rack for rack in routable_racks if rack.system_id in conn_rack_ids ] else: return routable_racks def get_usable_rack_controllers(self, with_connection=True): """Return a list of `RackController`'s that have the ability to access this `BMC` either using layer2 or routable if no layer2 are available. """ racks = self.get_layer2_usable_rack_controllers( with_connection=with_connection) if len(racks) == 0: # No layer2 routable rack controllers. Use routable rack # controllers. racks = self.get_routable_usable_rack_controllers( with_connection=with_connection) return racks def get_client_identifiers(self): """Return a list of identifiers that can be used to get the `rpc.common.Client` for this `BMC`. :raise NoBMCAccessError: Raised when no rack controllers have access to this `BMC`. """ rack_controllers = self.get_usable_rack_controllers() identifers = [controller.system_id for controller in rack_controllers] return identifers def is_accessible(self): """If the BMC is accessible by at least one rack controller.""" racks = self.get_usable_rack_controllers(with_connection=False) return len(racks) > 0 def update_routable_racks(self, routable_racks_ids, non_routable_racks_ids): """Set the `routable_rack_controllers` relationship to the new information.""" BMCRoutableRackControllerRelationship.objects.filter( bmc=self.as_bmc()).delete() self._create_racks_relationship(routable_racks_ids, True) self._create_racks_relationship(non_routable_racks_ids, False) def _create_racks_relationship(self, rack_ids, routable): """Create `BMCRoutableRackControllerRelationship` for list of `rack_ids` and wether they are `routable`.""" # Circular imports. from maasserver.models.node import RackController for rack_id in rack_ids: try: rack = RackController.objects.get(system_id=rack_id) except RackController.DoesNotExist: # Possible it was delete before this call, but very very rare. pass BMCRoutableRackControllerRelationship(bmc=self, rack_controller=rack, routable=routable).save()
class MessageManager(Manager.from_queryset(MessageQuerySet)): """Message manager""" pass
# -*- coding: utf-8 -*- from __future__ import absolute_import from django.db.models import Manager # Need to substitute model_utils in Django<1.7 try: Manager.from_queryset except AttributeError: from model_utils.managers import PassThroughManager as Manager Manager.from_queryset = Manager.for_queryset_class from .queryset import CursorQueryset CursorManager = Manager.from_queryset(CursorQueryset)
class MutationManager(Manager.from_queryset(MutationQuerySet)): def get_by_natural_key(self, genome, locus, name): return self.get(gene_locus__genome__code=genome, gene_locus__name=locus, name=name)
# -*- coding: utf-8 -*- """Manager and queryset for the redirects app.""" from django.db.models import Manager from django.db.models.query import QuerySet class RedirectQuerySet(QuerySet): def get_redirect_path(self, path, language=None, version_slug=None): for redirect in self.select_related('project'): new_path = redirect.get_redirect_path( path=path, language=language, version_slug=version_slug, ) if new_path: return new_path return None RedirectManager = Manager.from_queryset(RedirectQuerySet)
class Order_basic(models.Model): """订单基本信息""" # 订单号 orderId = models.CharField(max_length=100, verbose_name=_("支付流水号")) # 用户,一个用户多个收货地址 consumer = models.ForeignKey( User, verbose_name=_('用户名'), max_length=50, related_name='order_basic', on_delete=models.CASCADE, ) # 收货地址,后期改成下拉列表的形式 region = models.ForeignKey(Address, verbose_name=_('收货人'), on_delete=models.CASCADE, related_name='order_basic') # 支付方式 payment_choice = (('1', '货到付款'), ('2', '微信支付'), ('3', '支付宝'), ('4', '银联支付')) payment = models.CharField( verbose_name=_('支付方式'), choices=payment_choice, max_length=1, ) # 商品总数 commodity_total_counts = models.PositiveIntegerField( verbose_name=_('商品总数'), default=1, validators=[ MaxValueValidator(10000, message=_('订单中商品总数不超过10000件')), ]) # 商品总价钱 total_price = models.DecimalField( max_digits=9, decimal_places=2, verbose_name=_('商品总价格'), validators=[ MaxValueValidator(99999999.99, message=_('商品的总价格不能超过999999.99人民币')), ], null=True) # 产生订单日期 generate_time = models.DateTimeField(verbose_name=_('生成订单时间'), auto_now_add=True) # 审核订单完毕日期 check_time = models.DateTimeField(verbose_name=_('审核完毕订单时间'), auto_now=True) # 交易编号,支付包会返回的一个编号 trade_number = models.CharField(verbose_name=_('交易编号'), max_length=128, null=True) # 订单状态 status_choice = ( ("1", '代付款'), # 用户提交订单,尚未付款,此时会锁定库存 ("2", '代发货'), # 用户付款后,等待商家接单前 ("3", '代收货'), # 用户付款后,等待收获 ("4", '交易成功'), # 用户确认收货之后,订单完成交易 ("5", '已取消'), # 付款前取消订单 ("6", '售后中'), # 商家发货或付款后,用户取消订单 ("7", '交易关闭'), # 取消订单或售后结束或退货成功都转移到交易关闭 ("8", '正在退货'), # 用户选择退货,移至此 ("9", '退款成功'), # 用户选择退货,移至此 ) status = models.CharField( verbose_name=_('订单状态'), max_length=1, choices=status_choice, default=1, ) # 是否审核(同意接单) checked = models.BooleanField(verbose_name=_('是否审核'), default=False) # 是否可以评论 remarked = models.BooleanField(verbose_name=_('是否可以评论'), default=False) # 用户删除订单状态,假删除 delete_consumer = models.BooleanField(verbose_name=_('消费者是否删除订单'), default=False) # 商家删除订单状态,假删除 delete_shopper = models.BooleanField(verbose_name=_('商家是否删除订单'), default=False) # 订单提交有效时间 efficient_time = models.DateTimeField(verbose_name=_('订单过期时间'), null=True, auto_now=True) order_basic_ = Manager() class Meta: db_table = 'Order_basic' verbose_name = _('订单信息表') verbose_name_plural = _('订单信息表') def __str__(self): return '订单号:{}'.format(self.orderId)