1
votes

I am using wagtails wagtail-generic-chooser to create customChoosers for my data models and it is working great whenever I am referencing other modelAdmin models.

However, I have come across a situation where I have a Lexis model with a field that has a FK link to itself. The idea is to have a Lexis term, and then there can be related lexis terms connected to it. It works fine with a normal FieldPanel but this isn't a very good UI experience when there are hundreds of lexis terms. Accordingly, I wanted to create a custom LexisChooser for this field. However, the issue I've run into is according to the documentation in order to create a functional widget, I am required to create both a view and adminChooser that references the model the ChooserPanel is connected to.

https://github.com/wagtail/wagtail-generic-chooser#chooser-widgets-model-based

This makes sense, however, when I then try to import my LexisChooser into my Lexis model to use the LexisChooser as a widget, I get the error below.

ImportError: cannot import name 'Lexis' from 'lexis.models'

I realize this is due to a circular import error issue because I have subclasses that are importing the Lexis Class in order to build the LexisChooser widget and then I am trying to import that widget into the Lexis Class.

I know this isn't a bug with Wagtail nor is it a problem with wagtail-generic-chooser, However, does anyone have any idea how I can refactor the code to make this function so that I can use a LexisChooser on a field of the Lexis Model.

Below is my code.

views.py create a view

from django.utils.translation import ugettext_lazy as _
from generic_chooser.views import ModelChooserViewSet
from lexis.models import Lexis

class LexisChooserViewSet(ModelChooserViewSet):

    icon = 'user'
    model = Lexis
    page_title = _("Choose A Lexis Term")
    per_page = 20
    order_by = 'term'
    fields = ['term']

wagtail_hooks.py register view

from wagtail.core import hooks
from .views import LexisChooserViewSet

@hooks.register('register_admin_viewset')
def register_lexis_chooser_viewset():
    return LexisChooserViewSet('lexis_chooser', url_prefix='lexis-chooser')

widgets.py create a widget

from django.utils.translation import ugettext_lazy as _
from generic_chooser.widgets import AdminChooser
from lexis.models import Lexis

class LexisChooser(AdminChooser):

     choose_one_text = _('Choose a Lexis')
     choose_another_text = _('Choose another Lexis')
     link_to_chosen_text = _('Edit this Lexis')
     model = Lexis
     choose_modal_url_name = 'lexis_chooser:choose'

lexis/models.py use widget

from django.db import models
from modelcluster.fields import ParentalKey
from wagtail.admin.edit_handlers import FieldPanel, InlinePanel
from wagtail.core.models import Orderable
from modelcluster.models import ClusterableModel
from chooser_panels.widgets import LexisChooser


# Orderable link to multiple other linked lexis terms
class LexisLink(Orderable):

    page = ParentalKey("lexis.Lexis", related_name="lexis_link")

    term_link = models.ForeignKey(
        'lexis.Lexis', 
        on_delete=models.SET_NULL, 
        related_name='term_linked', 
        null=True
    )

    panels = [
        FieldPanel("term_link", widget=LexisChooser)
    ]


class Lexis(ClusterableModel):

    template = "lexis/lexis_page.html"
    term = models.CharField(max_length=100, blank=True, null=True)
    panels = [
        FieldPanel("term"),
        InlinePanel('lexis_link', label='Linked Lexis Terms'), 
    ]

    def __str__(self):
        return self.term

    class Meta:
        verbose_name = "Lexis"
        verbose_name_plural = "Lexis"

This, unfortunately, results in a circular import error: ImportError: cannot import name 'Lexis' from 'lexis.models'

On researching this error, I found that people recommend importing Lexis within the class as required rather than at the top of each file, but that doesn't seem to work with the subclassing as outlined above, because I get the same error.

If you have any ideas on how I can refactor the code to make it work and not create the circular import error it would be much appreciated.

I am running Django 3, python 3.7, wagtail 2.8

Thank you

1

1 Answers

0
votes

Split your models file into two separate files containing Lexis and LexisLink, as demonstrated in the documentation.

Then LexisLink can refer to LexisChooser while it cleanly refers to the Lexis model.