<p>سلام</p><p>در این پروژه ای که استاد داره برای دوره میزنه امکان اضافه کردن چند فروشنده(partners) برای هر محصول رو داره</p><p>هنگامی که فرم اضافه کردن محصول به سبد خرید رو به صورت دستی ایجاد میکنیم مشکلی وجود ندارد اما</p><p>هنگامی که از فرم ساز جنگو برای ایجاد فرم استفاده میکنیم.</p><p>نمیدونم که باید چطور partner رو مقداردهی اولیه کنم تا کاربر نتونه که به صورت دستی partner رو انتخاب کنه</p><pre class=\"ql-syntax\" spellcheck=\"false\"><span class=\"hljs-keyword\">class</span> <span class=\"hljs-title class_\">Product</span>(models.Model):
product_type = models.ForeignKey(
to=ProductType,
on_delete=models.PROTECT,
related_name=<span class=\"hljs-string\">\'products\'</span>
)
upc = models.BigIntegerField(unique=<span class=\"hljs-literal\">True</span>)
title = models.CharField(max_length=<span class=\"hljs-number\">32</span>)
slug = models.SlugField(max_length=<span class=\"hljs-number\">32</span>, unique=<span class=\"hljs-literal\">True</span>)
description = models.TextField(blank=<span class=\"hljs-literal\">True</span>)
is_available = models.BooleanField(default=<span class=\"hljs-literal\">True</span>)
quantity = models.PositiveSmallIntegerField(default=<span class=\"hljs-number\">10</span>)
category = models.ForeignKey(
to=Category,
on_delete=models.PROTECT,
related_name=<span class=\"hljs-string\">\'products\'</span>
)
brand = models.ForeignKey(
to=Brand,
on_delete=models.PROTECT,
related_name=<span class=\"hljs-string\">\'products\'</span>
)
create_time = models.DateTimeField(auto_now_add=<span class=\"hljs-literal\">True</span>)
update_time = models.DateTimeField(auto_now=<span class=\"hljs-literal\">True</span>)
<span class=\"hljs-keyword\">def</span> __str__(self):
<span class=\"hljs-keyword\">return</span> <span class=\"hljs-string\">f\'[<span class=\"hljs-subst\">{self.product_type}</span>] - <span class=\"hljs-subst\">{self.title}</span>\'</span>
<span class=\"hljs-meta\"> @property</span>
<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">get_stock</span>(<span class=\"hljs-params\">self</span>):
<span class=\"hljs-keyword\">return</span> self.partners.order_by(<span class=\"hljs-string\">\'price\'</span>).first()
<span class=\"hljs-meta\"> @property</span>
<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">get_stocks</span>(<span class=\"hljs-params\">self</span>):
<span class=\"hljs-keyword\">return</span> self.partners.prefetch_related(<span class=\"hljs-string\">\'partner\'</span>).exclude(partner_id=self.get_stock.partner.pk).order_by(<span class=\"hljs-string\">\'price\'</span>)
</pre><p><br></p><pre class=\"ql-syntax\" spellcheck=\"false\"><span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">product_detail_view</span>(<span class=\"hljs-params\">request, pk, slug</span>):
qs = Product.objects.select_related(<span class=\"hljs-string\">\'category\'</span>, <span class=\"hljs-string\">\'brand\'</span>).<span class=\"hljs-built_in\">filter</span>((Q(pk=pk) | Q(upc=pk)) & Q(slug=slug)) <span class=\"hljs-comment\"># hit-1</span>
<span class=\"hljs-keyword\">if</span> qs.exists():
product = qs.first()
<span class=\"hljs-keyword\">else</span>:
<span class=\"hljs-keyword\">return</span> HttpResponse(<span class=\"hljs-string\">\'Product Does Not Exist\'</span>)
context = {
<span class=\"hljs-string\">\'product\'</span>: product,
<span class=\"hljs-string\">\'form\'</span>: AddToBasketForm(initial={<span class=\"hljs-string\">\'product\'</span>: product.pk, <span class=\"hljs-string\">\'quantity\'</span>: <span class=\"hljs-number\">1</span>})
}
<span class=\"hljs-keyword\">return</span> render(request, <span class=\"hljs-string\">\'catalogue/product-detail.html\'</span>, context=context)
</pre><p><br></p><pre class=\"ql-syntax\" spellcheck=\"false\"><span class=\"hljs-keyword\">class</span> <span class=\"hljs-title class_\">Partner</span>(models.Model):
name = models.CharField(max_length=<span class=\"hljs-number\">48</span>)
<span class=\"hljs-keyword\">def</span> __str__(self):
<span class=\"hljs-keyword\">return</span> self.name
<span class=\"hljs-keyword\">class</span> <span class=\"hljs-title class_\">PartnerStock</span>(models.Model):
product = models.ForeignKey(
to=Product,
on_delete=models.CASCADE,
related_name=<span class=\"hljs-string\">\'partners\'</span>
)
partner = models.ForeignKey(
to=Partner,
on_delete=models.CASCADE,
related_name=<span class=\"hljs-string\">\'products\'</span>
)
price = models.DecimalField(max_digits=<span class=\"hljs-number\">10</span>, decimal_places=<span class=\"hljs-number\">2</span>, default=<span class=\"hljs-number\">0</span>)
<span class=\"hljs-keyword\">def</span> __str__(self):
<span class=\"hljs-keyword\">return</span> <span class=\"hljs-string\">f\'<span class=\"hljs-subst\">{self.product}</span> - <span class=\"hljs-subst\">{self.partner}</span> - <span class=\"hljs-subst\">{self.price}</span>\'</span>
</pre><p><br></p><pre class=\"ql-syntax\" spellcheck=\"false\"><span class=\"hljs-keyword\">class</span> <span class=\"hljs-title class_\">Basket</span>(models.Model):
user = models.ForeignKey(
to=User,
on_delete=models.CASCADE,
related_name=<span class=\"hljs-string\">\'baskets\'</span>,
null=<span class=\"hljs-literal\">True</span>,
blank=<span class=\"hljs-literal\">True</span>
)
create_time = models.DateTimeField(auto_now_add=<span class=\"hljs-literal\">True</span>)
<span class=\"hljs-keyword\">def</span> __str__(self):
<span class=\"hljs-keyword\">return</span> <span class=\"hljs-string\">f\'<span class=\"hljs-subst\">{self.user}</span>\'</span>
<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">add</span>(<span class=\"hljs-params\">self, product, partner, quantity=<span class=\"hljs-number\">1</span></span>):
<span class=\"hljs-keyword\">if</span> self.lines.<span class=\"hljs-built_in\">filter</span>(product=product, partner=partner).exists():
product_line = self.lines.<span class=\"hljs-built_in\">filter</span>(product=product, partner=partner).first()
product_line.quantity += quantity
product_line.save()
<span class=\"hljs-keyword\">else</span>:
product_line = self.lines.create(product=product, partner=partner, quantity=quantity)
<span class=\"hljs-comment\"># product_line = BasketLine.objects.create(basket=self, product=product, quantity=quantity)</span>
<span class=\"hljs-keyword\">return</span> product_line
<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">validate_user</span>(<span class=\"hljs-params\">self, user</span>):
<span class=\"hljs-keyword\">if</span> user.is_authenticated:
<span class=\"hljs-keyword\">if</span> self.user <span class=\"hljs-keyword\">is</span> <span class=\"hljs-keyword\">not</span> <span class=\"hljs-literal\">None</span> <span class=\"hljs-keyword\">and</span> self.user != user:
<span class=\"hljs-keyword\">return</span> <span class=\"hljs-literal\">False</span>
<span class=\"hljs-keyword\">if</span> self.user <span class=\"hljs-keyword\">is</span> <span class=\"hljs-literal\">None</span>:
self.user = user
self.save()
<span class=\"hljs-keyword\">elif</span> self.user <span class=\"hljs-keyword\">is</span> <span class=\"hljs-keyword\">not</span> <span class=\"hljs-literal\">None</span>:
<span class=\"hljs-keyword\">return</span> <span class=\"hljs-literal\">False</span>
<span class=\"hljs-keyword\">return</span> <span class=\"hljs-literal\">True</span>
<span class=\"hljs-meta\"> @classmethod</span>
<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">get_or_create_basket</span>(<span class=\"hljs-params\">cls, basket_id</span>):
<span class=\"hljs-keyword\">if</span> basket_id <span class=\"hljs-keyword\">is</span> <span class=\"hljs-literal\">None</span>:
basket = cls.objects.create()
<span class=\"hljs-keyword\">else</span>:
basket_qs = cls.objects.<span class=\"hljs-built_in\">filter</span>(pk=basket_id)
<span class=\"hljs-keyword\">if</span> basket_qs.exists():
basket = basket_qs.first()
<span class=\"hljs-keyword\">else</span>:
basket = <span class=\"hljs-literal\">None</span>
<span class=\"hljs-keyword\">return</span> basket
<span class=\"hljs-keyword\">class</span> <span class=\"hljs-title class_\">BasketLine</span>(models.Model):
basket = models.ForeignKey(
to=Basket,
on_delete=models.CASCADE,
related_name=<span class=\"hljs-string\">\'lines\'</span>
)
product = models.ForeignKey(
to=Product,
on_delete=models.CASCADE,
related_name=<span class=\"hljs-string\">\'lines\'</span>
)
partner = models.ForeignKey(
to=Partner,
on_delete=models.CASCADE,
related_name=<span class=\"hljs-string\">\'lines\'</span>
)
quantity = models.PositiveSmallIntegerField(default=<span class=\"hljs-number\">1</span>)
<span class=\"hljs-keyword\">def</span> __str__(self):
<span class=\"hljs-keyword\">return</span> <span class=\"hljs-string\">f\'<span class=\"hljs-subst\">{self.basket}</span> - <span class=\"hljs-subst\">{self.product.title}</span> - <span class=\"hljs-subst\">{self.quantity}</span>\'</span>
</pre><p><br></p><pre class=\"ql-syntax\" spellcheck=\"false\">class AddToBasketForm(forms.Form):
product = forms.<span class=\"hljs-built_in\">ModelChoiceField</span>(queryset=Product.objects.<span class=\"hljs-built_in\">all</span>(), widget=forms.<span class=\"hljs-built_in\">HiddenInput</span>())
partner = forms.<span class=\"hljs-built_in\">ModelChoiceField</span>(queryset=Partner.objects.<span class=\"hljs-built_in\">all</span>())
quantity = forms.<span class=\"hljs-built_in\">IntegerField</span>()
def <span class=\"hljs-built_in\">save</span>(self, basket):
product = self.cleaned_data.<span class=\"hljs-built_in\">get</span>(<span class=\"hljs-string\">\'product\'</span>)
partner = self.cleaned_data.<span class=\"hljs-built_in\">get</span>(<span class=\"hljs-string\">\'partner\'</span>)
quantity = self.cleaned_data.<span class=\"hljs-built_in\">get</span>(<span class=\"hljs-string\">\'quantity\'</span>)
basket.<span class=\"hljs-built_in\">add</span>(product=product, partner=partner, quantity=quantity)
return basket
</pre><p><br></p><pre class=\"ql-syntax\" spellcheck=\"false\">
<span class=\"hljs-meta\">@require_POST</span>
<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">add_to_basket</span>(<span class=\"hljs-params\">request</span>):
<span class=\"hljs-comment\"># TODO-1: Check if user has basket_id in cookie</span>
<span class=\"hljs-comment\"># TODO-2: Create and assign if doesn\'t have</span>
<span class=\"hljs-comment\"># TODO-2-1: Check if user is authenticated, set user to basket</span>
<span class=\"hljs-comment\"># TODO-3: Get product and partner from submitted form</span>
<span class=\"hljs-comment\"># TODO-4: Add product to the user basket lines</span>
<span class=\"hljs-comment\"># TODO-5: Return to the \'next\' url</span>
response = HttpResponseRedirect(request.POST.get(<span class=\"hljs-string\">\'next\'</span>, <span class=\"hljs-string\">\'/\'</span>))
basket_id = request.COOKIES.get(<span class=\"hljs-string\">\'basket_id\'</span>, <span class=\"hljs-literal\">None</span>)
basket = Basket.get_or_create_basket(basket_id=basket_id)
<span class=\"hljs-keyword\">if</span> basket <span class=\"hljs-keyword\">is</span> <span class=\"hljs-literal\">None</span>:
<span class=\"hljs-keyword\">raise</span> Http404
response.set_cookie(key=<span class=\"hljs-string\">\'basket_id\'</span>, value=basket.<span class=\"hljs-built_in\">id</span>)
<span class=\"hljs-keyword\">if</span> <span class=\"hljs-keyword\">not</span> basket.validate_user(user=request.user):
<span class=\"hljs-keyword\">raise</span> Http404
form = AddToBasketForm(data=request.POST)
<span class=\"hljs-keyword\">if</span> form.is_valid():
form.save(basket=basket)
<span class=\"hljs-keyword\">return</span> response
</pre><p><br></p><pre class=\"ql-syntax\" spellcheck=\"false\">
{% block content %}
<span class=\"hljs-tag\"><<span class=\"hljs-name\">h1</span>></span>Product Detail<span class=\"hljs-tag\"></<span class=\"hljs-name\">h1</span>></span>
<span class=\"hljs-tag\"><<span class=\"hljs-name\">p</span>></span>title: {{ product.title }}<span class=\"hljs-tag\"></<span class=\"hljs-name\">p</span>></span>
<span class=\"hljs-tag\"><<span class=\"hljs-name\">p</span>></span>category: {{ product.category.name }}<span class=\"hljs-tag\"></<span class=\"hljs-name\">p</span>></span>
<span class=\"hljs-tag\"><<span class=\"hljs-name\">p</span>></span>brand: {{ product.brand.name }}<span class=\"hljs-tag\"></<span class=\"hljs-name\">p</span>></span>
<span class=\"hljs-tag\"><<span class=\"hljs-name\">p</span>></span>quantity: {{ product.quantity }}<span class=\"hljs-tag\"></<span class=\"hljs-name\">p</span>></span>
{% if product.get_stock %}
<span class=\"hljs-tag\"><<span class=\"hljs-name\">h4</span>></span>- Recommended reseller<span class=\"hljs-tag\"></<span class=\"hljs-name\">h4</span>></span>
<span class=\"hljs-tag\"><<span class=\"hljs-name\">p</span> <span class=\"hljs-attr\">class</span>=<span class=\"hljs-string\">\"partner\"</span>></span>partner: {{ product.get_stock.partner.name }}<span class=\"hljs-tag\"></<span class=\"hljs-name\">p</span>></span>
<span class=\"hljs-tag\"><<span class=\"hljs-name\">p</span> <span class=\"hljs-attr\">class</span>=<span class=\"hljs-string\">\"price\"</span>></span>price: ${{ product.get_stock.price }}<span class=\"hljs-tag\"></<span class=\"hljs-name\">p</span>></span>
<span class=\"hljs-tag\"><<span class=\"hljs-name\">form</span> <span class=\"hljs-attr\">method</span>=<span class=\"hljs-string\">\"post\"</span> <span class=\"hljs-attr\">action</span>=<span class=\"hljs-string\">\"{% url \'basket:add-to-basket\' %}\"</span>></span>
{% csrf_token %}
{{ form.as_p }}
<span class=\"hljs-tag\"><<span class=\"hljs-name\">input</span> <span class=\"hljs-attr\">type</span>=<span class=\"hljs-string\">\"hidden\"</span> <span class=\"hljs-attr\">name</span>=<span class=\"hljs-string\">\"next\"</span> <span class=\"hljs-attr\">value</span>=<span class=\"hljs-string\">\"{{ request.build_absolute_uri }}\"</span>></span>
<span class=\"hljs-tag\"><<span class=\"hljs-name\">button</span> <span class=\"hljs-attr\">type</span>=<span class=\"hljs-string\">\"submit\"</span>></span>Add to basket<span class=\"hljs-tag\"></<span class=\"hljs-name\">button</span>></span>
<span class=\"hljs-tag\"></<span class=\"hljs-name\">form</span>></span>
<span class=\"hljs-tag\"><<span class=\"hljs-name\">h4</span>></span>- Other reseller<span class=\"hljs-tag\"></<span class=\"hljs-name\">h4</span>></span>
{% for stock in product.get_stocks %}
<span class=\"hljs-tag\"><<span class=\"hljs-name\">div</span>></span>
<span class=\"hljs-tag\"><<span class=\"hljs-name\">p</span> <span class=\"hljs-attr\">class</span>=<span class=\"hljs-string\">\"partner\"</span>></span>partner: {{ stock.partner.name }}<span class=\"hljs-tag\"></<span class=\"hljs-name\">p</span>></span>
<span class=\"hljs-tag\"><<span class=\"hljs-name\">p</span> <span class=\"hljs-attr\">class</span>=<span class=\"hljs-string\">\"price\"</span>></span>price: ${{ stock.price }}<span class=\"hljs-tag\"></<span class=\"hljs-name\">p</span>></span>
<span class=\"hljs-tag\"><<span class=\"hljs-name\">form</span> <span class=\"hljs-attr\">method</span>=<span class=\"hljs-string\">\"post\"</span> <span class=\"hljs-attr\">action</span>=<span class=\"hljs-string\">\"{% url \'basket:add-to-basket\' %}\"</span>></span>
{% csrf_token %}
{{ form.as_p }}
<span class=\"hljs-tag\"><<span class=\"hljs-name\">input</span> <span class=\"hljs-attr\">type</span>=<span class=\"hljs-string\">\"hidden\"</span> <span class=\"hljs-attr\">name</span>=<span class=\"hljs-string\">\"next\"</span> <span class=\"hljs-attr\">value</span>=<span class=\"hljs-string\">\"{{ request.build_absolute_uri }}\"</span>></span>
<span class=\"hljs-tag\"><<span class=\"hljs-name\">button</span> <span class=\"hljs-attr\">type</span>=<span class=\"hljs-string\">\"submit\"</span>></span>Add to basket<span class=\"hljs-tag\"></<span class=\"hljs-name\">button</span>></span>
<span class=\"hljs-tag\"></<span class=\"hljs-name\">form</span>></span>
<span class=\"hljs-tag\"></<span class=\"hljs-name\">div</span>></span>
{% empty %}
<span class=\"hljs-tag\"><<span class=\"hljs-name\">h3</span>></span>Not other reseller<span class=\"hljs-tag\"></<span class=\"hljs-name\">h3</span>></span>
{% endfor %}
{% endif %}
{% endblock content %}
</pre>