在 Django 中,我有一个 Order 和 Contact 表,它们都有一个指向 User 表的foreignKeyField,在 Order 表中,我希望 ManyToManyField 仅查看属于同一 User 的 Contact 表记录的子集,而不是 ManyToManyField 查看所有记录联系人表的记录。
class Contact(models.Model):
cnt_user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=30, blank=False, null=True)
class Order(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='order_set')
ref_code = models.CharField(max_length=20, blank=True, null=True)
### ManyToManyField should only see subset of contacts that have same user.
contacts = models.ManyToManyField(Contact, blank=True, limit_choices_to={'cnt_user': user})
创建或更新订单记录的视图函数:
def create_or_update_order(request, cur_pk=None, mst_pk=None):
order = None
masterpk = None
verbal = 'New'
error = None
sender = None
if cur_pk:
print('cur_pk recieved')
# When Get or Post and jet cur_pk is criterium for edit state
verbal = 'Edit'
# If pk is given, get the record object
try:
order = Order.objects.get(pk=cur_pk)
# Haal detail records op
#if hoedanigheid != 'ParentCurrentNoDetail':
# = order.Detail_Subset.all()
except Order.DoesNotExist:
pass
## When a mst_pk is given
if mst_pk:
masterpk = mst_pk
else:
## Check if there is a masterpk
try:
if order.user_id:
masterpk = order.user_id
except AttributeError:
pass
if request.method == 'POST':
print('in post')
sender = request.POST.get('ctrl')
# Beeing in post is criterium for edit state
verbal = 'Edit'
form = OrderForm(request.POST, request.FILES, instance=order)
# If pk is given it is about an update
if cur_pk:
print('has pk')
print(cur_pk)
if form.is_valid():
print('orderform is valid')
form.save()
else:
print('orderform is not valid')
else:
if form.is_valid():
order = form.save(commit=False)
#order.creator = request.user
order.ordered_date = timezone.now()
if masterpk:
order.user_id = masterpk
order.save()
else:
error = 'Form not valid, new record not saved'
else:
print('in get')
form = OrderForm(instance=order)
ctrl = {'verbal': verbal, 'masterpk': masterpk, 'error': error, 'from': sender}
if sender == 'checkout':
return redirect('core:checkout')
else:
return render(request, 'core/create_or_update_order.html', {'form': form, 'ctrl': ctrl })
此视图的网址:
path("create/order/<int:mst_pk>/", order.create_or_update_order, name="create_order"),
path("edit/order/<int:cur_pk>/", order.create_or_update_order, name="edit_order"),
订单列表视图:
def list_by_user_order(request, mst_pk):
user = None
orders = None
verbal = 'List'
Error = None
# Get all records
try:
user = theUser.objects.get(pk=mst_pk)
except theUser.DoesNotExist:
pass
orders = user.order_set.all()
ctrl = {'verbal': verbal, 'error': Error, 'masterpk': mst_pk}
return render(request, 'core/list_order_by_user.html',
{'ctrl': ctrl, 'orders': orders,
'user': user})
列表视图网址:
path("list_by_theUser/order/<int:mst_pk>/", order.list_by_user_order, name="list_by_theUser_order"),
订单表格(为了可读性,省略了一些代码(字段):
class OrderForm(forms.ModelForm):
required_css_class = 'required'
class Meta:
model = Order
fields = ( 'ord_contactpersonen',)
我无法弄清楚如何设置 limit_choices_to 参数或如何在这种情况下使用可调用对象。
在此示例中 ({'cnt_user': user}) django 将 user 视为“foreignKey 对象”而不是“用户对象”,这会导致以下错误:
字段“id”需要一个数字,但得到了
对我来说,“这个问题”似乎并不罕见,我希望有一个简单的解决方案。 任何人都可以向我展示如何通过可调用对象或 Q 对象或任何其他方式(可能是代理模型)实现此目的的示例吗? 预先感谢。
有不同的方法可以解决您在代码中面临的这个挑战,包括在您看来覆盖它,我相信实现它的最简单方法是通过使用
Q
对象,因为我仍然想使用 limit_choices_to
如你所愿。我们将创建的 Q 对象将允许您根据数据库中的用户 ID 过滤联系人。但是,我们需要在 limit_choices_to
参数中访问用户的 ID。实现此目的的一种方法是使用自定义管理器方法,通过这种方法,我们将重写整个 models.py 代码片段,我们确信我们已经限制了 contacts
中
Order
字段的选择模特的
ManyToManyField
.
from django.conf import settings
from django.db import models
from django.db.models import Q
class ContactManager(models.Manager):
def get_queryset(self) -> models.QuerySet:
""" This method overrides the default get_queryset() method provided by the base
models.Manager class. It returns a QuerySet
of objects based on the specified filter conditions"""
queryset = super().get_queryset().\
filter(user_id = models.F('order__user_id'))
return queryset
# NB : filter(user_id=models.F('order__user_id')) above, filters the queryset based on
# the condition that the user_id field should be equal to the value of models.F('order__user_id')
class Contact(models.Model):
cnt_user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)
name = models.CharField(max_length=30, blank=False, null=True)
objects = ContactManager()
def __str__(self) -> str:
return self.cnt_user.username
class Order(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='order_set'
)
ref_code = models.CharField(max_length=20, blank=True, null=True)
### ManyToManyField should only see subset of contacts that have same user.
contacts = models.ManyToManyField(
Contact,
limit_choices_to=Q(
user_id=models.F('cnt_user_id'),
blank=True
))
# a human readable object setup instead of the data been #
# returned in as object1, object2 etc. in your admin panel.
def __str__(self):
return self.user.username
请原谅我发表了这么多评论,只是为了尽可能地表达清楚,如果您愿意,请不要忘记删除它们。祝你好运,伙计。