Как ограничить выбор внешних ключей связанными объектами только в 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 элементы.

72
0
10
Общее количество ответов: 10

Ответ #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 доступ к "себе".

44
4

  • @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

40
1

  • Хорошая идея и работает с уже созданными объектами, но я не вижу, как ее можно заставить работать с НОВЫМИ объектами, у которых еще нет ПК или какого-либо набора данных. Особенно внут ...

Ответ #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 где-то на самом деле я, но я не уверен.

18
2

  • В последней строке допущена опечатка: `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, чтобы узнать больше.

13
0

Ответ #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)

12
1

  • Хорошее место. Я отредактировал запро ...

Ответ #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 проверять после выбора.

4
0

Ответ #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

4
0

Ответ #8

Ответ на вопрос: Как ограничить выбор внешних ключей связанными объектами только в django

Вы хотите ограничить выбор, доступный в 9X_django-models интерфейсе администратора при создании / редактировании 9X_pythonista экземпляра модели?

Один из способов сделать 9X_pythonista это - проверить модель. Это позволяет вызвать 9X_django ошибку в интерфейсе администратора, если 9X_python-shell внешнее поле не является правильным выбором.

Конечно, ответ 9X_pythonista Эрика правильный: вам действительно нужен 9X_pythonista только один внешний ключ, от дочернего к 9X_django-imagefield родительскому.

3
0

Ответ #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 админку придется выполнять со стороны ребенка.

2
0

Ответ #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)

1
0