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?
После нескольких часов чтения полузаданных вопросов я, наконец, понял это.
Вы не можете самостоятельно ссылаться на модель так, как я пытался это сделать, нет способа заставить 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 и добавить поля, которые вы используете, они должны работать.
Изменить: это решение прекрасно работает при редактировании, но не при создании новой записи, поскольку не может найти идентификатор категории, если он не выходит. Я пытаюсь выяснить, как это решить.
Другой подход, если вы не хотите добавлять настраиваемый 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
У меня был тот же вопрос, и мой ответ сам помог мне начать. Но я также нашел другое сообщение (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. Надеюсь, это поможет.
Посмотрите другие вопросы по меткам python django или Задайте вопрос