Django - Saving contents of a form into a database - django-models

class InitialForm(forms.Form):
Teacher_Name = forms.CharField(label='Teacher Name')
Subject = forms.CharField(label = 'Subject')
Question = forms.CharField(label = 'What is the first question?')
Topic = forms.CharField(label = 'What topic is this on?')
Option1_Q = forms.CharField(label = 'What is the first option?')
Option2_Q = forms.CharField(label = 'What is the second option?')
Option3_Q = forms.CharField(label = 'What is the third option?')
Option4_Q = forms.CharField(label = 'What is the fourth option?')
Answer_Q = forms.CharField(label = 'Which option is the correct option?', widget=forms.Select(choices=Options))
class Questions(models.Model):
testID = AutoSlugField(unique=True)
teacherID = models.ForeignKey(Teacher, on_delete=models.CASCADE)
studentID = models.ForeignKey(Student, on_delete=models.CASCADE)
Subject = models.CharField(max_length=1000)
Q = models.CharField(max_length=1000)
Topic = models.CharField(max_length=1000)
Option1_Q = models.CharField(max_length=1000)
Option2_Q = models.CharField(max_length=1000)
Option3_Q = models.CharField(max_length=1000)
Option4_Q = models.CharField(max_length=1000)
AnswerQ = models.CharField(max_length=1000)
def teachertests(request):
form = InitialForm()
if request.method == "POST":
form = InitialForm(request.POST)
form.save()
return render(request, 'teachertests.html', {'form':form})
Hey, pretty new to coding in general and wanted to save the contents of the form into the database and then display specific fields from the form, not sure what I had done wrong, could anyone help?

When you use a form it is important to add the form.is_valid() since from what you see you did not indicate in your form if there are fields that are not mandatory with the require=False as long as it is not valid it will not be saved
def teachertests(request):
form = InitialForm()
if request.method == "POST":
form = InitialForm(request.POST)
if form.is_valid():
data_form = form.cleaned_data
question = Question()
question.Option1_Q = data_form.get('Option1_Q')
# ....... all fields form
question.save()
return render(request, 'teachertests.html', {'form':form})

Related

How do you know exactly what causes the form not to be valid while processing form with model

