def __init__(self, *args, **kwargs): super(DirectoryBackendSection, self).__init__(*args, **kwargs) # tags self.sections = [DirectoryTagsSection()] # categories category_models = [] for model in get_models(): if issubclass(model, DirectoryCategory): category_models.append(model) category_models.sort(key=lambda m: m.__name__) self.sections.extend([DirectoryCategorySection(m) for m in category_models]) # directory entities content_models = [] for model in get_models(): if issubclass(model, DirectoryEntity): content_models.append(model) for title, attr, value, model in self.get_model_sections(content_models): slug = slugify(title) _title = get_listing_option(model, 'title') if _title is not None: title = _title self.sections.append(DirectoryContentSubSection(title, slug, attr, value, model, model.get_backend_section_group())) # sort sections by title self.sections.sort(key=lambda s: s.title)
def handle(self, *args, **options): """ Run command. """ print 'Rewriting CMS links ...Please Wait...' # simulation mode? simulate = options.get('simulate', False) # collect content models cms = get_cms() cms_models = tuple(cms.get_supported_models()) links = self.get_page_links() # process all models in the system models = get_models() i = 0 n = 0 for m in models: if issubclass(m, cms_models): _i, _n = self.process_model(m, links, simulate, options.get('pk')) i += _i n += _n print '%d item(s) updated out of %d content page(s) in total.%s' % ( i, n, ' (Simulated!)' if simulate else '')
def configure(self, request, instance=None, edit=True): super(PageForm, self).configure(request, instance, edit) # generate list of entity type choices based on all django models # that subclass from PageBase (but not Page itself). choices = [('', '-------')] for model in get_models(): if issubclass(model, ChildPage): choices.append((model.__name__, model._meta.verbose_name)) self.fields['entity_type'].choices = choices # navigation if edit or self.is_duplicate: self.fields['nav'].initial = instance.nav # parent page only available if hierarchical pages is enabled if not settings.PAGE_HIERARCHY: self.remove_field('parent') self.update_sections() # 404 page cannot be disabled! cms_settings = get_cms_settings() if instance and cms_settings.default_404 and instance.pk == cms_settings.default_404.pk: self.fields['disabled'].widget.attrs['disabled'] = True self.fields[ 'disabled'].help_text = 'This page is configured as the default 404 (Page Not Found) page and can therefore not be disabled.' self.fields['sitemap'].widget.attrs['disabled'] = True self.fields[ 'sitemap'].help_text = 'This page is configured as the default 404 (Page Not Found) page and can therefore not be excluded from the sitemap.'
def get_directory_content_backend_sections(backend_section): """ Return a list of all backend sections that are related to directory content. """ # append all known directory content entities and categories sections = [] content_models = [] for model in get_models(): if issubclass(model, DirectoryContentBase) or issubclass(model, DirectoryContentEntity): content_models.append(model) # create sections sections = [] for title, attr, value, model in backend_section.get_model_sections(content_models): slug = slugify(title) _title = get_listing_option(model, 'title') if _title is not None: title = _title if attr and value and hasattr(model, 'get_backend_section_title'): title = model.get_backend_section_title(value) sections.append(DirectoryContentSubSection(title, slug, attr, value, model, model.get_backend_section_group())) return sections
def delete_directory_categories(self): """ Delete all directory categories. """ for model in get_models(): if issubclass(model, DirectoryCategory): for c in model.objects.all(): c.delete()
def delete_entities(self): """ Delete all cms entities. """ for model in get_models(): if issubclass(model, Entity): for page in model.objects.all(): page.delete()
def delete_child_pages(self): """ Delete all child pages. """ for model in get_models(): if issubclass(model, ChildPage): for page in model.objects.all(): page.delete()
def get_directory_models(self): """ Return a list of aggregate-able directory content asset models. """ models = [] for model in get_models(): if issubclass(model, DirectoryContentBase): models.append(model) return models
def get_directory_category_models(self): """ Return a list of models representing directory categories. """ models = [] for model in get_models(): if issubclass(model, DirectoryCategory): models.append(model) return models
def get_child_page_models(): """ Return a list of all models that are derived from ChildPage. """ _models = [] for model in get_models(): if issubclass(model, ChildPage): _models.append(model) return _models
def save(self, *args, **kwargs): try: old_title = DirectoryTag.objects.get(pk=self.pk).title except: old_title = None for model in get_models(): self.update_tags_for_model(model, old_title, self.title) super(DirectoryTag, self).save(*args, **kwargs)
def _get_model_by_table_name(self, table): """ Return the model based on the given table name. """ if not hasattr(self, '_model_table_cache'): self._model_table_cache = {} for model in get_models(): self._model_table_cache[model._meta.db_table] = model return self._model_table_cache.get(table)
def delete_entities(self): """ Override: Deleting all CMS entities but NOT directory entities. """ for model in get_models(): if (issubclass(model, Entity) and not issubclass( model, DirectoryContentEntity)) or issubclass( model, DirectoryEntity): for page in model.objects.all(): page.delete()
def delete_directory_content_pages(self): """ Delete all directory content pages. """ for model in get_models(): if issubclass(model, DirectoryContentBase) or issubclass( model, DirectoryContentEntity) or issubclass( model, DirectoryEntity): for page in model.objects.all(): page.delete()
def get_sitemaps(self): """ Override: Add directory-specific content to sitemap. """ _sitemaps = super(CMSExtensions, self).get_sitemaps() # directory content for model in get_models(): if issubclass(model, DirectoryContentBase): _sitemaps[slugify(model._meta.verbose_name)] = CMSDirectoryContentSitemap(self, model) return _sitemaps
def node(self, request): # get cms from cubane.cms.views import get_cms cms = get_cms() # root level (pages and directory categories) if 'pk' not in request.GET and 'type' not in request.GET: return to_json_response({ 'success': True, 'items': [cms.get_sitemap_item(request, page) for page in cms.get_sitemap_root_pages()] }) # get pk argument if 'pk' not in request.GET: raise Http404('Missing argument: pk.') try: pk = int(request.GET.get('pk')) except ValueError: raise Http404('Invalid pk argument: Not a number.') # get type argument if 'type' not in request.GET: raise Http404('Missing argument: type.') type_name = request.GET.get('type') # resolve type by given name model = None for m in get_models(): if m.__name__ == type_name: model = m break if not model: raise Http404('Unknown model type name: \'%s\'.' % type_name) # get node by given pk node = model.objects.get(pk=pk) # generate child nodes items = [] children = cms.get_sitemap_children(node) if children: for child in children: item = cms.get_sitemap_item(request, child) if item: items.append(item) # return response (json) return to_json_response({ 'success': True, 'items': items })
def get_entity_model(self): """ Return the entity model that this page manages. """ if self._entity_model == None: self._entity_model = False for model in get_models(): if model.__name__ == self.entity_type: self._entity_model = model break if self._entity_model: return self._entity_model else: return None
def get_page_links(self): """ Return a dictionary of all known content pages via their url path. """ result = {} cms = get_cms() cms_models = tuple(cms.get_supported_models()) models = get_models() for model in models: if issubclass(model, cms_models): for instance in model.objects.all(): if hasattr(instance, 'get_absolute_url'): page_path = to_legacy_url(instance.get_absolute_url()) link = '#link[%s:%s]' % (model.__name__, instance.pk) result[page_path] = link return result
def get_object_model(self, model_name): """ Create a object model with given name. """ # only consider the axtual name if '.' in model_name: model_name = model_name.split('.')[-1] supported_models = self.get_supported_models() for model in get_models(): valid = False for supported_model in supported_models: if issubclass(model, supported_model): if model_name == model.__name__: return model return None
def load_model_fixtures(connection, stdout=sys.stdout, verbosity=1): """ Load the initial data for all models as defined for each model. """ for model in get_models(): fixtures = get_model_fixtures(model) if len(fixtures) > 0: if verbosity >= 1: for fixture in fixtures: stdout.write('Loading initial data fixture: %s.\n' % fixture) args = ['loaddata'] + fixtures call_command(*args, interactive=False, database=connection.alias, run_syncdb=True, verbosity=verbosity)
def _add_related_log(self, instance): """ Recursively issue change log entries for related items that are pointing to instance but would be set to NULL due to deleting instance. """ # find all models that are holding a reference to the given instance # model, which might be one of the following # - ForeignKey to instance model # - OneToOneField to instance model # - ManyToManyField without a through model referencing instance model # - GenericRelation. # ManyToManyField with a though model are irrelevant, since they will # be found because of a ForeignKey that exists to the instance model # in the intermediate model class. for model in get_models(): # skip self or ChangeLog if model == instance.__class__ or model == ChangeLog: continue # scan for related fields that are referencing the instance model for field in model._meta.get_fields(): # only RelatedField if not isinstance(field, RelatedField): continue # ignore ManyToMany or GenericRelation if field.many_to_many or isinstance(field, GenericRelation): continue # ignore the ones that are not pointing to instance model if not issubclass(instance.__class__, field.rel.model): continue # get affected target objects objects = model.objects.filter(**{field.name: instance.pk}) # generate log entry for obj in objects: if field.null: # nullable field -> log edit previous_obj = self.get_changes(obj) setattr(obj, field.attname, None) self.edit(obj, previous_obj) else: # not nullable -> log delete self.delete(obj)
def __init__(self, *args, **kwargs): super(ShopBackendSection, self).__init__(*args, **kwargs) # finance options if settings.SHOP_LOAN_ENABLED: from cubane.ishop.apps.merchant.finance.views import FinanceOptionBackendSection self.sections.append(FinanceOptionBackendSection()) # append all known shop entities entity_models = [] for model in get_models(): if issubclass(model, ShopEntity): entity_models.append(model) # sort by name entity_models = sorted(entity_models, key=lambda m: m.__name__) # create sections self.sections.extend([ShopContentEntitySection(model, model.get_backend_section_group()) for model in entity_models])
def get_changes(self, a, b=None): """ Return a structure in JSON that describes the changes that occurred for the given model a (before the change) and b (after the change). """ # nothing to work with if a is None and b is None: return None # identify model class and get list of known models _class = a.__class__ models = get_models() # identify all database columns from model fieldnames = get_model_field_names(_class) # generate index over b (if available) index = {} if b is not None: for entry in b: index[entry.get('n')] = entry.get('a') def _array_equal(ass, bss): if len(ass) != len(bss): return False for i, a in enumerate(ass): if a != bss[i]: return False return True # generate changes result = [] for fieldname in fieldnames: # get field is model field = _class._meta.get_field(fieldname) # ignore file fields if isinstance(field, DjangoFileField): continue # get previous value (b) if b is not None: vb = index.get(field.attname) else: vb = None # get current and previous values if field.many_to_many: # ignore ManyToMany with through model. It will be picked up # by collecting related objects has_through_model = False for m in models: if issubclass(field.rel.through, m): has_through_model = True break if has_through_model: continue # get list of pk's for many-to-many related objects if a.pk: va = getattr(a, field.name) if va is not None: va = [x.pk for x in va.all()] else: va = [] else: va = getattr(a, field.attname) # value changed? changed = False if b is not None: if isinstance(va, list) and isinstance(vb, list): changed = not _array_equal(va, vb) else: changed = va != vb if b is None or changed: result.append({'n': field.attname, 'a': va, 'b': vb}) return result
# coding=UTF-8 from __future__ import unicode_literals from django.conf.urls import url from cubane.directory.models import DirectoryContentBase from cubane.lib.app import get_models from cubane.directory import views # dispatch directory content urls = [] for model in get_models(): if issubclass(model, DirectoryContentBase): ctypes = model.get_directory_content_type_slugs() for attr_name, backend_section, ct in ctypes: p = r'^' + ct + r'/(?P<slug>[-\w\d]+)-(?P<pk>\d+)/$' urls.append( url(p, views.content, kwargs={ 'model': model, 'attr_name': attr_name, 'backend_section': backend_section }, name='cubane.directory.content.%s' % ct)) # url patterns urlpatterns = urls
def auto_migrate(interactive=True, load_fixtures=True, verbose=True): """ Automatically migrate current schema. """ # get database schema manager and start transaction, so that we can confirm # all changes at the end... schema = get_schema(connection, verbose) schema.begin() # lock all tables, so that we have exclusive access to the schema and data schema.lock(get_models()) # create/rename tables models_visited = [] for model in get_models(): create_or_rename_table(schema, model, interactive, models_visited) # update tables for model in get_models(): schema.update_table(model) # list containing custom indices that will be checked for existence and # created if not present. from django.contrib.contenttypes.models import ContentType custom_index = { get_class_name_with_modules(ContentType): ['app_label', 'model', ['app_label', 'model']] } # apply custom indecies not defined in the model, for example adding # index to auth_user's email address... indicies = [] for model in get_models(): indicies.extend(check_custom_indexing(schema, model, custom_index)) schema.keep_indicies(indicies) # migrate schema for each table fts_reindex_models = [] for model in get_models(): create_or_rename_fields(schema, model, interactive) drop_deprecated_fields(schema, model) update_fields(schema, model) if fts_install_for_model(schema, model): fts_reindex_models.append(model) # migrate content types schema.migrate_django_content_types() # ask user if he realy wants to go ahead with these changes... if ask_confirm("Apply changes?", interactive): commit_changes(schema) # ask for fts reindex if required if len(fts_reindex_models) > 0: if ask_confirm( "One or more models changed regarding full text search. Do you want to re-index now?", interactive): for model in fts_reindex_models: schema.fts_reindex_model(model) # re-install fixtures if load_fixtures: load_model_fixtures(connection, verbosity=1 if interactive else 0) else: schema.rollback()
def get_aggregated_pages(self, include_tags, exclude_tags=[], order=DirectoryOrder.ORDER_DEFAULT, max_items=None, navigation=False, visibility_filter_args={}): """ Return a list of all aggregated pages for the given include tags and exclude tags ordered by the given order. If no order is given, the system-wide order applies (settings). The number of result records may be limited to the number given. If the navigation argument is True, then directory content entities are NOT included in the result set. """ # enfore list of list of tags for include tags include_tags = list_of_list(include_tags) exclude_tags = list_of(exclude_tags) # create cache if not hasattr(self, '_agg_cache'): self._agg_cache = {} # collect all aggregated content pages = [] el_tags = set() for model in get_models(): if issubclass(model, DirectoryContentBase) or (not navigation and issubclass(model, DirectoryContentEntity)): # create cache key cache_id = '%s-%s-%d-%s' % ( '-'.join(itertools.chain(*include_tags)), '-'.join(exclude_tags), order, model ) # deliver partial result from cache? if cache_id in self._agg_cache: agg_pages = self._agg_cache[cache_id] else: agg_pages = self._agg_cache[cache_id] = model.objects.filter_by_tags(include_tags, exclude_tags, visibility_filter_args) # if the page is an aggregator as well as directory content, # then collect cascading tags to eliminate content if issubclass(model, DirectoryContentAndAggregator): for p in agg_pages: el_tags |= p.get_cascading_tags() pages.extend(agg_pages) # eliminate all pages that match one of the cascading tags found... if len(el_tags) > 0: pages = filter(lambda p: not p.matches_tags(el_tags), pages) # default order from settings? if order == DirectoryOrder.ORDER_DEFAULT: order = self.settings.order_mode # order pages if order == DirectoryOrder.ORDER_RANDOM: # seed random number generator based on the week and year, so that # we get a different random order every week but the order stays the # same during the week... now = datetime.now() random.seed('%s/%s' % (now.year, now.isocalendar()[1])) # generate and inject a random seq... for p in pages: p._random_seq = random.randint(0, 65535) # sort by random seq pages.sort(key=lambda x: x._random_seq) elif order == DirectoryOrder.ORDER_SEQ: pages.sort(key=lambda x: x.seq) elif order == DirectoryOrder.ORDER_TITLE: pages.sort(key=lambda x: x.title if hasattr(x, 'title') else False) elif order == DirectoryOrder.ORDER_DATE: pages.sort(key=lambda x: x.created_on, reverse=True) elif order == DirectoryOrder.ORDER_CUSTOM_DATE: pages.sort(key=lambda x: (x.custom_date or dt.datetime(1970, 1, 1)), reverse=False) # sort by priority pages.sort(key=lambda x: not x.priority) # move items with top priority to the top of the listing pages.sort(key=lambda x: not x.top_priority) # restrict the maximum number of aggregated items if max_items != None: pages = pages[:max_items] return pages
def fts_reindex(self): """ Reindex full text search index for all models with full text search index. """ for model in get_models(): self.fts_reindex_model(model)
def delete(self): super(DirectoryTag, self).delete() for model in get_models(): self.remove_tags_from_model(model, self.title)