Vince Salvino 2 лет назад
Родитель
Сommit
f196ff50de

+ 3 - 3
coderedcms/admin_urls.py

@@ -1,12 +1,12 @@
 from django.urls import include, path, re_path
-from wagtailimportexport import urls as wagtailimportexport_urls
 from wagtail.admin import urls as wagtailadmin_urls
-from coderedcms.views import import_pages_from_csv_file
+from coderedcms.views import import_index, import_pages_from_csv_file
 
 
 urlpatterns = [
+    path('codered/import-export/',
+         import_index, name="import_index"),
     path('codered/import-export/import_from_csv/',
          import_pages_from_csv_file, name="import_from_csv"),
     re_path(r'', include(wagtailadmin_urls)),
-    re_path(r'', include(wagtailimportexport_urls)),
 ]

+ 9 - 12
coderedcms/forms.py

@@ -3,8 +3,8 @@ Enhancements to wagtail.contrib.forms.
 """
 import csv
 import os
-import re
 from django import forms
+from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import ValidationError
 from django.db import models
 from django.http import HttpResponse
@@ -172,16 +172,13 @@ class SearchForm(forms.Form):
 def get_page_model_choices():
     """
     Returns a list of tuples of all creatable Codered pages
-    in the format of ("Custom Codered Page", "CustomCoderedPage")
+    in the format of (app_label:model, "Verbose Name")
     """
     from coderedcms.models import get_page_models
-    return (
-        (
-            page.__name__,
-            re.sub(
-                r'((?<=[a-z])[A-Z]|(?<!\A)[A-Z](?=[a-z]))',
-                r' \1',
-                page.__name__
-            )
-        ) for page in get_page_models() if page.is_creatable
-    )
+
+    rval = []
+    for page in get_page_models():
+        if page.is_creatable:
+            ct = ContentType.objects.get_for_model(page)
+            rval.append((f"{ct.app_label}:{ct.model}", ct.name))
+    return rval

+ 64 - 8
coderedcms/importexport.py

@@ -1,22 +1,73 @@
+"""
+This code is largely copied or extended upon the now defunct
+``wagtailimportexport`` package.
+
+In the future we may want to build a more robust import/exporter for CSV files,
+or simply deprecate all of this functionality.
+
+See: https://github.com/torchbox/wagtail-import-export/
+"""
 import csv
 import copy
 
 from django import forms
 from django.apps import apps
 from django.contrib.contenttypes.models import ContentType
-from django.db import transaction
-
+from django.db import models, transaction
+from django.utils.translation import ugettext as _
+from modelcluster.models import get_all_child_relations
+from wagtail.admin.widgets import AdminPageChooser
 from wagtail.core.models import Page
 
-from wagtailimportexport.forms import ImportFromFileForm
-from wagtailimportexport.importing import update_page_references
-
 from coderedcms.forms import get_page_model_choices
 
 
-class ImportPagesFromCSVFileForm(ImportFromFileForm):
+class ImportPagesFromCSVFileForm(forms.Form):
+    """
+    Mostly copied from:
+    https://github.com/torchbox/wagtail-import-export/blob/master/wagtailimportexport/forms.py#L29
+    with addition of ``page_type``.
+    """
     page_type = forms.ChoiceField(choices=get_page_model_choices)
 
+    file = forms.FileField(label=_("File to import"))
+
+    parent_page = forms.ModelChoiceField(
+        queryset=Page.objects.all(),
+        widget=AdminPageChooser(can_choose_root=True, show_edit_link=False),
+        label=_("Destination parent page"),
+        help_text=_("Imported pages will be created as children of this page.")
+    )
+
+
+def update_page_references(model, pages_by_original_id):
+    """
+    Copied from:
+    https://github.com/torchbox/wagtail-import-export/blob/master/wagtailimportexport/importing.py#L67
+    """
+    for field in model._meta.get_fields():
+        if isinstance(field, models.ForeignKey) and issubclass(field.related_model, Page):
+            linked_page_id = getattr(model, field.attname)
+            try:
+                # see if the linked page is one of the ones we're importing
+                linked_page = pages_by_original_id[linked_page_id]
+            except KeyError:
+                # any references to pages outside of the import should be left unchanged
+                continue
+
+            # update fk to the linked page's new ID
+            setattr(model, field.attname, linked_page.id)
+
+    # update references within inline child models, including the ParentalKey pointing back
+    # to the page
+    for rel in get_all_child_relations(model):
+        for child in getattr(model, rel.get_accessor_name()).all():
+            # reset the child model's PK so that it will be inserted as a new record
+            # rather than updating an existing one
+            child.pk = None
+            # update page references on the child model, including the ParentalKey
+            update_page_references(child, pages_by_original_id)
+
 
 @transaction.atomic()
 def import_pages(import_data, parent_page):
@@ -69,7 +120,7 @@ def import_pages(import_data, parent_page):
             strict_fks=False
         )
         base_page = pages_by_original_id[specific_page.id]
-        specific_page.page_ptr = base_page
+        specific_page.base_page_ptr = base_page
         specific_page.__dict__.update(base_page.__dict__)
         specific_page.content_type = ContentType.objects.get_for_model(model)
         update_page_references(specific_page, pages_by_original_id)
@@ -80,7 +131,12 @@ def import_pages(import_data, parent_page):
 
 def convert_csv_to_json(csv_file, page_type):
     pages_json = {"pages": []}
-    default_page_data = {"app_label": "website", "content": {"pk": None}, "model": page_type}
+    app_label, klass = page_type.split(":")
+    default_page_data = {
+        "app_label": app_label,
+        "content": {"pk": None},
+        "model": klass,
+    }
 
     pages_csv_dict = csv.DictReader(csv_file)
     for row in pages_csv_dict:

+ 0 - 11
coderedcms/models/page_models.py

@@ -554,17 +554,6 @@ class CoderedWebPage(CoderedPage):
         preview = body[:200] + "..." if len(body) > 200 else body
         return mark_safe(preview)
 
-    @property
-    def page_ptr(self):
-        """
-        Overwrite of `page_ptr` to make it compatible with wagtailimportexport.
-        """
-        return self.base_page_ptr
-
-    @page_ptr.setter
-    def page_ptr(self, value):
-        self.base_page_ptr = value
-
 
 class CoderedArticlePage(CoderedWebPage):
     """