Hey Mentors and Teachers, we appreciate having you, please help a young one here in this industry having not much experience this is one of my common challenges since I am still trying new ways, here I am using a model to save a form and also model form without having to use the form in the template. I am sure using the model form directly would have solved it quickly but I want the ability to be able to style my form, especially each individual field,
the version being used in this is django 3.1
Help me know how to make this code work
class Order(models.Model):
STATUS = (
('New', 'New'),
('Accepted', 'Accepted'),
('Completed', 'Completed'),
('Cancelled', 'Cancelled'),
)
user = models.ForeignKey(Account, on_delete=models.SET_NULL, null=True)
payment = models.ForeignKey(Payment, on_delete=models.SET_NULL, blank=True, null=True)
order_number = models.CharField(max_length=20)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
phone = models.CharField(max_length=15)
email = models.EmailField(max_length=50)
address_line_1 = models.CharField(max_length=50)
address_line_2 = models.CharField(max_length=50, blank=True)
country = models.CharField(max_length=50)
state = models.CharField(max_length=50)
city = models.CharField(max_length=50)
order_note = models.CharField(max_length=100, blank=True)
order_total = models.FloatField()
tax = models.FloatField()
status = models.CharField(max_length=10, choices=STATUS, default='New')
ip = models.CharField(blank=True, max_length=20)
is_ordered = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def full_name(self):
return f'{self.first_name}'
and here is a view that is am using:
def place_order(request, total=0, quantity=0,):
current_user = request.user
# If the cart count is less than or equal to 0, then redirect back to shop
cart_items = CartItem.objects.filter(user=current_user)
cart_count = cart_items.count()
if cart_count <= 0:
return redirect('store')
grand_total = 0
tax = 0
for cart_item in cart_items:
total += (cart_item.product.price * cart_item.quantity)
quantity += cart_item.quantity
tax = (2 * total)/100
grand_total = total + tax
if request.method == 'POST':
form = OrderForm(request.POST)
if form.is_valid():
# Store all the billing information inside Order table
data = Order()
data.user = current_user
data.first_name = form.cleaned_data['first_name']
data.last_name = form.cleaned_data['last_name']
data.phone = form.cleaned_data['phone']
data.email = form.cleaned_data['email']
data.address_line_1 = form.cleaned_data['address_line_1']
data.address_line_2 = form.cleaned_data['address_line_2']
data.country = form.cleaned_data['country']
data.state = form.cleaned_data['state']
data.city = form.cleaned_data['city']
data.more_address_details = form.cleaned_data['more_address_details']
data.order_note = form.cleaned_data['order_note']
data.order_note = form.cleaned_data['order_note']
data.order_total = grand_total
data.tax = tax
data.ip = request.META.get('REMOTE_ADDR')
data.save()
# Generate order number
yr = int(datetime.date.today().strftime('%Y'))
dt = int(datetime.date.today().strftime('%d'))
mt = int(datetime.date.today().strftime('%m'))
d = datetime.date(yr,mt,dt)
current_date = d.strftime("%Y%m%d") #20210305
order_number = current_date + str(data.id)
data.order_number = order_number
data.save()
order = Order.objects.get(user = current_user, is_ordered = False, order_number = order_number)
context = {
'order': order,
'cart_items': cart_items,
'total': total,
'tax': tax,
'grand_total': grand_total,
}
return render(request, 'orders/payments.html', {'context': context})
else:
return redirect('checkout')
else:
return redirect('store')
and here is what is in the template:
def place_order(request, total=0, quantity=0,):
current_user = request.user
# If the cart count is less than or equal to 0, then redirect back to shop
cart_items = CartItem.objects.filter(user=current_user)
cart_count = cart_items.count()
if cart_count <= 0:
return redirect('store')
grand_total = 0
tax = 0
for cart_item in cart_items:
total += (cart_item.product.price * cart_item.quantity)
quantity += cart_item.quantity
tax = (2 * total)/100
grand_total = total + tax
if request.method == 'POST':
form = OrderForm(request.POST)
if form.is_valid():
# Store all the billing information inside Order table
data = Order()
data.user = current_user
data.first_name = form.cleaned_data['first_name']
data.last_name = form.cleaned_data['last_name']
data.phone = form.cleaned_data['phone']
data.email = form.cleaned_data['email']
data.address_line_1 = form.cleaned_data['address_line_1']
data.address_line_2 = form.cleaned_data['address_line_2']
data.country = form.cleaned_data['country']
data.state = form.cleaned_data['state']
data.city = form.cleaned_data['city']
data.more_address_details = form.cleaned_data['more_address_details']
data.order_note = form.cleaned_data['order_note']
data.order_note = form.cleaned_data['order_note']
data.order_total = grand_total
data.tax = tax
data.ip = request.META.get('REMOTE_ADDR')
data.save()
# Generate order number
yr = int(datetime.date.today().strftime('%Y'))
dt = int(datetime.date.today().strftime('%d'))
mt = int(datetime.date.today().strftime('%m'))
d = datetime.date(yr,mt,dt)
current_date = d.strftime("%Y%m%d") #20210305
order_number = current_date + str(data.id)
data.order_number = order_number
data.save()
order = Order.objects.get(user = current_user, is_ordered = False, order_number = order_number)
context = {
'order': order,
'cart_items': cart_items,
'total': total,
'tax': tax,
'grand_total': grand_total,
}
return render(request, 'orders/payments.html', {'context': context})
else:
return redirect('checkout')
else:
return redirect('store')
I AM ALWAYS BLOWNED BY THE KIND OF PEOPLE WHO ALWAYS HELP WITHOUT EXPECTING ANYTHING IN RETURN, REALLY THANKS
Just found where the error was, had forgotten to add the name of a form field "more_address_details" in the template

TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use technicians.set() instead

