Django ForeignKey limit_choices_to другого идентификатора ForeignKey

Я пытаюсь ограничить выбор Django Admin в ForeignKey, используя limit_choices_to, но я не могу понять, как это сделать правильно.

Этот код делает то, что я хочу, если идентификатор категории равен 16, но я не могу понять, как использовать текущий идентификатор категории, а не жестко-кодировать его.

class MovieCategory(models.Model):    
    category = models.ForeignKey(Category)
    movie = models.ForeignKey(Movie)
    prefix = models.ForeignKey('Prefix', limit_choices_to={'category_id': '16'},
                               blank=True, null=True)
    number = models.DecimalField(verbose_name='Movie Number', max_digits=2,
                                 blank=True, null=True, decimal_places=0)

Можно ли каким-либо образом ссылаться на идентификатор категории ForeignKey?

+7
источник поделиться
3 ответа

После нескольких часов чтения полузаданных вопросов я, наконец, понял это.

Вы не можете самостоятельно ссылаться на модель так, как я пытался это сделать, нет способа заставить django действовать так, как я хотел использовать limit_choices_to, потому что он не может найти идентификатор другого ForeignKey в той же модели.

Это может быть сделано, если вы измените способ работы django, но более простой способ решить это - это вместо этого внести изменения в admin.py.

Вот как это выглядит в моих models.py сейчас:

# models.py
class MovieCategory(models.Model):    
    category = models.ForeignKey(Category)
    movie = models.ForeignKey(Movie)
    prefix = models.ForeignKey('Prefix', blank=True, null=True)
    number = models.DecimalField(verbose_name='Movie Number', max_digits=2,
                                 blank=True, null=True, decimal_places=0)

Я просто удалял limit_choices_to целиком. Я нашел подобную проблему здесь с решением, опубликованным Кайлом Дунканом. Разница заключается в том, что это использует ManyToMany, а не ForeignKey. Это означает, что мне пришлось удалить filter_horizontal = ('prefix',) под мой класс MovieCategoryAdmin(admin.ModelAdmin):, поскольку это только для полей ManyToMany.

В admin.py мне нужно было добавить from django import forms вверху, чтобы создать форму. Вот как выглядит форма:

class MovieCategoryForm(forms.ModelForm):

    class Meta:
        model = MovieCategory
        fields = ['prefix']

    def __init__(self, *args, **kwargs):
        super(MovieCategoryForm, self).__init__(*args, **kwargs)
        self.fields['prefix'].queryset = Prefix.objects.filter(
                                        category_id=self.instance.category.id)

И моя AdminModel:

class MovieCategoryAdmin(admin.ModelAdmin):
    """
    Admin Class for 'Movie Category'.
    """
    fieldsets = [
        ('Category',      {'fields': ['category']}),
        ('Movie',         {'fields': ['movie']}),
        ('Prefix',        {'fields': ['prefix']}),
        ('Number',        {'fields': ['number']}),
    ]
    list_display = ('category', 'movie', 'prefix', 'number')
    search_fields = ['category__category_name', 'movie__title', 'prefix__prefix']
    form = MovieCategoryForm

Именно так Кайл описывает это в своем ответе, за исключением того, что мне пришлось добавить fields = ['prefix'] в форму или она не будет работать. Если вы выполните его шаги и не забудьте удалить filter_horizontal и добавить поля, которые вы используете, они должны работать.

Изменить: это решение прекрасно работает при редактировании, но не при создании новой записи, поскольку не может найти идентификатор категории, если он не выходит. Я пытаюсь выяснить, как это решить.

+13
источник

Другой подход, если вы не хотите добавлять настраиваемый ModelForm, должен обрабатывать это в вашем методе ModelAdmin get_form(). Это было предпочтительнее для меня, потому что мне нужен был легкий доступ к объекту запроса для моего запроса.

class StoryAdmin(admin.ModelAdmin):

    def get_form(self, request, obj=None, **kwargs):
        form = super(StoryAdmin, self).get_form(request, obj, **kwargs)

        form.base_fields['local_categories'].queryset = LocalStoryCategory.\
            objects.filter(office=request.user.profile.office)

        return form
0
источник

У меня был тот же вопрос, и мой ответ сам помог мне начать. Но я также нашел другое сообщение (question-12399803), которое завершило ответ, то есть, как фильтровать при создании новой записи.

В views.py

form = CustomerForm(groupid=request.user.groups.first().id)

В forms.py

def __init__(self, *args, **kwargs):
    if 'groupid' in kwargs:
        groupid = kwargs.pop('groupid')
    else:
        groupid = None
    super(CustomerForm, self).__init__(*args, **kwargs)
    if not groupid:
        groupid = self.instance.group.id
    self.fields['address'].queryset = Address.objects.filter(group_id=groupid)

Итак, будь то добавление нового клиента или обновление существующего клиента, я могу щелкнуть ссылку, чтобы добавить новый адрес, который будет назначен этому клиенту.

Это мой первый ответ на StackOverflow. Надеюсь, это поможет.

-1
источник

Посмотрите другие вопросы по меткам или Задайте вопрос