【问题标题】:Django ModelChoice Field Conditional ForeignKeyDjango ModelChoice 字段条件外键
【发布时间】:2018-08-20 21:16:48
【问题描述】:

我下午大部分时间都在冲浪,并且在这个特殊的困境中已经有一段时间了。

如果用户驾驶过这种类型的汽车,我试图弄清楚如何从本质上将外键呈现为下拉选项。出于示例目的并使其尽可能简单...

假设我有一个CarsManufacturers 和一个UserProfile 模型。

我有一个Cars 的模型...

class Cars(models.Model):

    car_name = models.CharField(max_length=80)    
    class = models.ForeignKey(Manufacturer,null=True,on_delete=models.DO_NOTHING,related_name='car_manufacturer')

我有一个Manufacturers 的模型...

class Manufacturers(models.Model):

        manu_name = models.CharField(max_length=80)  

然后我有一个UserProfile 模型....

class Userprofile(models.Model):

   user = models.OneToOneField(User,on_delete=models.CASCADE)
   user_name = models.CharField(max_length=80)    
   car_owned = models.ForeignKey(Car,null=True,on_delete=models.DO_NOTHING,related_name='car_owned')

到目前为止一切都很好......

我有一个视图,我列出了所有Manufacturers,这也很好。它在下面的表单视图中显示了我期望的所有制造商。

class ManufacturerForm(forms.Form):

    dropdown = forms.ModelChoiceField(queryset=Manufacturer.objects.all())

    def __init__(self, *args, **kwargs):
        super(ManufacturerForm, self).__init__(*args, **kwargs)
        self.fields['dropdown'].widget.attrs['class'] = 'choices1'
        self.fields['dropdown'].empty_label = ''

我正在使用下面的 FORMVIEW 来显示表单...

class ManufacturerView(LoginRequiredMixin,FormView):
    form_class = ManufacturerForm
    template_name = 'Directory/HTMLNAME.html'

    def get_form_kwargs(self):
        kwargs = super(ManufacturerView, self).get_form_kwargs()
        kwargs['user'] = self.request.user
        return kwargs

    def form_valid(self, form):
        manufacturer = form.cleaned_data['dropdown']
        return HttpResponseRedirect(reverse("NAME:manufacturer",kwargs={'pk':manufacturer.pk}))

这一切都很好。但是,我不知道如何将制造商下拉列表限制为仅用户驾驶的汽车。我试图从本质上将下拉显示限制为仅与用户根据其个人资料拥有的汽车相关的制造商。我研究了反向查找,并尝试了类似于下面概述的方法来解决我的问题...

class ManufacturerForm(forms.Form):

    dropdown = forms.ModelChoiceField(queryset=Manufacturer.objects.filter(car_manufacturer=1)

    def __init__(self, *args, **kwargs):
        super(ManufacturerForm, self).__init__(*args, **kwargs)
        self.fields['dropdown'].widget.attrs['class'] = 'choices1'
        self.fields['dropdown'].empty_label = ''

但这显然只给了我Manufacturer 模型的记录1。我试图弄清楚如何根据他们的 car_owned 数据仅显示与个人用户相关的记录。我可以列出所有制造商,然后只显示ListView 中的相关记录,但我试图将下拉列表限制为仅在ListView 中有相关记录的地方。提前感谢您的任何想法。

【问题讨论】:

    标签: django python-3.x django-models django-forms django-views


    【解决方案1】:

    您只错过了几点:
    1)通过UserProfile作为kwargs['user']

    kwargs['user'] = UserProfile.objects.get(user=self.request.user)  
    

    2) 在表单的__init__ 签名中添加user 参数并在此处覆盖dropdown.queryset

    class ManufacturerForm(forms.Form):
        dropdown = forms.ModelChoiceField(queryset=Manufacturer.objects.all())
    
        def __init__(self, user, *args, **kwargs):
            super(ManufacturerForm, self).__init__(*args, **kwargs)
            self.fields['dropdown'].widget.attrs['class'] = 'choices1'
            self.fields['dropdown'].empty_label = ''
            self.fields['dropdown'].queryset = Manufacturer.objects.filter(car_manufacturer__car_owned=user)
    

    另外,我想建议将您的Car - User 关系重写为ManyToMany。如果我正确理解您的信息,用户可以拥有多辆汽车:

    将下拉菜单限制为仅显示 与用户拥有的汽车s相关

    另外,如果我理解正确,您想跟踪用户曾经拥有(但不再拥有)的汽车。
    如果您重写Car - User 关系,那么您可能没有任何理由保留UserProfile 模型只是为了持有额外的username。如果是这样,您的 models.py 应该如下所示:

    class Manufacturer(models.Model):
        name = models.CharField(max_length=80)
    
    
    class Car(models.Model):
        name = models.CharField(max_length=80)
        klass = models.ForeignKey(Manufacturer, null=True, on_delete=models.DO_NOTHING, related_name='car_manufacturer')
        owners = models.ManyToManyField(User, through='Ownership')
    
    
    class Ownership(models.Model):
        user = models.ForeignKey(User, on_delete=models.CASCADE)
        car = models.ForeignKey(Car, on_delete=models.CASCADE)
        active = models.BooleanField(default=True)   # True if user owns the car at the moment
    

    【讨论】:

    • 谢谢!这是让我绊倒的部分......Manufacturer.objects.filter(car_manufacturer__car_owned=user)..我可能会添加一整天!!!
    【解决方案2】:

    我认为这完全取决于您的订单和模型之间的关系,也许可以尝试在ManufacturerCar 之间添加ManyToMany 关系,这样一个制造商就可以制造很多汽车:

    类制造商(models.Model):

    name = models.CharField(max_length=80)
    car = models.ManyToManyField(Car)
    

    那么可能是这样的情况:

    qs = Manufacturer.objects.all(car=user.car_owned)
    
    dropdown = forms.ModelChoiceField(qs)
    

    在您的views.py 文件中:

    form = ManufacturerForm(request.POST, user=request.user)
    

    (您可能需要查看以上是否有效,因为我不确定Forms是否可以传入请求对象。

    免责声明:我看到您使用的是基于 class 的视图...所以我可能需要调整上述内容。

    【讨论】:

    • 感谢您抽出宝贵时间回复。我在玩你的建议,但它似乎不起作用。 qs = Manufacturer.objects.all 的关键字部分存在问题。如果我输入硬编码 car=1 或 car=2 或 car=3 以外的任何内容,则会出错。
    • 嗨史蒂夫 - 不用担心,您收到的错误是什么?
    • 大致上未定义。关键字语法似乎导致错误。
    • 跟form=ManufacturerForm...行吗?
    • 我也重命名了你的类,因为一个类代表一个对象,所以没有一个是复数的。您实例化同一对象的多个实例,因此用户、汽车、制造商等忽略我的迂腐性质,并且可能将我使用制造商的任何地方更改为定义为制造商的类。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-16
    • 2019-06-29
    • 2020-10-20
    • 2014-08-24
    • 2015-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多