I keep getting this very same type error even though I am using set. Can someone maybe point out what I'm doing wrong in my api endpoint?
views.py
#require_http_methods(["GET", "POST"])
def api_requerimientos(request):
if request.method == "GET":
requerimientos = FormularioCliente.objects.all()
return JsonResponse(
{"requerimientos": requerimientos},
encoder=FormularioClienteEncoder,
)
elif request.method == "POST":
print("POST REQUEST HIT")
try:
content = json.loads(request.body)
except json.JSONDecodeError:
return HttpResponseBadRequest("Invalid JSON in request body")
requerimiento = FormularioCliente(**content) # Create a new FormularioCliente object
if "technicians" in content and isinstance(content["technicians"], list):
try:
technicians_id_list = content["technicians"]
technicians = Technician.objects.filter(employee_number__in=technicians_id_list)
requerimiento.technicians.set(technicians)
requerimiento.save()
print('requerimiento:', requerimiento)
except Technician.DoesNotExist:
pass
requerimiento.save() # Save the object to the database
models.py
class FormularioCliente(models.Model):
empresa = models.CharField(max_length=21, null=True, unique=True)
titulo = models.CharField(max_length=66)
descripcion = models.CharField(max_length=66)
enlace = models.URLField(null=True)
tipo = models.CharField(max_length=17, choices=TIPO_REQUIRIMIENTO, default="tecnologia")
date = models.DateField(null=True, auto_now_add=True)
time = models.TimeField(null=True, auto_now_add=True)
entrega = models.DateField(null=True)
finished = models.CharField(max_length=19, choices=TIPO_FINALIZACION, default="Abierto")
technicians = models.ManyToManyField(Technician, blank=True)
special_hours = models.SmallIntegerField(default=0)
regular_hours = models.PositiveSmallIntegerField(default=1)
total_hours = models.SmallIntegerField(default=1)
importancia = models.PositiveSmallIntegerField(default=1)
file = models.FileField(upload_to='files', blank=True)
updated = models.DateField(auto_now=True)
def __str__(self):
return f'{self.titulo}: {self.descripcion} # {self.date}'
def technicians_as_json(self):
return list(self.technicians.all().values())
class Technician(models.Model):
name = models.TextField()
employee_number = models.SmallIntegerField(unique=True, primary_key=True)
def __str__(self):
return self.name + " - " + str(self.employee_number)
encoders.py
class TechnicianEncoder(ModelEncoder):
model = Technician
properties = ["name", "employee_number"]
class FormularioClienteEncoder(ModelEncoder):
model = FormularioCliente
properties = [
"id",
"empresa",
"titulo",
"descripcion",
# "user",
"enlace",
# "tipo",
# "File",
"tipo",
"date",
"time",
"entrega",
"finished",
"technicians", # <-- Add this
"special_hours",
"regular_hours",
"total_hours",
"importancia",
"updated",
]
encoders = {"technicians": TechnicianEncoder()}
I also tried to loop through technicians queryset and add it to the instance one by one as well via the add() method but that also didn't work.
I even tried this:
techs = list(requerimiento.technicians.filter(employee_number__in=technicians_id_list).all())
requerimiento.technicians.set(techs)
None of it worked

ValueError: variable needs to have a value for field "id" before this many to many relationship can be used - Django

