Skip to content

Commit

Permalink
Add a mixin for adding the import button back under Wagtail 6
Browse files Browse the repository at this point in the history
  • Loading branch information
gasman committed Jan 26, 2024
1 parent daa4369 commit 6b51655
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 4 deletions.
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ This package will attempt to match a model object against row in Airtable using

* Install the package with `pip install wagtail-airtable`
* Add `'wagtail_airtable'` to your project's `INSTALLED_APPS`.
* To enable the snippet-specific import button on the Snippet list view make sure `wagtail_airtable` is above `wagtail.snippets` in your `INSTALLED_APPS`
* On Wagtail 5.x, to enable the snippet-specific import button on the Snippet list view make sure `wagtail_airtable` is above `wagtail.snippets` in your `INSTALLED_APPS`
* In your settings you will need to map Django models to Airtable settings. Every model you want to map to an Airtable sheet will need:
* An `AIRTABLE_BASE_KEY`. You can find the base key in the [Airtable API docs](https://airtable.com/api) when you're signed in to Airtable.com
* An `AIRTABLE_TABLE_NAME` to determine which table to connect to.
Expand Down Expand Up @@ -252,6 +252,29 @@ The messaging will be off if you do this, so another setting has been made avail
`WAGTAIL_AIRTABLE_PUSH_MESSAGE` - set this to whatever you'd like the messaging to be e.g. `WAGTAIL_AIRTABLE_PUSH_MESSAGE='Airtable save is happening in the background'`


### Adding an Import action to the snippet list view (Wagtail 6.x)

As of Wagtail 6.0, the Import action is no longer automatically shown on the snippet listing view (although it is still available through Settings -> Airtable import). To add it back, first ensure that your snippet model is [registered with an explicit viewset](https://docs.wagtail.org/en/stable/topics/snippets/registering.html#using-register-snippet-as-a-function). Then, ensure that the index view for that viewset inherits from `SnippetImportActionMixin`:

```python
from wagtail.snippets.models import register_snippet
from wagtail.snippets.views.snippets import IndexView, SnippetViewSet
from wagtail_airtable.mixins import SnippetImportActionMixin
from .models import Advert


class AdvertIndexView(SnippetImportActionMixin, IndexView):
pass


class AdvertViewSet(SnippetViewSet):
model = Advert
index_view_class = AdvertIndexView

register_snippet(Advert, viewset=AdvertViewSet)
```


### Trouble Shooting Tips
#### Duplicates happening on import
Ensure that your serializer matches your field definition *exactly*, and in cases of `CharField`'s that have `blank=True` or `null=True` setting `required=False` on the serializer is also important.
Expand Down
15 changes: 13 additions & 2 deletions tests/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
from wagtail.fields import RichTextField
from wagtail.models import Page
from wagtail.snippets.models import register_snippet
from wagtail.snippets.views.snippets import IndexView, SnippetViewSet

from wagtail_airtable.mixins import AirtableMixin
from wagtail_airtable.mixins import AirtableMixin, SnippetImportActionMixin


class SimplePage(Page):
Expand All @@ -14,7 +15,6 @@ class Publication(models.Model):
title = models.CharField(max_length=30)


@register_snippet
class Advert(AirtableMixin, models.Model):
STAR_RATINGS = (
(1.0, "1"),
Expand Down Expand Up @@ -77,6 +77,17 @@ def __str__(self):
return self.title


class AdvertIndexView(SnippetImportActionMixin, IndexView):
pass


class AdvertViewSet(SnippetViewSet):
model = Advert
index_view_class = AdvertIndexView

register_snippet(Advert, viewset=AdvertViewSet)


@register_snippet
class SimilarToAdvert(Advert):
pass
Expand Down
30 changes: 29 additions & 1 deletion wagtail_airtable/mixins.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import sys
from importlib import import_module
from ast import literal_eval
from logging import getLogger

from airtable import Airtable
from django.conf import settings
from django.db import models
from django.urls import reverse
from django.utils.functional import cached_property
from requests import HTTPError

from wagtail.admin.widgets.button import Button

from .tests import MockAirtable

logger = getLogger(__name__)
Expand Down Expand Up @@ -362,3 +364,29 @@ def delete(self, *args, **kwargs):

class Meta:
abstract = True


class ImportButton(Button):
template_name = "wagtail_airtable/_import_button.html"

def get_context_data(self, parent_context):
context = super().get_context_data(parent_context)
context["csrf_token"] = parent_context["csrf_token"]
context["model_opts"] = parent_context["model_opts"]
context["next"] = parent_context["request"].path
return context


class SnippetImportActionMixin:
# Add a new action to the snippet listing page to import from Airtable
@cached_property
def header_buttons(self):
buttons = super().header_buttons
if issubclass(self.model, AirtableMixin) and self.add_url:
buttons.append(
ImportButton(
"Import from Airtable",
url=reverse("airtable_import_listing")
)
)
return buttons
11 changes: 11 additions & 0 deletions wagtail_airtable/templates/wagtail_airtable/_import_button.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% load i18n wagtailadmin_tags %}

{% blocktranslate asvar action_label with snippet_type_name=model_opts.verbose_name_plural %}Import {{ snippet_type_name }}{% endblocktranslate %}
<form action="{{ button.url }}" method="post">
{% csrf_token %}
<input type="hidden" name="model" value="{{ model_opts.label }}" />
<input type="hidden" name="next" value="{{ next }}" />
<button type="submit" aria-label="{{ action_label }}" data-controller="w-tooltip" data-w-tooltip-content-value="{{ action_label }}" class="w-header-button" style="background-color: inherit">
{% icon name="cog" %}
</button>
</form>

0 comments on commit 6b51655

Please sign in to comment.