Добавление динамического начального значения в фильтре

Я хочу добавить динамическое начальное значение для django-filter или django-autocomplete-light в мой DetailView. Я не знаю, как лучше создать это с django-filter, django-autocomplete-light или без третьего приложения

У меня есть выпадающий список зависимостей (в моем случае это журнал → год журнала → объем журнала) для каждого JournalDetailView. Выпадающая зависимость работает с django-autocomplete-light, а фильтр работает с django-filter. Я хочу передать динамическое поле для журнала, поэтому у меня есть ForeignKey, который используется для выпадающих зависимостей для года журнала и объема журнала

Например, в этом случае у меня есть три поля: журнал, год журнала и объем журнала. Я хочу передать значение в зависимости от DetailView для журнала. Например, для журнала "Nature" будет передано поле "Nature"; для журнала "Ca-A Cancer Journal for Clinicians" будет передано "Ca-A Cancer Journal for Clinicians".

У меня это enter image description here

Я хочу построить это enter image description here

models.py

class Journal(models.Model):
    slug = models.SlugField(unique=True)
    name = models.CharField(max_length=100, blank=True, null=True)



class Article(models.Model, HitCountMixin):
    slug = models.SlugField(unique=True)
    journal = models.ForeignKey(
        "Journal", on_delete=models.SET_NULL, null=True, blank=True
    )
    journalyear = models.ForeignKey(
        "JournalYear", on_delete=models.SET_NULL, null=True, blank=True
    )
    journalvolume = models.ForeignKey(
        "JournalVolume", on_delete=models.SET_NULL, null=True, blank=True
    )

    def __str__(self):
        return self.title



class JournalYear(models.Model):
    journal = models.ForeignKey(
        "Journal", on_delete=models.SET_NULL, null=True, blank=True
    )
    name = models.CharField(max_length=10, blank=True, null=True)

    def __str__(self):
        return self.name


class JournalVolume(models.Model):
    journalyear = models.ForeignKey(
        "JournalYear", on_delete=models.CASCADE, blank=True, null=True
    )
    name = models.CharField(max_length=10, blank=True, null=True)

    def __str__(self):
        return self.name

views.py

class JournalAutocomplete2(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        # Don't forget to filter out results depending on the visitor !
        if not self.request.user.is_authenticated:
            return Journal.objects.none()

        qs = Journal.objects.all()

        if self.q:
            qs = qs.filter(name__icontains=self.q)
            
        return qs


class JournalYearAutocomplete2(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        # Don't forget to filter out results depending on the visitor !
        if not self.request.user.is_authenticated:
            return JournalYear.objects.none()

        journal = self.forwarded.get("journal")

        qs = JournalYear.objects.all()

        if journal:
            qs = qs.filter(journal=journal)

        if self.q:
            qs = qs.filter(name__icontains=self.q)

        return qs


class JournalVolumeAutocomplete2(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        # Don't forget to filter out results depending on the visitor !
        if not self.request.user.is_authenticated:
            return JournalVolume.objects.none()

        qs = JournalVolume.objects.all()

        journalyear = self.forwarded.get("journalyear", None)

        if journalyear:
            qs = qs.filter(journalyear=journalyear)

        if self.q:
            qs = qs.filter(name__icontains=self.q)

        return qs

class JournalListView(ListView):
    model = Journal
    template_name = "journals/journals.html"
    context_object_name = "journals"

class JournalDetailView(DetailView):
    model = Journal
    template_name = "journals/journal_detail.html"
    context_object_name = "journal"

    def get_context_data(self, **kwargs):
        context_data = super(JournalDetailView, self).get_context_data()
        journal_slug = self.kwargs.get("slug", None)
        f = JournalFilter(
            self.request.GET,
            queryset=Article.objects.filter(
                journal__slug__exact=self.kwargs["slug"]),
        )
        context_data["filter"] = f
        return context_data

filters.py

class JournalFilter(django_filters.FilterSet):
    journal = django_filters.ModelChoiceFilter(
        queryset=Journal.objects.all(),
        widget=autocomplete.ModelSelect2(url="journalautocomplete2"),
    )
    journalyear = django_filters.ModelChoiceFilter(
        queryset=JournalYear.objects.all(),
        widget=autocomplete.ModelSelect2(
            url="journalyearautocomplete2", forward=["journal"]
        ),
    )
    journalvolume = django_filters.ModelChoiceFilter(
        queryset=JournalVolume.objects.all(),
        widget=autocomplete.ModelSelect2(
            url="journalvolumeautocomplete2", forward=["journalyear"]
        ),
    )

    class Meta:
        model = Article
        fields = {"journalyear", "journalvolume", "journal"}

urls.py

urlpatterns = [
    path("journals/", JournalListView.as_view(), name="journals"),
    path("journal/<str:slug>", JournalDetailView.as_view(), name="journal_detail"),
    # Django-autocomplete-light
    path(
        "journalyearautocomplete2/",
        JournalYearAutocomplete2.as_view(),
        name="journalyearautocomplete2",
    ),
    path(
        "journalvolumeautocomplete2/",
        JournalVolumeAutocomplete2.as_view(),
        name="journalvolumeautocomplete2",
    ),
    path(
        "journalautocomplete2/",
        JournalAutocomplete2.as_view(),
        name="journalautocomplete2",
    ),
]

Django-filter связывает дикту, обычно request.GET, для фильтрации своего набора запросов. Из документации:

def product_list(request):
    f = ProductFilter(request.GET, queryset=Product.objects.all())
    return render(request, 'my_app/template.html', {'filter': f})

Так что если вам нужны значения по умолчанию, если фильтрация не была задана, вы можете сделать

    my_filter_defaults = { ... }
    f = ProductFilter(request.GET or my_filter_defaults, queryset=Product.objects.all())

(Пифоническое использование: пустой dict является Falsy, поэтому вместо него используются значения по умолчанию)

Вы также можете поработать с request.GET, но учтите, что это QueryDict и неизменяемый, так что вам придется сначала скопировать его

my_dict = request.GET.copy( )

if not my_dict.get( 'foo', None):
    my_dict['foo'] = 'my_foo_default'
...
f = ProductFilter(my_dict, queryset=Product.objects.all())

Я не знаком с DAL.

Вернуться на верх