+ 0 - 1
coderedcms/project_template/basic/project_name/settings/base.py

@@ -34,7 +34,6 @@ INSTALLED_APPS = [
     'modelcluster',
     'taggit',
     'wagtailcache',
-    'wagtailimportexport',
     'wagtailseo',
 
     # Wagtail

+ 0 - 1
coderedcms/project_template/sass/project_name/settings/base.py

@@ -33,7 +33,6 @@ INSTALLED_APPS = [
     'modelcluster',
     'taggit',
     'wagtailcache',
-    'wagtailimportexport',
     'wagtailseo',
 
     # Wagtail

+ 0 - 11
coderedcms/templates/wagtailimportexport/export_to_file.html

@@ -1,11 +0,0 @@
-{% extends "wagtailimportexport/export_to_file.html" %}
-
-{% block css %}
-    {{ block.super }}
-    {{ form.media.css }}
-{% endblock %}
-
-{% block js %}
-    {{ block.super }}
-    {{ form.media.js }}
-{% endblock %}

+ 0 - 11
coderedcms/templates/wagtailimportexport/import_from_api.html

@@ -1,11 +0,0 @@
-{% extends "wagtailimportexport/import_from_api.html" %}
-
-{% block css %}
-    {{ block.super }}
-    {{ form.media.css }}
-{% endblock %}
-
-{% block js %}
-    {{ block.super }}
-    {{ form.media.js }}
-{% endblock %}

+ 11 - 1
coderedcms/templates/wagtailimportexport/import_from_csv.html

@@ -14,7 +14,7 @@
     {% include "wagtailadmin/shared/header.html" with title=title_str icon="download" %}
 
     <div class="nice-padding">
-        <form action="{% url 'import_from_csv' %}" enctype="multipart/form-data" method="POST" novalidate>
+        <form action="{% url 'import_from_csv' %}" enctype="multipart/form-data" method="POST">
             {% csrf_token %}
             <ul class="fields">
                 {% for field in form %}
@@ -22,6 +22,16 @@
                 {% endfor %}
             </ul>
 
+            <br>
+            <p>
+              <b>{% trans "IMPORTANT:" %}</b>
+              {% trans "CSV file must be in the correct format before importing." %}
+              <a href="https://docs.coderedcorp.com/wagtail-crx/features/import_export.html">
+                {% trans "Read the importing guide." %}
+              </a>
+            </p>
+            <br>
+
             <input type="submit" value="{% trans 'Import' %}" class="button">
         </form>
     </div>

+ 0 - 11
coderedcms/templates/wagtailimportexport/import_from_file.html

@@ -1,11 +0,0 @@
-{% extends "wagtailimportexport/import_from_file.html" %}
-
-{% block css %}
-    {{ block.super }}
-    {{ form.media.css }}
-{% endblock %}
-
-{% block js %}
-    {{ block.super }}
-    {{ form.media.js }}
-{% endblock %}

+ 2 - 13
coderedcms/templates/wagtailimportexport/index.html

@@ -2,22 +2,11 @@
 {% load i18n %}
 {% block titletag %}{% blocktrans %}Import / export pages{% endblocktrans %}{% endblock %}
 {% block content %}
-    {% trans "Import / export pages" as title_str %}
+    {% trans "Import pages" as title_str %}
     {% include "wagtailadmin/shared/header.html" with title=title_str icon="download" %}
 
     <div class="nice-padding">
-        <h3>JSON</h3>
-        <ul>
-            <li><a href="{% url 'wagtailimportexport_admin:import_from_file' %}">{% trans "Import from JSON file" %}</a></li>
-            <li><a href="{% url 'wagtailimportexport_admin:export_to_file' %}">{% trans "Export to JSON file" %}</a></li>
-        </ul>
         <h3>CSV</h3>
-        <ul>
-            <li><a href="{% url 'import_from_csv' %}">{% trans "Import from CSV file" %}</a></li>
-        </ul>
-        <h3>API</h3>
-        <ul>
-            <li><a href="{% url 'wagtailimportexport_admin:import_from_api' %}">{% trans "Import from API" %}</a></li>
-        </ul>
+        <p><a href="{% url 'import_from_csv' %}">{% trans "Import from CSV file" %}</a></p>
     </div>
 {% endblock %}

+ 0 - 1
coderedcms/tests/settings.py

@@ -35,7 +35,6 @@ INSTALLED_APPS = [
     'modelcluster',
     'taggit',
     'wagtailcache',
-    'wagtailimportexport',
     'wagtailseo',
 
     # Wagtail

+ 8 - 0
coderedcms/views.py

@@ -230,6 +230,14 @@ def event_get_calendar_events(request):
     )
 
 
+@login_required
+def import_index(request):
+    """
+    Landing page to replace wagtailimportexport.
+    """
+    return render(request, 'wagtailimportexport/index.html')
+
+
 @login_required
 def import_pages_from_csv_file(request):
     """

+ 15 - 0
coderedcms/wagtail_hooks.py

@@ -6,6 +6,7 @@ from django.http.response import HttpResponse
 from django.urls import reverse
 from django.utils.html import format_html, mark_safe
 from django.utils.translation import gettext_lazy as _
+from wagtail.admin.menu import MenuItem
 from wagtail.core import hooks
 from wagtail.core.models import UserPagePermissionsProxy, get_page_models
 from wagtailcache.cache import clear_cache
@@ -123,6 +124,20 @@ def serve_document_directly(document, request):
     return response
 
 
+class ImportExportMenuItem(MenuItem):
+    def is_shown(self, request):
+        return request.user.is_superuser
+
+
+@hooks.register('register_settings_menu_item')
+def register_import_export_menu_item():
+    return ImportExportMenuItem(
+        _('Import'),
+        reverse('import_index'),
+        classnames='icon icon-download',
+    )
+
+
 class CoderedSubmissionAdmin(SubmissionAdmin):
 
     def __init__(self, parent=None):

+ 18 - 9
docs/features/import_export.rst

@@ -1,26 +1,35 @@
 Import/Export
 =============
 
-``wagtail-import-export`` is included in the CMS. You can find documentation for it
-`here <https://github.com/torchbox/wagtail-import-export>`_.  In addition to the JSON
-import/export functionality that the package includes, we have added the ability to create
-pages by importing CSV files.
+CRX includes the ability to import pages from CSV files. This is useful for
+example in a store locator, where a list of stores needs to be uploaded
+periodically.
+
+To start an import, go to **Settings > Import**
 
 In the CSV each row will be a new page and each column header will correspond to an attribute
 of that page. On the import CSV page, you will select where you want the pages to live and what
 page type they should be created as. A use case for this functionality would be if your site needs
 to add several hundred locations as pages. These locations come from a CSV dump from some report
-generating software. Your CSV could look something like this::
+generating software. Your CSV could look something like this:
+
+.. code-block:: text
 
-    title       address         latitude    longitude
-    Store 1     123 Street      20.909      -15.32
-    Store 2     456 Avenue      34.223      87.2331
+    title   ,   address    ,   latitude ,   longitude
+    Store 1 ,   123 Street ,   20.909   ,   -15.32
+    Store 2 ,   456 Avenue ,   34.223   ,   87.2331
     ...
     ...
 
 ``title``, ``address``, ``latitude``, ``longitude`` are all fields on your Page model that you will
 be importing as.
 
-.. note::
+.. important::
+
     Your CSV file must be encoded as ASCII or UTF-8.
     UTF-8-BOM will cause an error.
+
+.. versionchanged:: 0.24
+
+   In version 0.24, the ability to import/export pages from JSON was removed.
+   The Import/Export link in the side menu was also moved to Settings > Import.

+ 0 - 1
setup.py

@@ -50,7 +50,6 @@ setup(
         'icalendar==4.0.*',
         'wagtail==2.16.*',
         'wagtail-cache==1.*',
-        'wagtail-import-export>=0.2,<0.3',
         'wagtail-seo==1.*',
     ],
     entry_points={

+ 0 - 1
tutorial/mysite/mysite/settings/base.py

@@ -34,7 +34,6 @@ INSTALLED_APPS = [
     'modelcluster',
     'taggit',
     'wagtailcache',
-    'wagtailimportexport',
     'wagtailseo',
 
     # Wagtail