#django #django-models #django-views #django-templates #django-class-based-views
Вопрос:
Прямо сейчас я могу сохранить данные, но все товары сохраняются отдельно, а не в одном поле, так как я могу этого добиться, и я использую корзину в качестве сеанса, чтобы сохранить ее идентификатор и размер в качестве ключа и значения
мои модели.py, где я хочу сохранить порядок
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE,)
item = models.ForeignKey(Item, on_delete=models.CASCADE )
status = models.IntegerField(choices = status_choices, default=1)
method = models.CharField(max_length=50, blank=False,)
size = models.CharField(max_length=20, blank=False)
price = models.FloatField(blank=False)
created_at = models.DateField(auto_now=True, editable=False)
payment_status = models.IntegerField(choices = payment_status_choices, default=3)
order_id = models.CharField(unique=True, max_length=200, null=True, blank=True, default=None)
datetime_of_payment = models.DateTimeField(default=timezone.now)
def placeorder(self):
self.save()
def __str__(self):
return self.user.username
мой views.py для сохранения данных
и мой html, где отображается моя корзина
<tbody style="margin-bottom: 20px;">
{% for item in items %}
<tr>
<th scope="row">{{forloop.counter}}</th>
<td> <img src="{{item.first.url}}" alt="" height="100px"></td>
<td>{{item.name}}</td>
{% if item.swag %}
<td>{{item|cart_size:request.session.cart}}</td>
{% endif %}
{% if not item.swag %}
<td>Regular </td>
{% endif %}
<td>{{item.price|currency}}</td>
<td> <a href="#">Remove</a> </td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</aside>
<aside class="col-lg-3">
<div class="card mb-3">
<div class="card-body">
<form>
<div class="form-group"> <label>Have coupon?</label>
<div class="input-group"> <input type="text" class="form-control coupon" name="" placeholder="Coupon code"> <span class="input-group-append"> <button class="btn btn-primary btn-apply coupon">Apply</button> </span> </div>
</div>
</form>
</div>
</div>
<div class="card">
<div class="card-body">
<dl class="dlist-align">
<dt style="float: left; font-size:20px; margin-right:10px;">Total price:</dt>
<dd style="font-size: 20px; color:#025;" class="text-right">{{items|total_actual_price:request.session.cart|currency}}</dd>
</dl>
<dl class="dlist-align">
<dt style="float: left; font-size:20px; margin-right:10px;">Discount:</dt>
<dd style="font-size: 20px; color:#025;" class="text-right text-danger">{{items|discount_price:request.session.cart|currency}}</dd>
</dl>
<dl class="dlist-align">
<dt style="float: left; font-size:20px; margin-right:10px;">Total Paying Amount:</dt>
<dd style="font-size: 20px; color:#025;" class="text-right"><strong name="price" >{{items|total_price:request.session.cart|currency}}</strong></dd>
</dl>
<hr>
<a href="#" class="btn btn-out btn-primary btn-square btn-main" data-bs-toggle="modal" data-bs-target="#exampleModal"> Make Purchase </a> <a href="#" class="btn btn-out btn-success btn-square btn-main mt-2" data-abc="true">Continue Shopping</a>
</div>
</div>
</aside>
</div>
</div>
Как вы можете видеть, я использую фильтр, чтобы показать общую цену пользователя в его корзине, поэтому я хочу сохранить идентификатор товара всех товаров в поле «Товары» и размер в поле «Размер» в соответствии с их товаром, а вместо цены была сохранена общая цена.
Но прямо сейчас он сохраняет отдельное поле для товара, я этого не хочу
моя html-форма для оформления заказа и сохранения заказов
<div class="modal-body">
<form action="{% url 'orders:checkout' %}" method="Post">
{% csrf_token %}
<h3>Please Select Your Payment Method</h3> <br>
<div class="method" style="font-size: 23px;">
<input type="radio" value="postpaid" name="payment" style="height: 20px; width: 20px;">
<label for="postpaid">Cash On Delivery😊</label>
<input type="radio" value="Prepaid" name="payment" style="height: 20px; width: 20px;">
<label for="prepaid">Online Payment😎</label>
</div>
</div>
<input type="submit" class="btn float-right btn-primary" value='Go Ahead'>
</form>
модель изделия
class Item(models.Model):
categories = models.ForeignKey(Categories, on_delete=models.CASCADE, related_name='our_items')
subcategories = models.ForeignKey(Subcategories, on_delete=models.CASCADE, related_name='products')
name = models.CharField(max_length=200, blank=False)
contain_size = models.CharField(max_length=50, blank=True)
brand_name = models.CharField(max_length=100, blank=False, default='Bagh')
swag = models.BooleanField(blank=False, default=False)
male = models.BooleanField(blank=False, default=False)
female = models.BooleanField(blank=False, default=False)
unisex = models.BooleanField(blank=False, default=False)
first = models.ImageField(upload_to='items', blank=False)
second = models.ImageField(upload_to='items', blank=False)
third = models.ImageField(upload_to='items', blank=True)
fourth = models.ImageField(upload_to='items', blank=True)
fifth = models.ImageField(upload_to='items', blank=True)
sixth = models.ImageField(upload_to='items', blank=True)
seventh = models.ImageField(upload_to='items', blank=True)
rate = models.CharField(max_length=5, choices=rating, default='⭐⭐⭐⭐')
stock = models.CharField(max_length=50, blank=False, default='In Stock')
authentic = models.CharField(max_length=1,blank=False,choices=auth, default='✔')
price = models.FloatField(blank=False,)
actual_price = models.FloatField(blank=False)
type = models.CharField(blank=False, max_length=100, default='Cloth')
joined_date = models.DateTimeField(default=timezone.now,editable=False)
update_at = models.DateTimeField(auto_now=True)
description = models.TextField(blank=True)
@staticmethod
def get_items_by_id(ids):
return Item.objects.filter(id__in = ids)
def __str__(self):
return self.name
и просмотр корзины, в которую попадает весь товар после выбора пользователем
class Cart(View):
def get (self, request):
cart = request.session.get('cart', None)
if not cart:
cart = {}
request.session['cart'] = cart
ids = (list(cart.keys()))
ids = (list(request.session.get('cart').keys()))
item = Item.get_items_by_id(ids)
address = Address.objects.filter(user=request.user)
print(item)
return render(request, 'cart.html', {'items': item, 'addresses':address })
Это действительно сохраняет элемент в нем, но я хочу получить все элементы автомобиля в этом поле
adding updated model as told
class Order(models.Model):
status_choices = (
(1, 'PENDING'),
(2, 'CONFIRMED'),
(3, 'PACKED'),
(4, 'SHIPPED'),
(5, 'IN WAY'),
(6, 'ARRIVED DESTINATION'),
(7, 'RECIEVED'),
(8, 'COMPLETED')
)
payment_status_choices = (
(1, 'SUCCESS'),
(2, 'FAILURE' ),
(3, 'PENDING'),
)
user = models.ForeignKey(User, on_delete=models.CASCADE,)
address = models.ForeignKey(Address, default= True, on_delete=models.CASCADE )
status = models.IntegerField(choices = status_choices, default=1)
method = models.CharField(max_length=50, blank=False,)
total_price = models.FloatField(blank=False, default=0)
created_at = models.DateField(auto_now=True, editable=False)
payment_status = models.IntegerField(choices = payment_status_choices, default=3)
order_id = models.CharField(unique=True, max_length=200, null=True, default=None)
datetime_of_payment = models.DateTimeField(default=timezone.now)
# related to razorpay
razorpay_order_id = models.CharField(max_length=1000, null=True, blank=True)
razorpay_payment_id = models.CharField(max_length=1000, null=True, blank=True)
razorpay_signature = models.CharField(max_length=1000, null=True, blank=True)
def save(self, *args, **kwargs):
if self.order_id is None and self.datetime_of_payment and self.id:
self.order_id = self.datetime_of_payment.strftime('CODER%Y%m%dODR') str(self.id)
return super().save(*args, **kwargs)
def __str__(self):
return self.user.username " " str(self.order_id) " " str(self.created_at)
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE,)
item = models.ForeignKey(Item, on_delete=models.CASCADE )
size = models.CharField(max_length=20, blank=False)
price = models.FloatField(blank=False)
def __str__(self):
return self.order.order_id
обновлено views.py
class Checkout(View):
def post (self, request,):
user = request.user
address = Address.objects.filter(default=True, user=request.user)
cart = request.session.get('cart')
items = Item.get_items_by_id(list(cart.keys()))
prefer = request.POST.get('payment')
total_price = request.POST.get('paying_price')
total_price = json.loads(total_price)
with transaction.atomic():
order = Order.objects.create(
user=user,
total_price=total_price,
address=address.first(),
method = prefer,
)
for item in items:
item_order = OrderItem.objects.create(
order=order,
item=item,
size=cart.get(str(item.id)),
price=item.price,
)
request.session['cart'] = {}
return redirect('orders:cart',)
добавление обратной трассировки
Окружающая среда:
Request Method: POST
Request URL: http://localhost:8000/Check-Out/
Django Version: 3.2.6
Python Version: 3.8.5
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'crispy_forms',
'xhtml2pdf',
'accounts',
'products',
'orders']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']
Traceback (most recent call last):
File "C:UsersmithleshDesktopcoolbuylibsite-packagesdjangocorehandlersexception.py", line 47, in inner
response = get_response(request)
File "C:UsersmithleshDesktopcoolbuylibsite-packagesdjangocorehandlersbase.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:UsersmithleshDesktopcoolbuylibsite-packagesdjangoviewsgenericbase.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "C:UsersmithleshDesktopcoolbuylibsite-packagesdjangoviewsgenericbase.py", line 98, in dispatch
return handler(request, *args, **kwargs)
File "C:UsersmithleshDesktopcoolbuycoolbuyordersviews.py", line 61, in post
item_order = OrderItem.objects.create(
File "C:UsersmithleshDesktopcoolbuylibsite-packagesdjangodbmodelsmanager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:UsersmithleshDesktopcoolbuylibsite-packagesdjangodbmodelsquery.py", line 453, in create
obj.save(force_insert=True, using=self.db)
File "C:UsersmithleshDesktopcoolbuylibsite-packagesdjangodbmodelsbase.py", line 682, in save
self._prepare_related_fields_for_save(operation_name='save')
File "C:UsersmithleshDesktopcoolbuylibsite-packagesdjangodbmodelsbase.py", line 932, in _prepare_related_fields_for_save
raise ValueError(
Exception Type: ValueError at /Check-Out/
Exception Value: save() prohibited to prevent data loss due to unsaved related object 'order'.
Комментарии:
1. Вы хотите сказать, что Вам не нужны заказы в другой области ?
2. @Программист да, я имею в виду, что если человек создает заказ, все элементы этого заказа помещаются в одно поле вместо создания отдельного поля для каждого отдельного элемента в этом заказе
3. прежде всего, было бы лучше, если бы вы могли разделить модель. Один для заказа и один для элементов заказа. таким образом, у вас будет только одна строка для заказа.
4. вы предлагаете мне создать два разных названия модели заказа и элемента заказа
5. Не могли бы вы также опубликовать код для модели товара?
Ответ №1:
Как упоминалось в большинстве ответов, вы должны разделить модели на 2. Сценарий Order-OrderItem является хорошим примером отношений «Один ко многим».
Подумайте о том, чтобы заказать Роти, Панир (индийские блюда) и кока-колу в Swiggy (приложение для доставки индийской еды). Свигги говорит, что ваш идентификатор заказа #123456.
Модели должны выглядеть так.
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE,)
status = models.IntegerField(choices = status_choices, default=1)
method = models.CharField(max_length=50, blank=False,)
... other fields ...
Модель заказа указывает, что Заказ размещен пользователем Shreyas, способ оплаты-X, а текущий статус-это.
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE,)
item = models.ForeignKey(Item, on_delete=models.CASCADE )
size = models.CharField(max_length=20, blank=False)
price = models.FloatField(blank=False)
... any other fields ...
Модель OrderItem сообщает, что этот товар — Кока — кола-является частью идентификатора заказа № 123456, а цена на момент заказа составляет Rs.X.
Ваша база данных после сохранения должна выглядеть следующим образом —
Таблица заказов
ID | пользователь | метод | Статус |
---|---|---|---|
123456 | шрейас (удостоверение личности) | оплата | упорядоченные_место |
Таблица элементов заказа
ID | идентификатор заказа | item_id | размер | Цена |
---|---|---|---|---|
1 | 123456 | роти (удостоверение личности) | n | 10.00 |
2 | 123456 | панир (удостоверение личности) | n | 50.00 |
3 | 123456 | кока-кола (идентификатор) | n | 25.00 |
Сохранение вашего заказа
В коде есть with transaction.atomic
инструкция, которая позволяет вам написать все модели за один раз и вернуться, если какая-либо из инструкций записи завершится неудачно. Ссылка: Транзакции Django
class Checkout(View):
def post (self, request):
user = request.user
address = Address.objects.filter(user=request.user)
cart = request.session.get('cart')
total_price = request.POST.get('price')
items = Item.get_items_by_id(list(cart.keys()))
prefer = request.POST.get('payment')
with transaction.atomic:
order = Order.objects.create(
user=user,
date_of_payment=datetime.datetime.now(),
total_price=total_price,
address=address
)
for item in items:
prod_order = OrderItem.objects.create(
order=order
item=item,
size=item.size,
price=price,
)
... return the view ...
Комментарии:
1. сохранить() запрещено для предотвращения потери данных из-за несохраненного связанного объекта «заказ». это приводит к ошибке
2. Ваша обновленная модель не соответствует моему определению. Мое определение трактует отношения как «Один ко многим», ваше-как «Многие ко многим», которые будут иметь значение. Пожалуйста, обновите в соответствии с моим определением и попробуйте.
3. я уже изменил это на ключ foriegn и обновил свою модель здесь, теперь посмотрите
4. отступ прямо в модели, пожалуйста, не обращайте внимания
Ответ №2:
Здравствуйте, у меня есть опыт работы с электронной коммерцией , насколько я понимаю , вы хотите сохранить все детали товара ,такие как размер, цена, название, описание почты в одном поле .Это правда ?
если да , то я думаю, что напрямую это невозможно, вы можете попробовать одну вещь —
1.You can take all the desired data and create a dictionary or list out of them
2. Create a single textfield with more maxlength and a FK with user or customer model and then you can save the list or dict as text in that one field in db, and then can retrieve the all data as well as you can get by index also.
Но это будет более эффективно только для хранения данных , если вы хотите эффективно извлекать данные, а затем переходить к отдельным моделям, которые вы создали.
надеюсь, что так и будет , я применил ту же концепцию для хранения жалоб клиентов и платежных реквизитов пользователей, и мне нравится ваш код, вы следуете хорошей практике!
Комментарии:
1. я тоже так думал, но я думаю, что это не очень хороший способ для порядка просмотра, поэтому я ищу лучший и чистый метод
Ответ №3:
добавление ответа от @allexiusw
Лучшая практика для этого заключается в том, что вам нужно создать 2 модели с отношениями «многие ко многим» для product_order:
class Order(models.Model):
order_group_id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
product_order = models.ManyToManyField(OrderItem, related_name='order', null=True)
total_price = models.DecimalField(default=0, decimal_places=2, max_digits=10, null=True)
datetime_of_payment = models.DateTimeField(default=timezone.now, null=True)
...
class OrderItem(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE, null=True)
size = models.CharField(max_length=20, blank=False, null=True)
price = models.FloatField(blank=False, null=True)
...
Чтобы сохранить его в этих 2 моделях, вы можете сделать что-то вроде этого:
class Checkout(View):
def post (self, request):
user = request.user
address = Address.objects.filter(user=request.user)
cart = request.session.get('cart')
total_price = request.POST.get('price')
items = Item.get_items_by_id(list(cart.keys()))
prefer = request.POST.get('payment')
order = Order.objects.create(
user=user,
date_of_payment=datetime.datetime.now(),
total_price=total_price,
address=address)
for item in items:
prod_order = OrderItem.objects.create(
item=item,
size=item.size,
price=price,
)
order.product_order.add(prod_order)
order.save()
....
Комментарии:
1. вместо создания заказа он выдает ошибку НЕ НУЛЕВОЕ ограничение не удалось: orders_orderitem.order_id
2. Как ваш ответ виттена
3. я редактирую ответ, не забудьте добавить
null=True
во все поля, особенно если вы добавляете новое поле. и не забудьте доmakemigrations
иmigrate
после внести изменения в модель… @Шреяш4. Я вижу ваше последнее обновление, в вашей новой модели все не совсем так, как я вам рассказывал об отношениях в модели, а также о представлениях. посмотри еще раз! вам следует удалить
order
поле изProductOrder
и добавитьproduct_order = models.ManyToManyField(OrderItem, related_name='order', null=True)
в модельOrderItem
5. он выдает ошибку «Нетип», объект не имеет атрибута «добавить», и одна вещь, которую я не могу использовать, много ко многим полям, которые я должен использовать для ключа
Ответ №4:
Вам нужно разделить модель Order
на две модели:
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE,)
status = models.IntegerField(choices = status_choices, default=1)
method = models.CharField(max_length=50, blank=False,)
payment_status = models.IntegerField(choices = payment_status_choices, default=3)
order_id = models.CharField(unique=True, max_length=200, null=True, blank=True, default=None)
datetime_of_payment = models.DateTimeField(default=timezone.now)
created_at = models.DateField(auto_now=True, editable=False)
def placeorder(self):
self.save()
def __str__(self):
return self.user.username
class ProductOrder(models.Model):
order = models.ForeingKey(Order, on_delete=models.CASCADE)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
size = models.CharField(max_length=20, blank=False)
price = models.FloatField(blank=False)
Таким образом, у вас будет 1 заказ и много продуктов на заказ.
Комментарии:
1. итак, как я могу сохранить товар в корзине в этой модели заказа товара и все остальное в моей модели заказа