I am trying to get user/customer info and copy it automatically to new model via custom form once requested but keep getting error. General overview as below.
(error : ValueError at /create_request/
Cannot assign "<SimpleLazyObject: <User: kambing>>": "OrderRequest.user" must be a "Customer" instance.)
model relationship between customer model and request model
my views.py as below:
from django.shortcuts import render, redirect
from .models import *
from accounts.models import *
from .forms import CreateRequestForm
from django.contrib.auth.decorators import login_required
from accounts.models import *
#login_required(login_url='login')
def createRequest(request):
form = CreateRequestForm()
if request.method =='POST':
form = CreateRequestForm(request.POST)
if form.is_valid():
order = form.save(commit=False)
order.user = request.user
order.save()
return redirect('/')
context = {'form':form}
return render(request, 'commerce_autoparts/request_form.html', context)
here my model.py(autopart_ecommerce): Same as shown in attached image
from django.db import models
from accounts.models import Customer
class Logistic(models.Model):
logistic_method = models.CharField(max_length=30, null=True,
blank=True)
def __str__(self):
return self.logistic_method
class OrderRequest(models.Model):
user = models.ForeignKey(Customer, on_delete=models.CASCADE,
null=True, blank=True)
ref_code = models.CharField(max_length=15, null=True, blank=True)
link = models.URLField(null=True, blank=True)
image = models.ImageField(upload_to='media/images',null=True,
blank=True)
price = models.FloatField(null=True)
draft = models.BooleanField(default=True)
logistic_method = models.ForeignKey(Logistic,
on_delete=models.CASCADE, null=True, blank=True)
note = models.TextField(max_length=100)
date_order = models.DateTimeField(auto_now=True)
I tried many solutions from stackoverflow but could not get it right. I am sorry if this not challenging question but I am stuck with this issue for some weeks. Some sort of guidance or reference available would be helpful.
I hope shared info is enough for your references.
Thank you
The problem is that it is a different model, so it doesn't like that. What you can do is copy the field data of the user to the customer, so you actually create new customer.
example:
# instead of this
order.user = request.user
order.save()
# you could do
new_user = Customer()
new_user.name = request.user.name
new_user.email = request.user.email
new_user.last_name = request.user.last_name
# then pass the user to the order
order.user = new_user
order.save()
I somehow manage to solve the issue. It was simply i don't refer the user to customer model. By adding the customer model (instance.user = request.user.customer), it automatically save the customer id once submitted. it may not be the perfect solution, but works for now..
#login_required(login_url='login')
def createRequest(request):
form = CreateRequestForm(request.POST)
if request.method =='POST':
form = CreateRequestForm(request.POST, request.FILES)
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user.customer
instance.ref_code = get_ref_code()
instance.save()
return redirect('/')
Related
First post here. I followed the project code in the Python Crash Course book, so if the code looks similiar that is why.
In my django project, I want all the users to be able to view everything on the website. However, I want to have only the users who entered information in the entries to be able to edit and delete said entries. I know I need to assign ownership, but I'm having difficulty assigning it. currently I have a default setting enabled. For some reason if I take out the default it messes everything up.
urls.py
"""Defines URL patterns for research_topic_database."""
# research_topic_database
from django.urls import path
from . import views
app_name = 'research_topic_database'
urlpatterns = [
# Home page
path('', views.index, name='index'),
# Page that shows all the research category topics.
path('topics/', views.topics, name='topics'),
# Detail page for a single research entry submission.
path('topics/<int:topic_id>/', views.topic, name='topic'),
# Page for adding a new research entry submission.
path('new_entry/<int:topic_id>/', views.new_entry, name='new_entry'),
# Page for editing an entry.
path('edit_entry/<int:entry_id>/', views.edit_entry, name='edit_entry'),
]
models.py
class Topic(models.Model):
"""A research category for topic submissions to fall under."""
category = models.CharField(max_length=19, choices=CATEGORY_CHOICES, blank=True)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
"""Return a string representation of the model."""
return self.category
class Entry(models.Model):
"""Entry information about a research topic."""
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
classification = models.CharField(max_length=10, choices=CLASSIFICTION_CHOICES, blank=True)
# The research_title identifies the entry in the database.
research_title = models.CharField(max_length=200)
research_topic_description = models.CharField(max_length=200)
# Explain the USMC requirements you want the research to fulfill.
extended_topic_description = models.TextField()
desired_objectives = models.TextField()
sponsor = models.CharField(max_length=100)
point_of_contact = models.CharField(max_length=100)
mailing_address = models.CharField(max_length=200)
email_address = models.CharField(max_length=50)
phone = models.CharField(max_length=12)
fax = models.CharField(max_length=12)
desired_completion_date = models.CharField(max_length=12)
available_funding = models.CharField(max_length=50)
comments = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
# connecting research entries to certain Users.
owner = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
# owner = models.ForeignKey(User, on_delete=models.CASCADE)
# owner = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
class Meta:
verbose_name_plural = 'entries'
def __str__(self):
"""Return a string representation of the model."""
return f"{self.research_title[:100]}..."
views.py
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.http import Http404
from .models import Topic, Entry
from .forms import EntryForm
def index(request):
"""The home page for research_topic_database."""
return render(request, 'research_topic_database/index.html')
#login_required
def topics(request):
"""Show all research categories from TOPIC class."""
topics = Topic.objects.order_by('date_added')
context = {'topics': topics}
return render(request, 'research_topic_database/topics.html', context)
#login_required
def topic(request, topic_id):
"""Show a single research category from TOPIC class
and all its submission entries."""
topic = Topic.objects.get(id=topic_id)
entries = topic.entry_set.order_by('-date_added')
context = {'topic': topic, 'entries': entries}
return render(request, 'research_topic_database/topic.html', context)
#login_required
def new_entry(request, topic_id):
"""Add a new entry submission under a research category."""
topic = Topic.objects.get(id=topic_id)
if request.method != 'POST':
# No data submitted; create a blank form.
form = EntryForm()
else:
# POST data submitted; process data.
form = EntryForm(data=request.POST)
if form.is_valid():
new_entry = form.save(commit=False)
new_entry.topic = topic
new_entry.save()
return redirect('research_topic_database:topic', topic_id=topic_id)
# Display a blank or invalid form
context = {'topic': topic, 'form': form}
return render(request, 'research_topic_database/new_entry.html', context)
#login_required
def edit_entry(request, entry_id):
"""Edit an existing research entry submission."""
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
if request.method != 'POST':
# Initial request, pre-fill form with current entry.
form = EntryForm(instance=entry)
else:
# POST data submitted; process data.
form = EntryForm(instance=entry, data=request.POST)
if form.is_valid():
form.save()
return redirect('research_topic_database:topic', topic_id=topic.id)
context = {'entry': entry, 'topic': topic, 'form': form}
return render(request, 'research_topic_database/edit_entry.html', context)
I'm attempting to save records into a model using the modelform (this part is working as intended) and delete records from the same model using a checkbox (can't figure this piece out). I am creating a comprehensive view so I'm not creating using a def variable(reqeust, id) function and my intention is to have both POST methods redirect back to the same page. How would I go about deleting a model record using a checkbox and POST? I will add an #login_required decorator later. Here is my code:
models.py:
class ReportDirectory(models.Model):
report_name = models.CharField(max_length=300, unique=True, blank=False)
report_desc = models.TextField()
report_type = models.CharField(max_length=300)
report_loc = models.TextField()
slug = models.SlugField(unique=True, max_length=300)
last_update = models.DateTimeField(null=True)
main_tags = models.CharField(max_length=300)
# Renames the item in the admin folder
def __str__(self):
return self.report_name
class Favorite(models.Model):
directory_user = models.ForeignKey(User, on_delete=models.CASCADE)
user_report = models.ForeignKey(ReportDirectory, on_delete=models.CASCADE)
favorited = models.BooleanField()
def __str__(self):
return str(self.directory_user)+" - "+str(self.user_report)
views.py:
from django.shortcuts import render,redirect
from django.views import generic
from .models import ReportDirectory, Favorite
from django.contrib.auth.models import User
from .forms import FavoriteForm
def report_directory(request):
favorite = Favorite.objects.filter(directory_user=request.user.id, favorited=True)
reports = ReportDirectory.objects.exclude(favorite__directory_user=request.user.id, favorite__favorited=True)
favform = FavoriteForm(initial={'directory_user':request.user,},)
context = {
'reports':reports,
'favorite':favorite,
'favform':favform
}
if request.method =='POST' and 'favorited' in request.POST:
form = FavoriteForm(request.POST)
if form.is_valid():
form.save()
return redirect('/report_directory')
else:
form = FavoriteForm()
elif request.method =='POST' and 'deletefav' in request.POST:
Favorite.objects.filter(id=id).delete()
return redirect('/report_directory')
return render(request, 'counter/report_directory.html',context)
I need to know how to clear the unsaved related data which causes the following error:
save() prohibited to prevent data loss due to unsaved related object 'order'.
My code is working as intended, but I failed to complete an order. Ever since this, any attempt to save a new order results in above error. I am aware of the cause being the changes to django.db.models.base.py, but there must be some way to clear this via logs or something...
I have tried recreating the database, and also the sqlflush command but neither is working.
VIEWS
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import weasyprint
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.admin.views.decorators import staff_member_required
from django.core.urlresolvers import reverse
from django.conf import settings
from django.http import HttpResponse
from django.template.loader import render_to_string
from .models import OrderItem, Order
from .forms import OrderCreateForm
from cart.cart import Cart
from .tasks import order_created
# Create your views here.
#staff_member_required
def admin_order_detail(request, order_id):
order = get_object_or_404(Order, id=order_id)
return render(request, 'admin/orders/order/detail.html', {'order': order})
#staff_member_required
def admin_order_pdf(request, order_id):
order = get_object_or_404(Order, id=order_id)
html = render_to_string('orders/order/pdf.html', {'order': order})
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'filename="order_{}.pdf"'.format(order.id)
weasyprint.HTML(string=html).write_pdf(response, stylesheets=[weasyprint.CSS(settings.STATIC_ROOT + 'css/pdf.css')])
return response
def order_create(request):
cart = Cart(request)
if request.method == 'POST':
form = OrderCreateForm(request.POST)
if form.is_valid():
order = form.save(commit=False)
if cart.coupon:
order.coupon = cart.coupon
order.discount = cart.coupon.discount
order.save()
for item in cart:
OrderItem.objects.create(order=order, product=item['product'], price=item['price'], quantity=item['quantity'])
#emptying the cart
cart.clear()
#launch celery async task
order_created.delay(order.id)
request.session['order_id'] = order.id #set order.id session
return redirect(reverse('payment:process'))
else:
form = OrderCreateForm()
return render(request, 'orders/order/create.html', {'cart': cart, 'form':form})
MODELS
class Order(models.Model):
first_name = models.CharField(_('first_name'),max_length=50)
last_name = models.CharField(_('last_name'),max_length=50)
email = models.EmailField(_('email'),)
address = models.CharField(_('address'),max_length=250)
postal_code = models.CharField(_('postal_code'),max_length=250)
city = models.CharField(_('city'),max_length=100)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
paid = models.BooleanField(default=False)
coupon = models.ForeignKey(Coupon, related_name='orders', null=True, blank=True)
discount = models.IntegerField(default=0, validators=[MinValueValidator(0), MaxValueValidator(100)])
class Meta:
ordering = ('-created',)
def __unicode__(self):
return 'Order {}'.format(self.id)
def get_total_cost(self):
total_cost = sum(item.get_cost() for item in self.items.all())
return total_cost - total_cost *(self.discount)
class OrderItem(models.Model):
order = models.ForeignKey(Order, related_name='items')
product = models.ForeignKey(Product, related_name='order_items')
price = models.DecimalField(max_digits=10, decimal_places=2)
quantity = models.PositiveIntegerField(default=1)
def __unicode__(self):
return '{}'.format(self.id)
def get_cost(self):
return self.price * self.quantity
FORMS
from django import forms
from .models import Order
class OrderCreateForm(forms.ModelForm):
class Meta:
model = Order
fields = ['first_name', 'last_name', 'email', 'address', 'postal_code', 'city']
If you check your models, then you can see that the coupon field in the order table is a foreign key, in other words, a related object.
Because you don't save the coupon object, it doesn't have a pk and can't be added to the order. First save the coupon object, and then add it to the order.
So something like:
coupon = cart.coupon # not sure if this in between step is needed
coupon.save()
order.coupon = coupon
order.save()
SOLVED
simply save the order object a little earlier in the code so within the orders.views.py file, within the create_order() method, add an earlier invocation of order.save() ...
THIS
if form.is_valid():
order = form.save(commit=False)
BECOMES
if form.is_valid():
order = form.save(commit=False)
order.save()
if cart.coupon:
............
..............
All working fine again!!
#Snackoverflow thks for all your help :-)
I've created a Django view that does 2 things:
Create a new account
Modify a account
Works:
Creating new account and submitting the HTML form data to the database. Also works: showing a prefilled HTML form if user wants to modify an account with the account data that is known in the database.
Doesnt work:
When the user submits his/her form to update an account (user modified the info in the form), nothing is updated in the database.
I know how to update one single static value in the database like so:
a = accounts.objects.filter(pk=account_id).update(name='static value here')
but I don't know how to update the database with all the form data that the user submits when using Django Modelforms. Does anyone knows how to update the database with the submitted form data?
Code
#login_required(login_url='/dashboard/')
def dashboard_accounts_new_modify(request, account_id=None):
if request.method == 'POST':
# POST DETECTED
form = MyModelForm(request.POST, request.FILES)
if account_id:
# POST DETECTED
# ACCOUNT ID FOUND
# USER WANTS TO MODIFY A ACCOUNT
# WITH THIS QUERY I CAN UPDATE 1 STATIC VALUE IN THE DATABASE
# HOW DO I UPDATE THE VALUES FROM THE FORM IN THE DATABASE?? :(
a = accounts.objects.filter(pk=account_id).update(name='static value here')
return HttpResponseRedirect('/dashboard/accounts/')
else:
# POST DETECTED
# ACCOUNT ID NOT FOUND
# USER WANTS TO CREATE A NEW ACCOUNT
if form.is_valid():
if request.POST.get("name").lower() == 'new':
raise Http404("New account name may not be named NEW.")
# DATAHASE QUERY: ADD NEW ACCOUNT TO DATABASE
form.save()
# REDIRECT
return HttpResponseRedirect('/dashboard/accounts/')
elif account_id:
# NO POST DETECTED
# ACCOUNT ID FOUND
# PREFILL FORM WITH DATA
try:
from django.forms.models import model_to_dict
a = accounts.objects.get(pk=account_id)
form = MyModelForm(initial=model_to_dict(a))
except:
raise Http404("Account not found.")
else:
# NO POST DETECTED
# MODIFICATION IS NOT DETECTED
# LOAD EMPTY FORM
form = MyModelForm()
return render(request, 'backend/base_accounts_new.html', {'Title': 'Accounts', 'form' : form})
Model
# Clientdatabase
class accounts(models.Model):
name = models.CharField(max_length=200)
url = models.CharField(max_length=200)
website_title = models.CharField(max_length=200)
website_h1_text = models.CharField(max_length=200)
website_h2_text = models.CharField(max_length=200)
website_search_text = models.CharField(max_length=200)
website_font = models.CharField(max_length=200)
website_footer_left = models.CharField(max_length=600)
website_footer_right = models.CharField(max_length=600)
website_color_code_search_button = models.CharField(max_length=200)
website_color_code_banner = models.CharField(max_length=200)
website_logo_height_pixels = models.PositiveIntegerField()
website_logo_width_pixels = models.PositiveIntegerField()
filepath_favicon = models.FileField()
filepath_logo_vector = models.FileField()
filepath_logo_normal = models.FileField()
filepath_background_1 = models.FileField()
filepath_background_2 = models.FileField(blank=True, null=True)
filepath_background_3 = models.FileField(blank=True, null=True)
filepath_background_4 = models.FileField(blank=True, null=True)
setting_background_1_active = models.BooleanField()
setting_background_2_active = models.BooleanField()
setting_background_3_active = models.BooleanField()
setting_background_4_active = models.BooleanField()
def __str__(self):
return self.name
class AccountsForm(ModelForm):
class Meta:
model = accounts
fields = '__all__'
You can do like:
from django.shortcuts import get_object_or_404
if request.method == 'POST':
if account_id::
account = get_object_or_404(accounts, pk=account_id)
form = MyModelForm(request.POST,request.FILES, instance=account)
if form.is_valid():
...
form.save()
return HttpResponseRedirect('/dashboard/accounts/')
else:
form = MyModelForm(request.POST, request.FILES)
if form.is_valid():
if request.POST.get("name").lower() == 'new':
raise Http404("New account name may not be named NEW.")
form.save()
Learn more about forms here
I have a ModelChoiceField called outage_name. I also have a simple form that allows you to select the item from the list. The ModelChoiceField is pulled from a MySQL DB. This queryset is located in forms.py
outage_name = forms.ModelChoiceField(queryset = Outage.objects.filter(published = True)
The models.py is listed below.
from django.db import models
from django.contrib.auth.models import User
class Outage(models.Model):
outage_name = models.CharField(max_length=60, unique=True)
published = models.BooleanField()
def __unicode__(self):
return self.outage_name
class Detail(models.Model):
detail = models.CharField(max_length=60, unique=True)
user = models.ForeignKey(User)
outage = models.ForeignKey(Outage)
def __unicode__(self):
return self.outage
When I select from the list and submit the form I can't seem to figure out how to match outage = models.ForeignKey(Outage) that was selected on the list. To the correct outage_name. In my views.py I can hard code the id and it submits to the database and everything works fine.
def turnover_form(request):
if request.user.is_authenticated():
if request.method == 'POST':
form = TurnoverForm(request.POST)
if form.is_valid():
details = Detail.objects.get_or_create(
detail = form.cleaned_data['detail'],
user = request.user,
outage = Outage.objects.get(pk=1))
return HttpResponseRedirect('/turnover/user/')
else:
form = TurnoverForm()
variables = RequestContext(request, {'form': form})
return render_to_response('turnover_form.html', variables)
else:
return HttpResponseRedirect('/authorization/')
Any advice on how to match the id with the selected item would be appreciated. I'm sure my code is not very pythonic as I'm still learning.
outage = form.cleaned_data['outage'] # cleaned_data['outage'] is a model instance