I am following a Django youtube E-comerce tutorial by Dennis Ivy. I follow the tutorial line by line. from the initial i use to run the program and view all the output but alone the way i start getting this error message "RelatedObjectDoesNotExist: User has no customer". Am confuse because i keep repeating the video to see where i was wrong but could not trace it. please what is the solution? I realise the last time i tried, it open on its own using 'internet explorer' it display. when i open in 'chrome', it show the same erro. but when i deleted a customer from database it start showing the same erro again in 'internet explorer'. I dont want to give up on the tutorial cos i need it. please someone should assist me. Thanks
from multiprocessing import context
from django.shortcuts import render
from .models import *
from django.contrib.auth.models import User
from django.http import JsonResponse
import json
# Create your views here.
def store(request):
if request.user.is_authenticated:
customer = request.user.customer
order, created=Order.objects.get_or_create(customer=customer, complete =False)
items =order.orderitem_set.all()
cartItems=order.get_cart_items
else:
items=[]
order = {'get_cart_total':0, 'get_cart_items':0}
cartItems=order['get_cart_items']
products = Product.objects.all()
context = {
'products':products,
'cartItems':cartItems,
}
return render(request, 'store/store.html', context)
def cart(request):
if request.user.is_authenticated:
customer = request.user.customer
order, created=Order.objects.get_or_create(customer=customer, complete =False)
items =order.orderitem_set.all()
cartItems=order.get_cart_items
else:
items=[]
order = {'get_cart_total':0, 'get_cart_items':0}
cartItems=order['get_cart_items']
context = {
'items':items,
'order':order,
'cartItems':cartItems,
}
return render(request, 'store/cart.html', context)
def checkout(request):
if request.user.is_authenticated:
customer = request.user.customer
order, created=Order.objects.get_or_create(customer=customer, complete =False)
# order, created=Order.objects.get_or_create(complete =False)
items =order.orderitem_set.all()
else:
items=[]
order = {'get_cart_total':0, 'get_cart_items':0}
cartItems=order['get_cart_items']
context = {
'items':items,
'order':order,
'cartItems':cartItems
}
return render(request, 'store/checkout.html', context)
def updateItem(request):
data = json.loads(request.data)
productId = data['productId']
action = data['action']
print('Action:', action)
print('productId:', productId)
customer=request.user.customer
product=Product.objects.get(id=productId)
order, created=Order.objects.get_or_create(complete =False)
orderItem, created=OrderItem.objects.get_or_create(order=order, product=product)
if action =='add':
orderItem.quantity =(orderItem.quantity +1)
elif action =='remove':
orderItem.quantity =(orderItem.quantity -1)
orderItem.save()
if orderItem.quantity <=0:
orderItem.delete()
return JsonResponse('Item was added', safe =False)
this is the models.py
import email
from django.db import models
from django.db.models.fields.related import OneToOneField
from django.contrib.auth.models import User
from numpy import product
# Create your models here.
class Customer(models.Model):
user=models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE)
name = models.CharField(max_length=200, null=True)
email=models.CharField(max_length=200)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=200, null=True)
price = models.FloatField()
digital=models.BooleanField(default=False, null=True, blank=True)
image = models.ImageField(null=True, blank=True)
def __str__(self):
return self.name
#this is to avoid erro in the template when we delete image
#property
def imageURL(self):
try:
url=self.image.url
except:
url=''
return url
class Order(models.Model):
customer=models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True, blank=True)
date_ordered=models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=200, null=True)
def __str__(self):
return str(self.id)
#property
def get_cart_total(self):
orderitems = self.orderitem_set.all()
total = sum([item.get_total for item in orderitems])
return total
#property
def get_cart_items(self):
orderitems = self.orderitem_set.all()
total = sum([item.quantity for item in orderitems])
return total
class OrderItem(models.Model):
product=models.ForeignKey(Product, on_delete=models.SET_NULL, null=True, blank=True)
order=models.ForeignKey(Order, on_delete=models.SET_NULL, null=True, blank=True)
quantity = models.IntegerField(default=0, null=True, blank=True)
date_added=models.DateTimeField(auto_now_add=True)
#property
def get_total(self):
total = self.product.price * self.quantity
return total
class ShippingAddress(models.Model):
customer=models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True, blank=True)
order=models.ForeignKey(Order, on_delete=models.SET_NULL, null=True, blank=True)
address= models.CharField(max_length=200, null=True)
city = models.CharField(max_length=200, null=True)
state = models.CharField(max_length=200, null=True)
zipcode = models.CharField(max_length=200, null=True)
date_added=models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.address
this is the urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.store, name = 'store'),
path('cart/', views.cart, name = 'cart'),
path('checkout', views.checkout, name = 'checkout'),
path('update_item/', views.updateItem, name='update_item')
]
Ways to solve it
You can either add the code below inside step 1 or 2 which you need to run in the shell(inside your app folder)
Create in your app folder this file , create_customers.py
Open the app folder in terminal and run the command below
python manage.py shell
then paste the code below into shell
from django.contrib.auth.models import User
from store.models import Customer
for user in User.objects.all():
Customer.objects.create(user=user, name=user.username, email=user.email)
you can use the request.user to query the customer
customer = Customer.objects.get(user__id = request.user.id)
Related
I have a model form to list an item and I am trying to get the form to fill in the user id from the user that is submitting the form. Currently, the form is submitted successfully but it always uses the first user in the database's id for every item.
models.py
class Item(models.Model):
id = models.UUIDField( primary_key=True, default=uuid.uuid4, editable=False )
creator = models.ForeignKey( get_user_model(), on_delete=models.CASCADE, default=2)
item_name = models.CharField(max_length=40)
price = models.DecimalField(max_digits = 6, decimal_places=2)
description = models.CharField(max_length= 500)
main_image = models.ImageField(upload_to=path_and_rename , max_length=255, null=True, blank=True)
image_2 = models.ImageField(upload_to='items/', blank=True)
image_3= models.ImageField(upload_to='items/', blank=True)
image_4= models.ImageField(upload_to='items/', blank=True)
image_5= models.ImageField(upload_to='items/', blank=True)
quantity = models.IntegerField(default=1, validators=[ MaxValueValidator(100),MinValueValidator(1)])
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
def __str__(self):
return self.item_name
def get_absolute_url(self):
return reverse("item_detail_view", args=[str(self.id)])
forms.py
from django.forms import ModelForm, forms
from .models import Item
class List_Item_Form(ModelForm):
forms.ModelChoiceField(queryset=Item.objects.filter(user=user))
class Meta:
model = Item
def __init__(self, *args, **kwargs):
user = kwargs.pop("user", None)
super().__init__(*args, **kwargs)
views.py
class AddListing( generic.CreateView):
template_name = 'store/add_listing.html'
fields = ('item_name','price','description','main_image','quantity')
model = Item
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.save()
return super().form_valid(form)
It can be done using function based view too because there we get current user more easily.
Try this:
models.py
from django.db import models
from django.contrib.auth.models import User
class Item(models.Model):
creator = models.ForeignKey(User, on_delete=models.CASCADE)
item_name = models.CharField(max_length=40)
price = models.DecimalField(max_digits=6, decimal_places=2)
description = models.CharField(max_length=500)
main_image = models.ImageField(
upload_to=path_and_rename, max_length=255, null=True, blank=True)
image_2 = models.ImageField(upload_to='items/', blank=True)
image_3 = models.ImageField(upload_to='items/', blank=True)
image_4 = models.ImageField(upload_to='items/', blank=True)
image_5 = models.ImageField(upload_to='items/', blank=True)
quantity = models.PositiveIntegerField(default=1)
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
def __str__(self):
return self.item_name
admin.py
from django.contrib import admin
from home.models import Item
#admin.register(Item)
class ItemRegister(admin.ModelAdmin):
lis_display = ['id', 'creator', 'item_name', 'price', 'description']
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.list, name='home'),
path('success/', views.success, name='success')
]
forms.py
from django.forms import ModelForm, forms
from .models import Item
class ListItemForm(ModelForm):
class Meta:
model = Item
fields = ['item_name', 'price', 'main_image'
'description', 'quantity']
views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .models import Item
from .forms import ListItemForm
def list(request):
if request.method == 'POST':
form = ListItemForm(request.POST)
if form.is_valid():
itemName = form.cleaned_data['item_name']
price = form.cleaned_data['price']
desc = form.cleaned_data['description']
quan = form.cleaned_data['quantity']
main_img = form.cleaned_data['main_image']
current_user = request.user
model_instance = Item(creator=current_user, item_name=itemName, price=price,
description=desc, quantity=quan, main_image=main_img)
model_instance.save()
return HttpResponseRedirect('/success/')
else:
form = ListItemForm()
return render(request, 'store/add_listing.html', {'form': form})
def success(request):
return render(request, 'store/success.html')
Rest of the fields of models you can customize very easily in the view.
I have a pretty basic django install, with summernote.
When I'm in the admin panel, it looks like so.
But when I go to any of the category pages, it looks like this.
I tried clearing cache, but still looks the same.
Any help would be appreciated.
EDIT:
My models code is
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
import uuid
STATUS = (
(0,"Draft"),
(1,"Publish")
)
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="blog_posts"
)
updated_on = models.DateTimeField(auto_now=True)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=0)
class Meta:
ordering = ["-created_on"]
def __str__(self):
return self.title
def get_absolute_url(self):
from django.urls import reverse
return reverse("post_detail", kwargs={"slug": str(self.slug)})
def get_previous_by_created_on_active(self):
return self.get_previous_by_created_on(status=1)
def get_next_by_created_on_active(self):
return self.get_next_by_created_on(status=1)
class Newsletter(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField(null=False, blank=True, max_length=200, unique=True)
conf_num = models.CharField(max_length=15)
confirmed = models.BooleanField(default=False)
def __str__(self):
return self.email + " (" + ("not " if not self.confirmed else "") + "confirmed)"
I see you got the solution.
I suggest providing the display in admin view correctly and as you want.
from django.contrib import admin
from .models import YourModel
#admin.register(YourModel)
class YourModelAdmin(admin.ModelAdmin):
list_display = ("name", "slug") // fields you want to display
I am naive in Django, I have done a sample E-commerce application that is present online. I am unable to understand the highlighted statements, I searched online but unable to understand the statements.
Can someone please explain me like below
productitems = self.name_set.all()
From where this name_set.all() came ?????????
orderItems = self.orderitem_set.all()
likewise from where orderitem_set.all() ?????????
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Customer(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE, null=True,blank=True)
name = models.CharField(max_length=200,null=True)
email = models.CharField(max_length=200,null=True)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=200, null=True)
price = models.DecimalField(max_digits=7,decimal_places=2)
digital = models.BooleanField(default=False,null=True,blank=False)
image = models.ImageField(null=True,blank=True)
#image
def __str__(self):
return self.name
#property
def imageURL(self):
try:
url = self.image.url
except:
url = ''
return url
#property
def get_product_total(self):
**productitems = **self.name_set.all()****
total = sum([item.get_total for item in productitems])
return total
print('total:',total)
class Order(models.Model):
customer = models.ForeignKey(Customer,on_delete=models.SET_NULL,blank=True,null=True)
date_ordered=models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False,null=True,blank=False)
transaction_id = models.CharField(max_length=200, null=True)
def __str__(self):
return str(self.id)
#property
def shipping(self):
shipping = False
orderItems = **self.orderitem_set.all()**
for i in orderItems:
if i.product.digital == False:
shipping = True
return shipping
#property
def get_cart_total(self):
orderitems = self.orderitem_set.all()
total = sum([item.get_total for item in orderitems])
return total
#property
def get_cart_items(self):
orderitems = self.orderitem_set.all()
total = sum([item.quantity for item in orderitems])
return total
class OrderItem(models.Model):
product = models.ForeignKey(Product,on_delete=models.SET_NULL,blank=True,null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, blank=True, null=True)
quantity=models.IntegerField(default=0,blank=True,null=True)
date_added=models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.product)
#property
def get_total(self):
print(self.product.price)
# print("self.product.price:",self.product.price)
# print("self.quantity:", self.quantity)
total = self.product.price * self.quantity
return total
class ShippingAddress(models.Model):
customer = models.ForeignKey(Customer,on_delete=models.SET_NULL,blank=True,null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, blank=True, null=True)
address = models.CharField(max_length=200,null=True)
city = models.CharField(max_length=200, null=True)
state = models.CharField(max_length=200, null=True)
zipcode = models.CharField(max_length=200, null=True)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.address)
Those are reverse foreign key lookups. The {field_name}_set pattern is what Django uses by default if you don't define a different term yourself.
The Django documentation explains it more here https://docs.djangoproject.com/en/3.1/ref/models/fields/#django.db.models.ForeignKey.related_name
and here https://docs.djangoproject.com/en/3.1/topics/db/queries/#following-relationships-backward
An example from the docs is:
>>> b = Blog.objects.get(id=1)
>>> b.entry_set.all() # Returns all Entry objects related to Blog.
Instead of using the default you can set the related lookup to a custom value when defining the ForeignKey field on the model, using the related_name argument. I do this often myself, there are usually more fitting terms for the project than the default.
The view works with just the PK, however, the problem is that my PK on the live site is an incoherent string and I want to make it coherent titling for an article to boost SEO. I don't want to change the PK to the slug. I want both.
When I try to add both the PK and a slug it fails and I get the error: no reverse match.
URL path:
path('idea/<slug:slug>,<int:pk>', views.IdeaDetailView.as_view(), name='detail')
Model:
class Idea(models.Model):
idea_id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Searches ID')
idea_number = models.IntegerField(blank=True, null=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
idea_title = models.CharField(max_length=300, blank=True, null=True)
idea_text = NonStrippingTextField(max_length=10000, blank=True, null=True)
Views.py:
class IdeaDetailView(generic.DetailView):
model = Idea
template_name = "idea/detail.html"
def get_context_data(self, **kwargs):
context = super(IdeaDetailView, self).get_context_data(**kwargs)
context['results'] = Idea.objects.filter(idea_id=self.kwargs.get('pk'))
return context
Admin.py:
class IdeaAdmin(admin.ModelAdmin):
prepopulated_fields = {"slug": ("idea_title",)}
I want to add a slug which is the idea_title, however if I try to add that into the URL it fails.
Try adding a slugfield, get_absolute_url method, and save method to your Idea model, like this:
from django.conf import settings
from django.db import models
from django.urls import reverse
from django.utils.text import slugify
class Idea(models.Model):
idea_id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Searches ID')
idea_number = models.IntegerField(blank=True, null=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
idea_title = models.CharField(max_length=300, blank=True, null=True)
idea_text = NonStrippingTextField(max_length=10000, blank=True, null=True)
slug = models.SlugField(
default='',
editable=False,
max_length=300,
)
def get_absolute_url(self):
kwargs = {
'pk': self.id,
'slug': self.slug
}
return reverse('idea-pk-slug-detail', kwargs=kwargs)
def save(self, *args, **kwargs):
value = self.title
self.slug = slugify(value, allow_unicode=True)
super().save(*args, **kwargs)
Then, in urls.py:
path('idea/<int:pk>-<str:slug>/', views.IdeaDetailView.as_view(), name='detail')
And, in views.py right under template_name:
query_pk_and_slug = True
Two more methods and more info found HERE.
Hope this helps!
Im creating a site where you can write down your goals, you should be able to split every goal into subgoals if chosen, and allow those subgoals to be split into subgoals infinitely.
This code below shows what i came up with first for the models, the first model is for creating a goal, the second model can either either be a subgoal of the goal or a subgoal of the subgoal.
But it seems like a really bad way to go around this problem.
Django semi-newbie BTW...
from django.db import models
from django.contrib.auth.models import User
class Goal(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default=None)
title = models.CharField(max_length=70, null=True)
content = models.TextField(blank=True)
slug = models.SlugField(max_length=50, editable=False)
date_created = models.DateTimeField(auto_now_add=True, null=True)
class Meta:
unique_together = ['user', 'title']
def __str__(self):
return self.user.username + " - " + self.title
def save(self, *args, **kwargs):
self.slug = self.title.replace(' ', '-').lower()
super(Goal, self).save(*args, **kwargs)
class SubGoal(models.Model):
goal = models.ForeignKey(
Goal, on_delete=models.CASCADE, null=True, blank=True)
parent = models.ForeignKey(
"SubGoal", on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=70)
content = models.TextField(blank=True)
date_created = models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
try:
return self.goal.title + " - " + self.title
except:
return self.parent.title + " - " + self.title
You can make a ForeignKey to self. If the ForeignKey is NULL, then that goal has no parent, otherwise it refers to the parent:
from django.db import models
from django.contrib.auth.models import User
from django.conf import settings
django.utils.text import slugify
class Goal(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=70)
content = models.TextField(blank=True)
slug = models.SlugField(max_length=50, editable=False)
date_created = models.DateTimeField(auto_now_add=True)
parent = models.ForeignKey(
'self',
on_delete=models.SET_NULL,
null=True,
default=None,
related_name='subgoals'
)
class Meta:
constraints = [
models.UniqueConstraint(fields=['user', 'title'], name='user_title')
]
def __str__(self):
if self.parent_id is None:
return '{}-{}'.format(self.user.username, self.title)
else:
return '{}-{}'.format(str(self.parent), self.title)
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Goal, self).save(*args, **kwargs)
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.