Good day, I am trying to implement django with a dependent foreignkey forms on one page. I have three moodels Store, Product, and ProductClothing. They are all ForeignKey related respectively. Users get to create their store seperately, and are redirected to the store detail view where they will now have to upload Products. But this time, I want them to upload both products and product clothing at once. Below is my models.py and views.py of what I have currently on the store detail view. Also the error I get is:
error.py
NOT NULL constraint failed: product_productclothing.product_id
models.py
class Store(models.Model):
owner = models.ForeignKey(Profile, null=True, on_delete=models.SET_NULL)
name = models.CharField(max_length=100, unique=True)
slug = AutoSlugField(populate_from='name', unique=True)
description = models.CharField(max_length=255, blank=True)
def __str__(self):
return self.name
class Product(models.Model):
store = models.ForeignKey(Store, null=True, on_delete=models.SET_NULL)
owner = models.ForeignKey(Profile, null=True, on_delete=models.SET_NULL)
title = models.CharField(max_length=255)
price = models.DecimalField(max_digits=9, decimal_places=2, verbose_name=_("Regular price"))
class ProductClothing(models.Model):
CLOTHING_GENDER_CHOICES = (
('M', 'Male',),
('F', 'Female',),
('U', 'Unisex',),
)
CLOTHING_TYPE_CHOICES = (
('dress', 'Dresses',),
('fabric', 'Fabrics',),
('shirt', 'Shirts',),
('suit', 'Suits',),
('tshirt', 'T-Shirts',),
('base_layers', 'Base_Layers',),
('blazer', 'Blazers',),
)
product = models.OneToOneField(Product, on_delete=models.CASCADE)
gender = models.CharField(max_length=10, choices=CLOTHING_GENDER_CHOICES, blank=True, null=True)
clothing_type = models.CharField(max_length=255, choices=CLOTHING_TYPE_CHOICES, blank=True, null=True)
def __str__(self):
return self.product.title
views.py
#login_required
def store_dashboard_view(request, slug):
store = get_object_or_404(Store, slug=slug)
new_product = None
product_clothing = None
if request.user.profile == store.owner:
if request.method == 'GET':
product_form = ProductForm()
product_clothing_form = ProductClothingForm()
if request.method == 'POST':
product_form = ProductForm(data=request.POST)
product_clothing_form = ProductClothingForm(data=request.POST)
if product_form.is_valid() and product_clothing_form.is_valid():
new_product = product_form.save(commit=False)
product_clothing_form.save(commit=False)
new_product.store = store
new_product.owner = request.user.profile
product = product_form.save()
product = product
product_clothing_form.product = product
product_clothing_form.save()
print(request.user.first_name)
return redirect('/')
context = {
"object":store,
"form": product_form,
"product_clothing_form": product_clothing_form
}
return render(request, "store/store-dashboard.html", context)
else:
return redirect('store:store-detail-view', slug=store.slug)
Try to Change this part
if product_form.is_valid() and product_clothing_form.is_valid():
new_product = product_form.save(commit=False)
product_clothing_form.save(commit=False)
new_product.store = store
new_product.owner = request.user.profile
product = product_form.save()
product = product
product_clothing_form.product = product
product_clothing_form.save()
print(request.user.first_name)
return redirect('/')
to
if product_form.is_valid() and product_clothing_form.is_valid():
new_product = product_form.save(commit=False)
product_clothing_form = product_clothing_form.save(commit=False)
new_product.store = store
new_product.owner = request.user.profile
new_product.save() #this is correct your mistake was here
print(new_product)
product_clothing_form.product = new_product
product_clothing_form.save()
print(request.user.first_name)
return redirect('/')
Related
This is my models.py file
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Book(models.Model):
category_choices =(
#("Undefined","Undefined"),
("Action", "Action"),
("Romance", "Romance"),
("Horror", "Horror"),
("Comedy", "Comedy"),
("Adventure", "Adventure"),
("Dramatic", "Dramatic"),
("Crime","Crime"),
("Fantasy","Fantasy"),
)
name = models.CharField(max_length=100)
author = models.CharField(max_length=100, null=True)
content = models.TextField()
price = models.DecimalField(max_digits=5, decimal_places=2)
image = models.ImageField(upload_to= 'photos/%y/%m/%d', blank = True)
category = models.CharField(
max_length = 20,
choices = category_choices,
#default = 'Undefined'
)
publication_year = models.CharField(max_length=4, null=True)
ISBN = models.CharField(max_length=13, null=True, unique=True)
active = models.BooleanField(default= True)
def __str__(self):
return self.name
class Borrow(models.Model):
name = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
book = models.OneToOneField(Book, null=True, on_delete= models.SET_NULL)
period = models.PositiveIntegerField(default=0)
id = models.IntegerField(primary_key=True)
def __str__(self):
return str(self.book)
and this is my forms.py file
from django import forms
from .models import Borrow
class BorrowForm(forms.ModelForm):
class Meta:
model = Borrow
fields = ('name', 'book', 'period')
and this is the function in my views.py file that renders the form
#login_required
def borrowing(request):
momo = BorrowForm()
if request.method == 'POST':
momo = BorrowForm(request.POST)
if momo.is_valid():
instacne = momo.save(commit=False)
instacne.user = request.user.username
instacne.save()
return redirect('profile')
return render(request, 'books/book.html', {'momo': momo})
The role of this function is to render that form and to save the data that user will enter and automatically assign the username of the current user to the field 'name' in form.
I tried alot of things to get the username of the current user and assign it to the field 'name' but nothing works and that field stays blank.
You're using a models.ForeignKey(User) so that table will store a user id, not a username. I'd call this field user and not name, personally.
Therefore you need to provide a user instance to it like this;
#login_required
def borrowing(request):
initial = {}
if request.user.is_authenticated:
initial.update({'name': request.user})
momo = BorrowForm(initial=initial)
if request.method == 'POST':
momo = BorrowForm(request.POST)
if momo.is_valid():
instance = momo.save(commit=False)
instance.user = request.user
instance.save()
If you wanted to easily get the username for a Borrow instance you could do this;
class Borrow(models.Model):
name = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
book = models.OneToOneField(Book, null=True, on_delete= models.SET_NULL)
period = models.PositiveIntegerField(default=0)
id = models.IntegerField(primary_key=True)
def __str__(self):
return str(self.book)
#property
def username(self):
return self.name.username
If you want the form to offer users by username, you can either have the str method of your user model return username, or create custom choices as a tuple of user ID & username in the form __init__
Please help me I stuck at this problem. When Click on the view button I want to show all the orders from that user as shown in the image below, but when i click on it I am getting this error instead of order details for that customer.
The models file contains
models.py
class Customer(models.Model):
user = models.OneToOneField(
User, null=True, blank=True, on_delete=models.CASCADE)
name = models.CharField(max_length=50, null=True)
phone = models.CharField(max_length= 200, null = True)
email = models.CharField(max_length=100)
def __str__(self):
return self.name
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, null=True, blank=True)
transaction_id = models.CharField(max_length=200, null=True)
def __str__(self):
return str(self.customer)
#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):
customer = models.ForeignKey(
Customer, on_delete=models.SET_NULL, null=True, blank=True)
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=False)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.product.name
#property
def get_total(self):
total = self.product.price * self.quantity
return total
The views.py file contains
Views.py
#login_required(login_url='login')
#admin_only
def customer(request, pk):
customer = Customer.objects.get(id=pk)
orders = Customer.orderitem_set.all()
shippinginfo = customer.shippingaddress_set.all()
total_order = orders.count()
context = {'customer': customer, 'orders': orders, 'total_order':total_order, 'shippinginfo': shippinginfo}
return render(request, 'store/customer.html', context)
Do it like :-
def customer(request, pk):
customer = Customer.objects.get(id=pk)
orders = customer.orderitem_set.all()
shippinginfo = customer.shippingaddress_set.all()
total_order = orders.count()
What i have changed ?
I have related (connected) orderitem_set with the existing id with existing query.
EDIT :-
I have found the problem in your GitHub Repo.
The Problem is in the updateItem view.
You're saving the order but you're not relating the request.user as a customer with the order.
So do it like :-
def updateItem(request):
data = json.loads(request.body)
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(customer=customer, 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)
# Add this line
orderItem.customer = request.user.customer
orderItem.save()
if orderItem.quantity <= 0:
orderItem.delete()
return JsonResponse('Item was added', safe=False)
Add a related_name field in your models.py on Order model like
class Order(models.Model):
customer = models.ForeignKey(
Customer, on_delete=models.SET_NULL, null=True, blank=True, related_name="orders")
And then in views.py
def customer(request, pk):
customer = Customer.objects.get(id=pk)
orders = customer.orders.all()
In models.py:
class Comment(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE, related_name='comments')
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
body = models.TextField()
rating = models.FloatField(null=True)
aggregate = models.FloatField(null=True)
date = models.DateTimeField(auto_now_add=True)
class Item(models.Model):
id_item = models.AutoField(primary_key='true')
item_name = models.CharField(max_length=100, null=False)
slug = models.SlugField(max_length=250, blank=True, null=True)
item_description = models.TextField()
item_img = models.ImageField(blank=True, null=True, upload_to="static/item/cover/")
tags = TaggableManager()
In views.py:
def detail(request, slug_text):
details = Item.objects.filter(slug=slug_text)
if details.exists():
reviews = Comment.objects.filter(item=slug_text)
details = details.first()
average = reviews.aggregate(Avg("rating"))["rating_avg"]
average = round(average, 2)
form = CommentForm()
if request.method == "POST":
form = CommentForm(request.POST, author=request.user, item=details)
if form.is_valid():
form.save()
return HttpResponseRedirect(slug_text)
else:
return HttpResponse('<h1>Trang không tồn tại</h1>')
return render(request, 'homepage/detail.html', {'detail': details, 'form': form, 'average': average})
What if I want to get the item.slug = slug_text field in here?
reviews = Comment.objects.filter(item=slug_text)
You not far from it, to get data from a foreignkey you use double under score __ i.e: to get item slug use item__slug see below
reviews = Comment.objects.filter(item__slug=slug_text)
All the best.
I'm still new to django, I'm working on a project where I'll need users to enter some information about houses they want to rent out. I want the users to upload a minimum of 6 pictures and from what I've gathered, the best way to do this on django is to use two models, one collects basic information about the houses and the second stores images of the houses. How am I supposed to code the views.py. I've tried all to no avail.
forms.py
class MyHouseEditForm(forms.ModelForm):
class Meta:
model = Myhouses
fields = ('name_of_accomodation',
'type_of_apartment','Number_of_rooms', 'house_rent',
'availability', 'location', 'nearest_institution',
'description',)
class ImageForm(forms.ModelForm):
class Meta:
model = Image
fields = ('__all__' )
models.py
class Myhouses(models.Model):
Available = 'A'
Not_Available = 'NA'
Availability = (
(Available, 'Available'),
(Not_Available, 'Not_Available'),
)
Flat = 'F'
Self_contained = 's'
Bungalow = 'b'
Mini_flat = 's'
Duplex = 'D'
Room = (
(Flat, 'Flat'),
(Self_contained, 'Self_contained'),
(Bungalow, 'Bungalow'),
(Mini_flat, 'Mini_flat'),
(Duplex, 'Duplex'),
)
time = models.DateTimeField(default = datetime.now, blank = True)
name_of_accomodation = models.CharField(max_length=20)
type_of_apartment = models.CharField(max_length=2, choices=Room, )
Number_of_rooms = house_rent = models.IntegerField()
house_rent = models.IntegerField()
availability = models.CharField(max_length=2, choices=Availability, default=Available,)
location = models.CharField(max_length=200)
nearest_institution = models.CharField(max_length=200)
description = models.TextField(blank=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name='author')
def __str__(self):
return self.name_of_accomodation
def get_absolute_url(self):
return reverse('search-detail', args=[str(self.id)])
class Meta:
ordering = ["-time"]
class Image(models.Model):
myhouses = models.ForeignKey(Myhouses, related_name='images', on_delete=models.PROTECT)
image = models.ImageField(upload_to='documents/')
views.py
def addlisting(request):
if request.method == 'POST':
Hform = MyHouseEditForm(request.POST, files=request.FILES, )
Iform = ImageForm(request.POST, request.FILES, )
if Hform.is_valid() and Iform.is_valid():
Houses = Hform.save(commit=False)
Houses.author=request.user
Houses.save()
image = iform.save(commit=False)
Houses.image.myhouses = myhouses
Houses.save()
messages.success(request, 'Listing Created Succesfully successfully')
return redirect('addlisting')
else:
Hform = MyHouseEditForm()
Iform = ImageForm()
return render(request, 'houses/addlisting.html', {'Hform':Hform, 'Iform': Iform}, )
In models.py my Product model is
class Product(models.Model):
productName = models.CharField(max_length=20, default='1',blank=False,null=False, primary_key = True)
userPhone = models.CharField(max_length=20, default='1')
userid = models.ForeignKey(Account, default='1',null=True)
productDesc = models.TextField(blank=False,null=False, default='1')
productCategory = models.ForeignKey(Category, null=False, default='1')
productPrice = models.DecimalField(default='0',blank=False,null=False, max_digits=6, decimal_places=2)
picture = models.ImageField(upload_to='product_images', blank=True, null=True, default='1')
def __unicode__(self):
return self.productName
The form that I have to add new Products is,
class ProductForm(forms.ModelForm):
productName = forms.CharField(label='Product Name')
productCategory = forms.ModelChoiceField(label='Category', queryset=Category.objects.all())
productDesc = forms.CharField(label='Product Description', widget=forms.Textarea)
productPrice = forms.DecimalField(label='Expected Price')
userPhone = forms.CharField(label='Phone Number')
picture = forms.ImageField(label='Upload Picture')
class Meta:
model = Product
fields = ('productName', 'productCategory', 'productDesc', 'productPrice', 'userPhone', 'picture',)
def clean_productName(self):
productName = self.cleaned_data['productName']
try:
Product.objects.get(productName=productName)
except Product.DoesNotExist:
return productName
raise forms.ValidationError("A product under that name already exits. Rename your product.")
def clean_productCategory(self):
productCategory = self.cleaned_data['productCategory']
def clean_productDesc(self):
productDesc = self.cleaned_data['productDesc']
def clean_productPrice(self):
productPrice = self.cleaned_data['productPrice']
def clean_userPhone(self):
userPhone = self.cleaned_data['userPhone']
def clean_picture(self):
picture = self.cleaned_data['picture']
And to take form input, I have in my views.py file
#login_required(login_url='/accounts/login/')
def newProduct(request):
if(request.method =='POST'):
product_form = ProductForm(request.POST, request.FILES)
if product_form.is_valid():
product = product_form.save(commit=True)
product.save()
else:
print product_form.errors
else:
product_form = ProductForm()
return render(request, 'market/postad.html', {'product_form':product_form} )
I want to update the userid field of Product model to the user_id of the logged in user. How do I go about doing that?
request.user.id
might give me the id of the logged in user. But how do I associate that with the product that is being entered into the database? (I am using MySQL database)
My AUTH_USER_MODEL isn't configured to Account. Is there any way to do it without configuring it?
My Account model is
class Account(models.Model):
user = models.OneToOneField(User)
I imported User from django.contrib.auth.models
In views.py (if your AUTH_USER_MODEL configured to Account)
#login_required(login_url='/accounts/login/', template_name='market/postad.html')
def newProduct(request):
product_form = ProductForm(request.POST or None, request.FILES or None)
if(request.method =='POST'):
if product_form.is_valid():
product = product_form.save(commit=False)
product.userid = Account.objects.get_or_create(user=request.user)
product.save()
else:
print product_form.errors
return render(request, template_name, {'product_form':product_form} )