如何在模型名称订单的单个字段中由用户获取购物车的所有项目
Posted
技术标签:
【中文标题】如何在模型名称订单的单个字段中由用户获取购物车的所有项目【英文标题】:how to fetch all the item of a cart by a user in single field of model name orders 【发布时间】:2021-10-07 13:22:03 【问题描述】:现在我可以保存数据,但所有项目都单独保存而不是在一个字段中,所以我如何实现这一点,我使用购物车作为会话将其 id 和大小保存为键和值
我要保存订单的models.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" ></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>
如您所见,我正在使用过滤器来显示用户购物车的总价格,所以我想要的是保存项目字段中所有项目的项目 ID 和尺寸字段中的大小,根据他们的项目并代替价格总价得到了保存。 但是现在它正在为项目保存单独的字段,我不想要那个
我用于结帐和保存订单的 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:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\views\generic\base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "C:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\views\generic\base.py", line 98, in dispatch
return handler(request, *args, **kwargs)
File "C:\Users\mithlesh\Desktop\coolbuy\coolbuy\orders\views.py", line 61, in post
item_order = OrderItem.objects.create(
File "C:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\db\models\manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\db\models\query.py", line 453, in create
obj.save(force_insert=True, using=self.db)
File "C:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\db\models\base.py", line 682, in save
self._prepare_related_fields_for_save(operation_name='save')
File "C:\Users\mithlesh\Desktop\coolbuy\lib\site-packages\django\db\models\base.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'.
【问题讨论】:
你的意思是,你不想要不同领域的订单? @PrOgRaMmEr 是的,我的意思是,如果一个人创建一个订单,该订单的所有项目都放在一个字段中,而不是为该订单中的每个项目创建单独的字段 首先,如果可以拆分模型会更好。一个用于订单,一个用于订单项目。这样你就只有一行订单了。 你是在建议我创建两个不同的型号名称订单和订单项 你能把物品模型的代码也贴出来吗? 【参考方案1】:正如大多数答案中提到的,您必须将模型分成 2 个。Order-OrderItem 场景是一对多关系的一个很好的例子。
假设您从 Swiggy(印度食品配送应用程序)订购 Roti、Paneer(印度菜)和可乐。 Swiggy 说您的订单 ID 是 #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 ...
Order 模型告诉用户 Shreyas 下订单,付款方式为 X,当前状态为 this。
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 模型表明该商品 - 可口可乐 - 是订单 ID #123456 的一部分,订购时的价格为 Rs.X。
保存后你的数据库应该是这样的 -
订单表
id | user | method | status |
---|---|---|---|
123456 | shreyas (id) | payment | order_placed |
OrderItem 表
id | order_id | item_id | size | price |
---|---|---|---|---|
1 | 123456 | roti (id) | n | 10.00 |
2 | 123456 | paneer (id) | n | 50.00 |
3 | 123456 | coke (id) | n | 25.00 |
保存您的订单
代码中有一个with transaction.atomic
语句,这使您可以一次编写所有模型,并在任何写入语句失败时恢复。参考:Django transactions
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 ...
【讨论】:
save() 禁止以防止由于未保存的相关对象“订单”而导致数据丢失。它抛出错误 您更新的模型不符合我的定义。我的定义将关系视为一对多,而您的定义将其视为多对多,这会有所作为。请按照我的定义更新并尝试。 我已经把它改成了外键,现在在这里更新我的模型看看 模型中有缩进,请不要介意【参考方案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.\
但仅存储数据会更有效,如果您想有效地检索数据,请使用您创建的单独模型。
希望它有,我已经应用了相同类型的概念来存储客户的投诉和用户的付款详细信息,我喜欢你的代码,你正在遵循良好的做法!
【讨论】:
我也想过这个问题,但我想这不是查看顺序的好方法,所以我正在寻找更好更干净的方法【参考方案3】:添加来自@allexiusw 的答案
最好的做法是,您需要为 product_order 创建 2 个具有多对多关系的模型:
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()
....
【讨论】:
不是创建订单而是抛出错误 NOT NULL 约束失败:orders_orderitem.order_id 作为您的智慧答案 我正在编辑答案,如果您添加新字段,请不要忘记将null=True
添加到所有字段中。在进行模型更改后不要忘记makemigrations
和migrate
... @Shreyash
我看到你的最新更新,你的新模型与我告诉你的模型关系和视图不完全一样。再看一遍!您应该从ProductOrder
中删除order
字段,并将product_order = models.ManyToManyField(OrderItem, related_name='order', null=True)
添加到模型OrderItem
它抛出错误'NoneType'对象没有属性'add',一件事我不能使用多对多字段我必须使用外键【参考方案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-Order 和 Many-Productos。
【讨论】:
那么我如何在这个产品订单模型中保存购物车项目以及在我的订单模型中保存所有其他东西以上是关于如何在模型名称订单的单个字段中由用户获取购物车的所有项目的主要内容,如果未能解决你的问题,请参考以下文章
在 Woocommerce 订单和电子邮件通知中显示产品品牌和名称
如何在 Woocommerce 购物车页面中添加订单备注字段?