@KenWhitesell @anilrai21
I really appreciate you help
I would like to clarify that I’m saving the photos to the MEDIA folder through using the corresponding settings in the settings.py and urls.py as you can see here
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
where BASE_DIR is
BASE_DIR = Path(__file__).resolve().parent.parent
for the urls.py
from django.contrib import admin
from django.urls import path, include
from . import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('store.urls')),
path('cart/', include('cart.urls')),
path('payment/', include('payment.urls'))
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
AND I’m using 2 views for the PRODUCT model
the first one is to add new product
if request.user.is_authenticated:
user = Profile.objects.get(user=request.user.id)
shops = Vendor.objects.filter(id = request.user.id)
product_form = Product_Form(request.POST or None , request.FILES, request=request)# , initial={'vendor': vendor.id})
if request.method == 'POST':
if product_form.is_valid():
product_form.save()
messages.success(request, 'You Added a new Product successfuly')
return redirect('update_user')
else:
for error in list(product_form.errors.values()):
print(request.body)
messages.error(request, error)
return redirect('update_user')
else:
return render(request, "add_new_product.html", {"product_form": product_form} )
else:
messages.success(request, "You Must be Logged in to access this page")
return redirect('home')
this views works fine and it adds new photo for each new product
the problem is with the update product view
def edit_product(request, id):
if request.user.is_authenticated:
product = Product.objects.get(id=id)
shop_id = product.vendor.id
# Prevent other users from accessing current user data
if request.user == product.vendor.owner.user:
# print(shop_id)
print(request.FILES)
product_form = Product_Form(request.POST or None, instance=product, request=request)
if request.method == 'POST':
if product_form.is_valid():
product_form.save()
messages.success(request, "Shop has Been Updated")
return redirect('update_user')
else:
for error in list(product_form.errors.values()):
print(request.body)
messages.error(request, error)
return redirect('update_user')
else:
return render(request, "edit_product.html", {"product_form": product_form, 'shop_id': shop_id})
else:
messages.success(request, "You are UNAUTHORIZED to access this page")
return redirect('home')
else:
messages.success(request, "You Must be Logged in to access this page")
return redirect('home')
the main difference between the 2 views is that the second one I use an existing product instance to fill in the form
so I use
product_form = Product_Form(request.POST or None, instance=product, request=request)
when I used it like that
product_form = Product_Form(request.POST or None , instance=product, request.FILES, request=request)
the instance data is lost completely
and here are the form class
class Product_Form(forms.ModelForm):
name = forms.CharField(label="", widget=forms.TextInput(attrs={'class':'form-control', 'placeholder':' enter your product name'}), required=True , error_messages = {'required':"Please Enter your Name1"})
price = forms.DecimalField(label="", widget=forms.TextInput(attrs={'class':'form-control', 'placeholder':' price'}), required=True , error_messages = {'required':"Please Enter your Name2"})
category = forms.ModelChoiceField(label="category",queryset=Category.objects.all() , required=True, error_messages = {'required':"Please Enter your Name3"})
# vendor = forms.CharField(label="vendor", widget=forms.Select(attrs={'class':'form-control', 'disabled': 'disabled'}), required=False)
description = forms.CharField(label="description", widget=forms.TextInput(attrs={'class':'form-control', 'placeholder':' description'}), required=True , error_messages = {'required':"Please Enter your Name4"})
image = forms.ImageField(label="upload product image", required=False, error_messages = {'required':"Please Enter your Name5"})
is_sale = forms.BooleanField(label="is_sale", required=False , error_messages = {'required':"Please Enter your Name6"})
sale_price = forms.DecimalField(label="sale_price", widget=forms.TextInput(attrs={'class':'form-control', 'placeholder':' sale price'}), required=True , error_messages = {'required':"Please Enter your Name7"})
is_not_available = forms.BooleanField(label="is_not_available", required=False , error_messages = {'required':"Please Enter your Name8"})
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request")
super(Product_Form, self).__init__(*args, **kwargs)
owner = Profile.objects.get(user=self.request.user)
self.fields["vendor"].queryset = Vendor.objects.filter(owner = owner)
class Meta:
model = Product
fields = ("name", "price", "category", 'vendor' , "description", "image", "is_sale", "sale_price", "is_not_available")
here is the tempate
{% extends 'base.html' %}
{% block content %}
<!-- Header-->
<header class="bg-dark py-5">
<div class="container px-4 px-lg-5 my-5">
<div class="text-center text-white">
<h1 class="display-4 fw-bolder">Shop in style</h1>
<p class="lead fw-normal text-white-50 mb-0">With this shop hompeage template</p>
</div>
</div>
</header>
<br><br><br>
<div class="container">
<div class="card mb-3" >
<div class="row g-0">
<div class="col-md-4">
{% if product.image%}
<img src="{{ product.image.url }}" class="img-fluid rounded-start" alt="{{ product.name }}">
{% endif %}
<center>
<div class="col-md-6">
<div class="rating-card p-4">
<div class="star-rating animated-stars ">
<label for="star5" class="bi bi-star-fill"></label>
<label for="star5" class="bi bi-star-fill"></label>
<label for="star5" class="bi bi-star-fill"></label>
<label for="star5" class="bi bi-star-fill"></label>
<label for="star5" class="bi bi-star-fill"></label>
</div>
</div>
</div>
</div>
</center>
<div class="col-md-8">
<div class="card-body">
<center>
<h5 class="card-title">{{ product.name }}</h5>
<p class="card-text">{{ product.desciption }}</p>
<br><br>
{% if product.is_sale %}
<div class="d-flex justify-content-center small text-warning mb-2" >
<div class="bi-star-fill"></div>
Sale
<div class="bi-star-fill"></div>
</div>
<strike>{{ product.price }} L.E</strike>
{{ product.sale_price }} L.E
{% else %}
<p class="card-text">price: {{ product.price }} L.E </p>
{% endif %}
<br><br>
<br><br>
<div class="row justify-content-center">
<div class="col-md-2">Quantity:</div>
<div class="col-md-2">
<select class="form-select form-select-sm" id="qty-cart" >
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
</select>
</div>
</div>
<br><br><br><br><br><br><br>
<a href="{% url 'home' %}" class="btn btn-secondary">Go to Home</a>
<button type="button" class="btn btn-secondary" id="add-to-cart" value="{{product.id}}">Add to Cart</button>
</center>
</div>
</div>
</div>
</div>
</div>
{% if user.is_authenticated %}
<center>
<form method="POST" action="{% url 'product' product.id %}" >
{% csrf_token%}
<div class="form-group">
<div class="col-md-6">
<div class="rating-card p-4">
<h5 class="mb-4" >التقييم </h5>
<div class="star-rating animated-stars">
<input type="radio" id="star5" name="rating" value="5">
<label for="star5" class="bi bi-star-fill"></label>
<input type="radio" id="star4" name="rating" value="4">
<label for="star4" class="bi bi-star-fill"></label>
<input type="radio" id="star3" name="rating" value="3">
<label for="star3" class="bi bi-star-fill"></label>
<input type="radio" id="star2" name="rating" value="2">
<label for="star2" class="bi bi-star-fill"></label>
<input type="radio" id="star1" name="rating" value="1">
<label for="star1" class="bi bi-star-fill"></label>
</div>
<div class="">
<div class="card">
<div class="card-header">
Write your review
</div>
<div class="card-body">
<input type="text" class="form-control" placeholder="Write your review" name="review">
</div>
<br>
<button type="submit" class="btn btn-secondary">Click to Submit</button>
</form>
</div>
</div>
</div>
</div>
</center>
{% endif %}
<center>
<br><br><br>
<h3>Customers Reviews</h3>
{% if reviews %}
{% for review in reviews %}
<div class="container">
<div class="comments border border-light rounded bg-light text-dark">
<p class="font-weight-bold">
{{ review.name }}
<span class=" text-muted font-weight-normal">
{{ review.created_on }}
</span>
</p>
{{ review.body | linebreaks }}
</div>
<br>
</div>
{% endfor %}
</center>
{% elif not user.is_authenticated %}
<p>لا توجد تققيمات لهذا المنتج , برجاء تسجيل حساب و كن اول من يكتب تقييم لة </p>
{% else %}
<p>لا توجد تققيمات لهذا المنتج , كن اول من يكتب تقييم لة </p>
{% endif %}
<style>
.star-rating {
direction: rtl;
display: inline-block;
cursor: pointer;
}
.star-rating input {
display: none;
}
.star-rating label {
color: #ddd;
font-size: 24px;
padding: 0 2px;
cursor: pointer;
transition: all 0.2s ease;
}
.star-rating label:hover,
.star-rating label:hover~label,
.star-rating input:checked~label {
color: #ffc107;
}
</style>
<script>
document.querySelectorAll('.star-rating:not(.readonly) label').forEach(star => {
star.addEventListener('click', function() {
this.style.transform = 'scale(1.2)';
setTimeout(() => {
this.style.transform = 'scale(1)';
}, 200);
});
});
</script>
<br><br><br><br><br><br><br><br><br><br>
<script>
// check if a button presses
$(document).on('click', '#add-to-cart', function(e){
e.preventDefault();
$.ajax({
type: 'POST',
url: '{% url "cart_add" %}',
data: {
product_id: $('#add-to-cart').val(),
product_qty:$('#qty-cart option:selected').text(),
csrfmiddlewaretoken: '{{ csrf_token }}',
action:'post',
},
success: function(json){
console.log(json)
document.getElementById("cart_quantity").textContent = json.qty
location.reload;
},
error: function(xhr, errmsg, err){
}
});
})
</script>
{% endblock %}
and here is the product model
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(default=0, decimal_places=2, max_digits=6)
category = models.ForeignKey(Category ,on_delete=models.CASCADE )
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE)
description = models.CharField(max_length=250, default='', blank=True, null=True)
image = models.ImageField(upload_to='uploads/product/')
is_sale = models.BooleanField(default=False)
sale_price = models.DecimalField(default=0, decimal_places=2, max_digits=6)
is_not_available = models.BooleanField(default=False)
def __str__(self):
return self.name