【问题标题】:Django Model: How to only access fields related to a specific user from another modelDjango 模型:如何仅从另一个模型访问与特定用户相关的字段
【发布时间】:2021-08-17 10:30:54
【问题描述】:

我如何只能从订单模型中访问指定用户(用户模型)的地址(地址模型)。 这是代码:Models.py

class User(AbstractBaseUser, PermissionsMixin):
    phone_number = PhoneField(max_length=12, primary_key=True, unique=True)

class Address(models.Model):
    address = models.CharField(max_length=500, blank=False,null=False,primary_key=True)
    customer = models.ForeignKey((User, on_delete= models.CASCADE)

class Order(models.Model):
    order = CharField(max_length=400,blank=False,null=False)
    customer = models.ForeignKey(User,on_delete=models.SET_NULL, null=True)
    address = models.ForeignKey(Address,on_delete=models.SET_NULL, null=True)

订单模型中的地址字段是我的问题。在 Django Administration 中创建新订单时,当我选择其中一个客户时,我仍然可以选择在数据库中注册的任何地址

如何限制对特定用户的地址访问。 提前致谢

【问题讨论】:

  • 您需要在表单中过滤它。您能否提供您尝试选择地址的视图?

标签: python django django-models


【解决方案1】:

您不能在模型中过滤它。您需要通过表单层来执行此操作。

我们可以通过以下方式实现:

class MyForm(forms.ModelForm):
    
    def __init__(self, *args, user=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['address'].queryset = Address.objects.filter(user=user)

    class Meta:
        model = Order
        fields = ['address']

那么在视图中,我们可以构造一个以登录用户为用户的表单:

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    if request.method == 'POST':
        form = MyForm(request.POST, user=request.user)
        if form.is_valid():
            form.instance.user = request.user
            # set the order number to the instance
            form.save()
            return redirect('name-of-some-view')
    else:
        form = MyForm(user=request.user)
    return render(request, 'name-of-some-template.html', {'form': form})

【讨论】:

  • 感谢它确实有帮助,但我是 Django 新手,并且能够将任何客户分配到管理中的任何地址,这让“我”感觉很混乱。有没有办法在管理中具有相同的行为?
【解决方案2】:

这取决于是否应允许客户拥有多个地址(如在大多数在线商店中)。在这种情况下,用户和地址模型看起来很不错!

Django Admin 可能有点棘手。但这只是流程的本质,因为当您打开“创建订单页面”时,服务器不知道您将选择哪个用户,因此不知道它应该过滤哪个地址。你必须使用 ajax 来达到你的目标,但我可以提出一些不同的建议......

问题是您为什么要在订单中添加另一个地址字段?不要误会我的意思,这实际上是正确的方法。但是……

如果用户点了东西,改变了他的地址对象并回顾了订单历史怎么办?

实际上,您可以在订单上删除地址外键,您仍然可以通过以下方式访问任何订单上的当前客户地址:

some_order = Order.objects.first()
customer = some_order.customer

# As defined in your model, one customer can have many addresses. For now just access the "latest" one
customers_address = customer.address_set.last()

但是订单历史仍然很混乱……现在更糟了。每当客户添加或更改地址时,订单历史记录都会显示错误的值。

为了防止这种情况,您可以保留外键,防止编辑 address_id(只读字段),防止编辑相关地址对象,并在地址对用户可见或软删除时添加标志.

你应该对read_only fieldseditableoverriding model methods做一些研究

但是为了让事情更简单一点,我们只需将 Order->address 字段更改为 Charfield 而不是外键。您不再需要在管理员中显示可编辑字段,而是让用户拥有他的默认地址。

class Order(models.Model):
    order = CharField(max_length=400,blank=False,null=False)
    customer = models.ForeignKey(User,on_delete=models.SET_NULL, null=True)
    shipping_address = models.CharField(max_length=500, editable=False)

    def save(self, *args, **kwargs):
        # You can use this field to stringify even more complex objects
        # Again, last() is not the right way in the end but you could have a specific field on the customer: preferred_address
        self.shipping_address = self.customer.address_set.last().address
        super().save(*args, **kwargs)

【讨论】:

    猜你喜欢
    • 2019-09-30
    • 2022-10-16
    • 2012-12-24
    • 2017-10-04
    • 2017-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-21
    相关资源
    最近更新 更多