I created a datamodel in Django, and now I created a script to auto populate the models using web-scraped values. However when I run the script I get the following error:
ValueError: variable needs to have a value for field "id" before this many to many relationship can be used
Models.py
class Books(models.Model):
title = models.CharField(max_length=100)
def __str__(self):
return self.title
class Meta:
ordering = ['-title']
class Author(models.Model):
book = models.ManyToManyField(Books)
first_name = models.CharField(max_length=150)
last_name = models.CharField(max_length=200)
def __str__(self):
return "{} {}".format(self.first_name, self.last_name)
class Meta:
ordering = ['last_name','first_name']
class Book_details(models.Model):
book = models.ForeignKey(Books,
on_delete=models.CASCADE,
null=True) # models.SET_NULL weggehaald
pages = models.CharField(max_length=250)
publ_year = models.CharField(max_length=250)
edition = models.CharField(max_length=30) # paperback, hardcover, audiobook, etc
def __str__(self):
return "{} - pages: <{}>, edition: <{}>".format(self.book.title,
self.pages,
self.edition)#
class Cover(models.Model):
book = models.OneToOneField(Books,
on_delete=models.CASCADE)
path = models.CharField(max_length=500)
def __str__(self):
return "<Cover <path={}>".format(self.id, self.path)
populate_script
def add_book(title):
b = Books.objects.get_or_create(title = title)[0]
print(b)
b.save()
return b
def populate(scraped_tuple):
fake = Faker()
for _ in range(len(scraped_tuple)):
b_title = scraped_tuple[_][0][0]
new_book = add_book(b_title)
b_author_first = scraped_tuple[_][0][1].split(" ")[0]
b_author_last = scraped_tuple[_][0][1].split(" ")[1]
b_pages = scraped_tuple[_][0][2].split(" ")[0]
b_publ_year = fake.year()
b_edition = scraped_tuple[_][0][3].split(",")[0]
b_cover = scraped_tuple[_][0][4]
new_details = Book_details.objects.get_or_create(book = new_book, pages = b_pages, publ_year = b_publ_year, edition = b_edition)[0]
new_author = Author.objects.get_or_create(book = new_book, first_name = b_author_first, last_name = b_author_last)[0]
new_cover = Cover.objects.get_or_create(book = new_book, path = b_cover)[0]
The scraped_tuple is a return value from the webscraper containing the details.
(Part of) the Traceback:
Books.models.DoesNotExist: Author matching query does not exist.
File "C:\path\to\LibraryApp\Library_WebA
pp\Library\populate.py", line 45, in populate
new_author = Author.objects.get_or_create(book = new_book, first_name = b_author_first, last_nam
e = b_author_last)[0]
Followed by:
ValueError: "<Author: Mary McCarthy>" needs to have a value for field "id" before this many-to-many relationship can be used.
So, it seems that something goes awfully wrong when trying to execute the new_author statement, because of the many-to-many field "book" in the Author model. How can I resolve this. Do I need a similar function for an Author object like I have for the Book in add_book()?
It seems the new_details statement executes just fine (title and book_details appear correctly in the database in the admin part of Django).
As mentioned in the docs, user .add() to associate the records in many to many field.
def populate(scraped_tuple):
fake = Faker()
for _ in range(len(scraped_tuple)):
b_title = scraped_tuple[_][0][0]
new_book = add_book(b_title)
b_author_first = scraped_tuple[_][0][1].split(" ")[0]
b_author_last = scraped_tuple[_][0][1].split(" ")[1]
b_pages = scraped_tuple[_][0][2].split(" ")[0]
b_publ_year = fake.year()
b_edition = scraped_tuple[_][0][3].split(",")[0]
b_cover = scraped_tuple[_][0][4]
new_details = Book_details.objects.get_or_create(book = new_book, pages = b_pages, publ_year = b_publ_year, edition = b_edition)[0]
new_author = Author.objects.get_or_create(first_name = b_author_first, last_name = b_author_last)[0]
# add many to many fields this way:
new_author.book.add(new_book)
new_cover = Cover.objects.get_or_create(book = new_book, path = b_cover)[0]

How to build a form for nested models?

