Как ограничить выбор внешних ключей связанными объектами только в django
У меня двустороннее внешнее отношение, подобное 9X_pythonic следующему
class Parent(models.Model): name = models.CharField(max_length=255) favoritechild = models.ForeignKey("Child", blank=True, null=True) class Child(models.Model): name = models.CharField(max_length=255) myparent = models.ForeignKey(Parent)
Как ограничить выбор для Parent.favoritechild 9X_django-fields только детьми, родителем которых является 9X_python-interpreter я сам? Я пробовал
class Parent(models.Model): name = models.CharField(max_length=255) favoritechild = models.ForeignKey("Child", blank=True, null=True, limit_choices_to = {"myparent": "self"})
но из-за этого в интерфейсе 9X_python администратора не отображаются дочерние 9X_django-fields элементы.
Ответ #1
Ответ на вопрос: Как ограничить выбор внешних ключей связанными объектами только в django
Я только что наткнулся на ForeignKey.limit_choices_to в документации 9X_pythonic Django. Пока не знаю, как это работает, но, возможно, здесь 9X_django-models это правильно.
Обновление: ForeignKey.limit_choices_to 9X_py позволяет указать либо константу, либо вызываемый 9X_py объект, либо объект Q, чтобы ограничить 9X_python допустимый выбор для ключа. Очевидно, что 9X_django-imagefield константа здесь бесполезна, поскольку она 9X_pythonic ничего не знает о задействованных объектах.
Использование 9X_python вызываемого объекта (функции или метода 9X_python-shell класса или любого вызываемого объекта) кажется 9X_pythonista более перспективным. Однако проблема доступа 9X_python-interpreter к необходимой информации из объекта HttpRequest 9X_pythonic остается. Решением может стать использование 9X_python thread local storage.
2. Обновление: Вот что у меня сработало:
Я создал промежуточное 9X_python ПО, как описано в приведенной выше ссылке. Он 9X_pythonista извлекает один или несколько аргументов 9X_py из части запроса GET, например "product 9X_django-models = 1", и сохраняет эту информацию в 9X_django-models локальных переменных потока.
Затем в модели 9X_python-shell есть метод класса, который считывает локальную 9X_pythonista переменную потока и возвращает список идентификаторов, чтобы 9X_django-models ограничить выбор поля внешнего ключа.
@classmethod def _product_list(cls): """ return a list containing the one product_id contained in the request URL, or a query containing all valid product_ids if not id present in URL used to limit the choice of foreign key object to those related to the current product """ id = threadlocals.get_current_product() if id is not None: return [id] else: return Product.objects.all().values('pk').query
Важно 9X_py вернуть запрос, содержащий все возможные 9X_pythonista идентификаторы, если ни один не был выбран, чтобы 9X_python нормальные страницы администратора работали 9X_python-interpreter нормально.
Поле внешнего ключа объявляется 9X_django-models как:
product = models.ForeignKey( Product, limit_choices_to={ id__in=BaseModel._product_list, }, )
Загвоздка в том, что вы должны предоставить 9X_python-shell информацию для ограничения выбора через 9X_pythonic запрос. Я не вижу здесь способа получить 9X_pythonic доступ к "себе".
- @miraculixx Я действительно нашел это в документации того времени (должно быть, около версии 1.0). И вот я верну ...
Ответ #2
Ответ на вопрос: Как ограничить выбор внешних ключей связанными объектами только в django
"Правильный" способ сделать это - использовать 9X_django-models настраиваемую форму. Оттуда вы можете получить 9X_python-interpreter доступ к self.instance, который является 9X_pythonic текущим объектом. Пример -
from django import forms from django.contrib import admin from models import * class SupplierAdminForm(forms.ModelForm): class Meta: model = Supplier fields = "__all__" # for Django 1.8+ def __init__(self, *args, **kwargs): super(SupplierAdminForm, self).__init__(*args, **kwargs) if self.instance: self.fields['cat'].queryset = Cat.objects.filter(supplier=self.instance) class SupplierAdmin(admin.ModelAdmin): form = SupplierAdminForm
- Хорошая идея и работает с уже созданными объектами, но я не вижу, как ее можно заставить работать с НОВЫМИ объектами, у которых еще нет ПК или какого-либо набора данных. Особенно внут ...
Ответ #3
Ответ на вопрос: Как ограничить выбор внешних ключей связанными объектами только в django
Новый «правильный» способ сделать это, по 9X_python-shell крайней мере, с тех пор, как Django 1.1, - это 9X_django-fields переопределить AdminModel.formfield_for_foreignkey 9X_pythonic (self, db_field, request, ** kwargs).
См. http://docs.djangoproject.com/en/1.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_for_foreignkey
Для 9X_pythonista тех, кто не хочет переходить по ссылке ниже, приведен 9X_python пример функции, близкой к моделям, указанным 9X_py выше.
class MyModelAdmin(admin.ModelAdmin): def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == "favoritechild": kwargs["queryset"] = Child.objects.filter(myparent=request.object_id) return super(MyModelAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)
Я только не знаю, как получить текущий 9X_python-interpreter редактируемый объект. Я полагаю, что это 9X_pythonista где-то на самом деле я, но я не уверен.
- В последней строке допущена опечатка: `formfield_for_manytomany` ->` ...
Ответ #4
Ответ на вопрос: Как ограничить выбор внешних ключей связанными объектами только в django
Django работает не так. Вы создадите отношения 9X_pythonic только в одном направлении.
class Parent(models.Model): name = models.CharField(max_length=255) class Child(models.Model): name = models.CharField(max_length=255) myparent = models.ForeignKey(Parent)
И если бы вы 9X_django-models пытались получить доступ к дочерним элементам 9X_pythonista от родителя, вы бы сделали parent_object.child_set.all()
. Если вы установите 9X_pythonic related_name в поле myparent, то вы бы назвали 9X_python-interpreter его именно так. Пример: related_name='children'
, тогда вы должны 9X_django-models сделать parent_object.children.all()
Прочтите docs http://docs.djangoproject.com/en/dev/topics/db/models/#many-to-one-relationships, чтобы узнать больше.
Ответ #5
Ответ на вопрос: Как ограничить выбор внешних ключей связанными объектами только в django
Если вам нужны только ограничения в интерфейсе 9X_django-models администратора Django, это может сработать. Я 9X_pythonista основал его на this answer с другого форума - хотя 9X_pythonista он для отношений ManyToMany, вы должны иметь 9X_django-fields возможность заменить formfield_for_foreignkey
, чтобы он работал. В 9X_django-imagefield admin.py
:
class ParentAdmin(admin.ModelAdmin): def get_form(self, request, obj=None, **kwargs): self.instance = obj return super(ParentAdmin, self).get_form(request, obj=obj, **kwargs) def formfield_for_foreignkey(self, db_field, request=None, **kwargs): if db_field.name == 'favoritechild' and self.instance: kwargs['queryset'] = Child.objects.filter(myparent=self.instance.pk) return super(ChildAdmin, self).formfield_for_foreignkey(db_field, request=request, **kwargs)
- Хорошее место. Я отредактировал запро ...
Ответ #6
Ответ на вопрос: Как ограничить выбор внешних ключей связанными объектами только в django
@Ber: Я добавил проверку к модели, подобной 9X_python-shell этой
class Parent(models.Model): name = models.CharField(max_length=255) favoritechild = models.ForeignKey("Child", blank=True, null=True) def save(self, force_insert=False, force_update=False): if self.favoritechild is not None and self.favoritechild.myparent.id != self.id: raise Exception("You must select one of your own children as your favorite") super(Parent, self).save(force_insert, force_update)
который работает именно так, как я хочу, но 9X_python-interpreter было бы очень хорошо, если бы эта проверка 9X_pythonista могла ограничивать выбор в раскрывающемся 9X_django-models списке в интерфейсе администратора, а не 9X_django-models проверять после выбора.
Ответ #7
Ответ на вопрос: Как ограничить выбор внешних ключей связанными объектами только в django
Я пытаюсь сделать что-то подобное. Кажется, что 9X_python-shell все, кто говорит: «У вас должен быть только 9X_python-interpreter один внешний ключ», возможно, неправильно 9X_django-models поняли, что вы пытаетесь сделать.
Жаль, что 9X_python-interpreter limit_choices_to = {"myparent": "self"}, который 9X_django вы хотели сделать, не работает ... это было 9X_python-interpreter бы просто и ясно. К сожалению, "я" не 9X_django-fields оценивается и передается в виде простой 9X_python-interpreter строки.
Я подумал, может, у меня получится:
class MyModel(models.Model): def _get_self_pk(self): return self.pk favourite = models.ForeignKey(limit_choices_to={'myparent__pk':_get_self_pk})
Но, увы, это 9X_pythonic выдает ошибку, потому что функции не передается 9X_django собственный аргумент :(
Похоже, что единственный 9X_pythonic способ - поместить логику во все формы, использующие 9X_django-imagefield эту модель (т.е. передать набор запросов 9X_python в варианты выбора для вашего поля формы). Это 9X_python-interpreter легко сделать, но было бы СУХИЕ иметь это 9X_python-interpreter на уровне модели. Переопределение метода 9X_pythonic сохранения модели кажется хорошим способом 9X_django-fields предотвратить попадание неверных вариантов.
Обновить
См. Мой 9X_python-shell более поздний ответ, чтобы узнать о другом 9X_django способе https://stackoverflow.com/a/3753916/202168
Ответ #8
Ответ на вопрос: Как ограничить выбор внешних ключей связанными объектами только в django
Вы хотите ограничить выбор, доступный в 9X_django-models интерфейсе администратора при создании / редактировании 9X_pythonista экземпляра модели?
Один из способов сделать 9X_pythonista это - проверить модель. Это позволяет вызвать 9X_django ошибку в интерфейсе администратора, если 9X_python-shell внешнее поле не является правильным выбором.
Конечно, ответ 9X_pythonista Эрика правильный: вам действительно нужен 9X_pythonista только один внешний ключ, от дочернего к 9X_django-imagefield родительскому.
Ответ #9
Ответ на вопрос: Как ограничить выбор внешних ключей связанными объектами только в django
Альтернативный подход - не использовать 9X_python fk favouritechild в качестве поля в родительской 9X_django модели.
Вместо этого у вас может быть логическое 9X_python-interpreter поле is_favourite для дочернего элемента.
Это 9X_django может помочь: https://github.com/anentropic/django-exclusivebooleanfield
Таким образом вы обойдете 9X_django-fields всю проблему обеспечения того, чтобы Дети 9X_django-models могли стать фаворитами только Родителя, которому 9X_django-models они принадлежат.
Код представления будет 9X_python-shell немного другим, но логика фильтрации будет 9X_python-shell простой.
В админке у вас может быть даже 9X_py встроенная модель для дочерних моделей, которая 9X_python-interpreter выставляет флажок is_favourite (если у вас 9X_py есть только несколько дочерних элементов 9X_django на одного родителя), в противном случае 9X_django-fields админку придется выполнять со стороны ребенка.
Ответ #10
Ответ на вопрос: Как ограничить выбор внешних ключей связанными объектами только в django
Гораздо более простой вариант ответа @ s29:
Вместо 9X_py настройки формы Вы можете просто ограничить варианты, доступные в поле формы в вашем представлении:
у меня сработало: в forms.py:
class AddIncomingPaymentForm(forms.ModelForm): class Meta: model = IncomingPayment fields = ('description', 'amount', 'income_source', 'income_category', 'bank_account')
в 9X_python-shell views.py:
def addIncomingPayment(request): form = AddIncomingPaymentForm() form.fields['bank_account'].queryset = BankAccount.objects.filter(profile=request.user.profile)
-
8
-
13
-
5
-
2
-
6
-
4
-
3
-
14
-
4
-
13
-
3
-
14
-
10
-
6
-
11
-
17
-
2
-
2
-
13
-
3
-
5
-
8
-
4
-
6
-
7
-
3
-
2
-
12
-
3
-
14
-
1
-
3
-
12
-
9
-
9
-
4
-
6
-
4
-
15
-
4
-
2
-
7
-
1
-
6
-
5
-
2
-
4
-
3
-
3
-
12