Django Model: Как получить доступ из другой модели только к полям, относящимся к определенному пользователю
Как я могу получить доступ только к адресам (модель Address) указанного пользователя (модель User) из модели Order. вот код: 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, когда я выбираю одного из клиентов, я все еще могу выбрать любой адрес, зарегистрированный в базе данных
Как я могу ограничить доступ к адресам для определенного пользователя. Заранее спасибо
Вы не можете фильтровать это в моделях. Это нужно делать на слое формы.
Мы можем реализовать это с помощью:
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']
затем в представлении мы можем построить форму с вошедшим пользователем в качестве user:
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})
В зависимости от того, нужно ли разрешить покупателям иметь несколько адресов (как в большинстве интернет-магазинов). В этом случае модели User и Address выглядят довольно хорошо!
Django Admin может быть немного запутанным. Но такова природа потока, потому что в тот момент, когда вы открываете "Create Order Page", сервер не имеет представления о том, какого пользователя вы выберете, и поэтому не знает, какой адрес он должен отфильтровать. Вам придется использовать ajax, чтобы достичь вашей цели, но я могу предложить кое-что другое...
Вопрос в том, зачем вы добавили еще одно поле адреса в заказ? Не поймите меня неправильно, на самом деле это правильный путь. Но...
Что если пользователь закажет что-то, изменит свой адрес объекта и посмотрит историю заказов?
На самом деле вы МОЖЕТЕ отбросить address-foreignkey в заказе, и вы все равно сможете получить доступ к текущему адресу клиента в любом заказе, по:
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 (поле только для чтения), предотвратить редактирование связанного объекта адреса и добавить флаг, если адрес виден пользователю или мягко удален
Вам следует провести некоторое исследование о полях только для чтения, изменяемых и переопределяющих методах модели
Но чтобы все было немного проще, давайте просто изменим поле 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)