I am building an app in Django 1.9 with the models Customers and Addresses:
class Customers(models.Model):
name = models.CharField(db_column='NAME', max_length=400)
email = models.CharField(db_column='EMAIL', max_length=255, unique=True)
phone_number = models.CharField(db_column='PHONE_NUMBER', max_length=200, blank=True, null=True)
address = models.ForeignKey(Addresses, db_column='ADDRESS_ID', related_name='customer_address', null=True)
class Addresses(models.Model):
street = models.TextField(db_column='STREET', max_length=2000)
city = models.CharField(db_column='CITY', max_length=400, blank=True, null=True)
postal_code = models.CharField(db_column='POSTAL_CODE', max_length=200, blank=True, null=True)
country = models.ForeignKey(Country, db_column='COUNTRY_ID', null=True)
I am new in Django, so please forgive me if this has too much mistakes.
I want to create a new Customer using a form:
class CustomersForm(ModelForm):
name = forms.CharField(label=_(u'Name'), widget=TextInput())
email = forms.CharField(label=_(u'Email'), widget=TextInput())
phone_number = forms.IntegerField(label=_(u'Phone Number'), required=False, widget=TextInput(attrs={'style': 'width:80px'}))
But I still want to be able to add the address. I read some stuff about nested forms, but I didn't understand.
Could you, please, help in building a form that creates a Customer with name, email, phone_number and address?
I figured it out! :)
You have to override the save method of the form.
class CustomersForm(ModelForm):
name = forms.CharField(label=_(u'Name'), widget=TextInput())
email = forms.CharField(label=_(u'Email'), widget=TextInput())
a_street = forms.CharField(label=_(u'Street'), widget=TextInput(), required=False)
a_postal_code = forms.CharField(label=_(u'Postal Code'), widget=TextInput(), required=False)
a_city = forms.CharField(label=_(u'City'), widget=TextInput(), required=False)
a_country = forms.CharField(label=_(u'Country'), widget=TextInput(), required=False)
# Override the save method like this
def save(self, commit=True):
c = super(CustomersForm, self).save(commit=False)
# Address
if c.address:
a = c.address
else:
a = Addresses()
a.street = self.cleaned_data.get('a_street')
a.city = self.cleaned_data.get('a_city')
a.postal_code = self.cleaned_data.get('a_postal_code')
a.country = self.cleaned_data.get('a_country')
if commit:
a.save()
c.address = a
c.save()
return c

Django model inserting foreign key from same model

I am building a simple comment app in Django. The app allows replies to comments and uses the same model to store comments and replies. My issues is when I try to insert a new reply, the parentpost(FK to parent comment) inserts as NULL. When I use the admin interface to insert a reply, it properly stores the parentpost ID for the parentpost I choose. So I know the issue is not within my model but within my view.
/MODEL/
class UserPost(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, unique=True,
help_text='Unique value for product page URL, created from name.', editable = False)
post = models.TextField()
is_active = models.BooleanField(default=True)
meta_keywords = models.CharField("Meta Keywords", max_length=255, blank = True, null = True,
help_text='Content for description meta tag')
meta_description = models.CharField(max_length = 255, blank = True, null = True,
help_text = 'Content for description meta tag')
created_at = models.DateTimeField(auto_now_add = True)
updated_at = models.DateTimeField(auto_now = True)
parentpost = models.ForeignKey('self', blank = True, null = True)
class Meta:
#app_label = ''
db_table = 'userposts'
ordering = ['created_at']
verbose_name_plural = 'UserPosts'
def __unicode__(self):
return self.name
#models.permalink
def get_absolute_url(self):
return ('lync_posts', (), {'posts_slug': self.slug})
def save(self):
if not self.id:
d = datetime.datetime.now()
s = d.strftime('%Y-%M-%d-%H-%M-%S-%f')
slugfield = str(self.name + s)
self.slug = slugfield
super(UserPost, self).save()
/VIEW/
def reply(request, slugIn):
parentpostIn = UserPost.objects.get(slug = slugIn)
pid = parentpostIn.id
template_name = 'reply.html'
if request.method == 'POST':
form = forms.ReplyPostForm(data = request.POST)
# create a new item
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
if form.is_valid():
nameIn = form.cleaned_data['name']
postIn = form.cleaned_data['post']
newPost = UserPost(name = nameIn, post = postIn, parentpost = pid)
newPost.save()
return render_to_response(template_name, locals(), context_instance = RequestContext(request))
else:
# This the the first page load, display a blank form
form = forms.NewPostForm()
return render_to_response(template_name, locals(), context_instance=RequestContext(request))
return render_to_response(template_name, locals(), context_instance=RequestContext(request))
You are trying to set the parentpost ForeignKey by id.
You should either use:
newPost = UserPost(name = nameIn, post = postIn, parentpost = parentpostIn)
or (see Django: Set foreign key using integer?):
newPost = UserPost(name = nameIn, post = postIn)
newPost.parentpost_id = pid

Resources