Django - Save forms in the same data table - django

I'm having problem in saving selected choices in the same row of data table for each participant).
I have 2 forms. The first form is for some data and a multiple-choice question. The second form is another multiple-choice question. It also means I have 2 pages, after submit answers for page 1, it will redirect to page 2 for question 2.
When I try to be a participant and choose answers, the selected choices are saved in different data table. Pictures and code are displayed below.
forms.py
from django import forms
from .models import Survey
class SurveyForm(forms.ModelForm):
BAT='Batman'
SUPER='Superman'
IRON='Ironman'
WHATMOVIE1 = [
(BAT, 'Batman'),
(SUPER, 'Superman'),
(IRON, 'Ironman'),
]
movie_1 = forms.ChoiceField(choices=WHATMOVIE1, widget=forms.RadioSelect())
class Meta:
model = Survey
fields = ["location", "age",
"marital_status", "education", 'movie_1']
class SurForm(forms.ModelForm):
APP='Apple'
BAN='Banana'
LEM='Lemon'
WHATMOVIE2 = [
(APP, 'Apple'),
(BAN, 'Banana'),
(LEM, 'Lemon'),
]
movie_2 = forms.ChoiceField(choices=WHATMOVIE2, widget=forms.RadioSelect())
class Meta:
model = Survey
fields = [ 'movie_2']
views.py
from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from .forms import SurveyForm, SurForm
def homepage(request):
if request.method == 'POST':
title = "Questionnaire"
form = SurveyForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return HttpResponseRedirect(reverse('nextpage'))
else:
form = SurveyForm()
return render(request, "homepage.html", {"form": form})
def nextpage(request):
title = "Next page"
form = SurForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
context = {
"form": form,
}
return render(request, "nextpage.html", context)
admin.py
from django.contrib import admin
from .forms import SurveyForm, SurForm
from .models import Survey, Sur
class SurAdmin(admin.ModelAdmin):
form = SurForm
class SurveyAdmin(admin.ModelAdmin):
list_display = ["location", "age",
"marital_status", "education",
"movie_1"]
form = SurveyForm
admin.site.register(Survey, SurveyAdmin)
admin.site.register(Sur, SurAdmin)
What should I do to save all selected answers in the same row for each participant?

You are using two different models, that is why they are getting separated. You need to create a relation between them, using a OneToOneField can solve the problem. Something like this:
from django.db import models
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
def __str__(self): # __unicode__ on Python 2
return "%s the place" % self.name
class Restaurant(models.Model):
place = models.OneToOneField(Place, primary_key=True)
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
def __str__(self): # __unicode__ on Python 2
return "%s the restaurant" % self.place.name
Optionally, you can just combine the two models.

Related

When adding a new query in Django, the foreign key gets the value NULL

I am still learning programming and currently experimenting with Django.
Currently I am trying to build a task manager but when I try to add a new Tasks(def new_tasks) it should be related to TaskGroup, instead the task_group_id is related to NULL and I can't seem to figure out why. I believe the reason is some where in the views.py -> def new_tasks. Any help is gratefully appreciated.
The structure:
Project 1
Task Group 1
Tasks 1
Task 1
Task 2
Task 3
Tasks 2
Task 4
Task 5
Task Group 2
Tasks 3
Task 6
Project 2
Task Group 3
Tasks 4
Task 7
Task 8
Relating the Task Group to Project works but relating the Tasks to Task Group gives the value NUll.
image of database
Models.py
from django.db import models
from django.contrib.auth.models import User
class Project(models.Model):
"""A project the user is working on."""
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
"""Return a string representation of the model."""
return self.text
class TaskGroup(models.Model):
""" Title of a group of tasks """
project = models.ForeignKey(Project, null=True, on_delete=models.CASCADE)
title = models.CharField(max_length=100, blank=True, default='')
desc = models.CharField(max_length=300, default='')
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
""" Return a string representation of the model. """
return self.title
class Tasks(models.Model):
""" Will be the title/segment that will contain the task items """
task_group = models.ForeignKey(TaskGroup, null=True, on_delete=models.CASCADE)
title = models.CharField(max_length=100, default='')
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
""" Return a string representation of the model. """
return self.title
views.py
from django.shortcuts import render, redirect
from .models import Project, TaskGroup, Task, Tasks
from .forms import ProjectForm, TasksForm, TaskGroupForm
from django.contrib.auth.decorators import login_required
from django.http import Http404
from django.contrib import messages
# Delete
from django.core.exceptions import PermissionDenied
from django.urls import reverse
#login_required
def taskgroup(request, task_id):
"""Show a single task"""
taskgroup = TaskGroup.objects.get(id=task_id)
tasks = taskgroup.tasks_set.all()
# Make sure the task belongs to the current user.
project = taskgroup.project
if project.owner != request.user:
raise Http404
context = {'taskgroup':taskgroup, 'tasks': tasks}
return render(request, 'tasks/taskgroup.html', context)
#login_required
def task(request, task_id):
"""Show a single task"""
tasks = Task.objects.get(id=task_id)
# Make sure the task belongs to the current user.
project = tasks.project
if project.owner != request.user:
raise Http404
context = {'tasks':tasks}
return render(request, 'tasks/task.html', context)
#login_required
def new_project(request):
"""Add new project"""
if request.method != 'POST':
# No data submitted; create a blank form.
form = ProjectForm()
else:
# POST data submitted; process data.
form = ProjectForm(data=request.POST)
if form.is_valid():
new_project = form.save(commit=False)
new_project.owner = request.user
new_project.save()
return redirect('tasks:projects')
# Display a blank or invalid form.
context = {'form': form}
return render(request, 'tasks/new_project.html', context)
#login_required
def new_taskgroup(request, project_id):
""" Add new task """
project = Project.objects.get(id=project_id)
# Make sure the task belongs to the current user.
if project.owner != request.user:
raise Http404
if request.method != 'POST':
# No data submitted; create a blank form.
form = TaskGroupForm()
else:
# POST data submitted; process data.
form = TaskGroupForm(data=request.POST)
if form.is_valid():
new_taskgroup = form.save(commit=False)
new_taskgroup.project = project
new_taskgroup.save()
return redirect('tasks:project', project_id=project_id)
# Display a blank or invalid form.
context = {'project': project, 'form': form}
return render(request, 'tasks/new_taskgroup.html', context)
#login_required
def new_tasks(request, taskgroup_id):
""" Add new task """
taskgroup = TaskGroup.objects.get(id=taskgroup_id)
# Make sure the task belongs to the current user.
project = taskgroup.project
if project.owner != request.user:
raise Http404
if request.method != 'POST':
# No data submitted; create a blank form.
form = TasksForm()
else:
# POST data submitted; process data.
form = TasksForm(data=request.POST)
if form.is_valid():
new_tasks = form.save(commit=False)
new_tasks.taskgroup = taskgroup
new_tasks.save()
return redirect('tasks:taskgroup', task_id=taskgroup_id)
# Display a blank or invalid form.
context = {'taskgroup': taskgroup, 'form': form}
return render(request, 'tasks/new_tasks.html', context)
Forms.py
from django import forms
from .models import Project, TaskGroup, Task, Tasks
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = ['text']
labels = {'text': ''}
class TaskGroupForm(forms.ModelForm):
class Meta:
model = TaskGroup
fields = ['title', 'desc']
labels = {'desc': 'Description:','title': 'Title:'}
widgets = {'desc': forms.Textarea(attrs={'cols':80})}
class TasksForm(forms.ModelForm):
class Meta:
model = Tasks
fields = ['title']
labels = {'title': 'title:'}
urls.py
"""Defines URL patterns for tasks"""
from django.urls import path
from . import views
app_name = 'tasks'
urlpatterns = [
# Home page
path('', views.index, name='index'),
# Page that shows all projects.
path('taskmanager/', views.projects, name='projects'),
# Detail page for a single project.
path('taskmanager/<int:project_id>/', views.project, name='project'),
# Detail page for a single taskgroup.
path('taskmanager/task/<int:task_id>/', views.taskgroup, name='taskgroup'),
# Detail page for a single task.
path('taskmanager/task/<int:task_id>/', views.task, name='task'),
# Page for adding a new project
path('new_project/', views.new_project, name='new_project'),
# Page for adding new task group
path('new_taskgroup/<int:project_id>/', views.new_taskgroup, name='new_taskgroup'),
# Page for adding new task
path('new_tasks/<int:taskgroup_id>/', views.new_tasks, name='new_tasks'),
# Page for editing task
path('edit_task/<int:task_id>/', views.edit_task, name='edit_task'),
]
urlpatterns.extend(
[
path('delete/<int:task_id>/', views.delete_task, name='delete_task'),
]
)
Made a Mistake, fixed it.
new_tasks.taskgroup = taskgroup => new_tasks.task_group = taskgroup
thanks to Iain!

how to render django forms manually?

am new in Django. Does anybody know how to implement manual?
I have newsletter app:
newsletter/views.py
from django.shortcuts import render
from .forms import NewsUserForm
from . models import NewsUsers
# Create your views here.
def newsletter_subscribe(request):
if request.method == 'POST':
form = NewsUserForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
instance = form.save(commit=False)
if NewsUsers.objects.filter(email=instance.email).exists():
print('your email Already exists in our database')
else:
instance.save()
print('your email has been submitted to our database')
else:
form = NewsUserForm()
context = {'form':form}
template = "home/base.html"
return render(request, template, context)
newsletter/models.py
from django.db import models
# Subscribe models.
class NewsUsers(models.Model):
name = models.CharField(max_length = 30)
last_name = models.CharField(max_length = 30)
email = models.EmailField()
date_added = models.DateField(auto_now_add=True)
class Meta:
verbose_name = "NewsUser"
verbose_name_plural = "NewsUsers"
def __str__(self):
return self.email
newslettter/urls.py
from django.urls import path
from .views import newsletter_subscribe
app_name = 'newsletter'
urlpatterns = [
path('subscribe', newsletter_subscribe, name='subscribe'),
]
How to render this django forms manually, from third app to home template?
And i have in home app base template with following code:
home/templates/base.html
How to use this form on this template?

how to get a data from database of django and display it in html

I am new to django and i am trying to get data from the database based on a key and include it into html
this is my models.py
from django.db import models
# Create your models here.
class Car(models.Model):
billing_number = models.BigIntegerField(primary_key=True)
customer = models.CharField(max_length=100)
price = models.IntegerField()
purchase_date = models.DateTimeField()
company = models.CharField(max_length=100)
model = models.CharField(max_length=100)
serial_number = models.BigIntegerField()
mfg_date = models.DateTimeField()
shipping_date = models.DateTimeField()
This is my forms.py
from django.forms import ModelForm
from .models import Car
class CarForm(ModelForm):
class Meta:
model = Car
exclude = ()
class CarAccessForm(ModelForm):
class Meta:
model = Car
fields = ('billing_number',)
This is my views.py
from __future__ import unicode_literals
from django.shortcuts import render
from django.views.generic import TemplateView
from django.http import HttpResponseRedirect, HttpResponse
# Create your views here.
from .forms import CarForm, CarAccessForm
def add_car(request):
if request.method == 'POST': # data sent by user
form = CarForm(request.POST)
if form.is_valid():
form.save() # this will save Car info to database
return render(request,'saved.html')
else: # display empty form
form = CarForm()
return render(request, 'add_car.html', {'car_form': form})
def get_car(request):
if request.method == 'POST': # data sent by user
form = CarAccessForm(request.POST)
if form.is_valid():
form.save() # this will save Car info to database
return render(request,'saved.html')
else: # display empty form
form = CarAccessForm()
return render(request, 'get_car.html', {'car_form': form})
how can i change them to display data based on key value
If you want to get data without change page use Ajax (Asynchronous JavaScript)
send data from ajax to view
In the view, prepare the data as json and return them
to return them you can use JsonResponse

Django to clear data causing save() prohibited to prevent data loss due to unsaved related object

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 :-)

Django uploading multiple images

Ive been trying to make this for two days now. I have created website that is capable of uploading one image file, but i would like to be able to upload more of them, that are connected to the same main model.
This is what i have for one picture upload:
forms.py:
from django import forms
from .models import Exam
class ExamForm(forms.ModelForm):
class Meta:
model = Exam
fields = ['exam_number', 'exam_file']
widgets = {
'exam_number': forms.NumberInput(
attrs={'id': 'exam_number', 'required': True,})
}
Models.py:
from django.db import models
from django.contrib.auth.models import User
from django.template.defaultfilters import slugify
from datetime import datetime
from django.core.validators import MaxValueValidator, MinValueValidator
class Exam(models.Model):
exam_number = models.PositiveIntegerField(validators=[MaxValueValidator(6),MinValueValidator(1)])
exam_path = models.CharField(max_length=255)
exam_file = models.ImageField() #i want to be able to upload more of these
exam_date = models.DateTimeField(auto_now_add=True)
exam_user = models.ForeignKey(User, null=True)
def __str__(self):
return self.exam_path
def __int__(self):
return self.exam_number
views.py:
def create_exam(request, letnik_id, classes_id, subject_id):
response_data = {}
if subject_id in SUBJECTS:
path = letnik_id + '/' + classes_id + '/' + subject_id
form = ExamForm(request.POST or None, request.FILES or None)
if form.is_valid():
exam = form.save(commit=False)
exam.exam_user = request.user
exam.exam_path = path
exam.exam_file = request.FILES['exam_file']
file_type = exam.exam_file.url.split('.')[-1]
file_type = file_type.lower()
if file_type not in IMAGE_FILE_TYPES:
context = {
'error_message': 'error',
}
return Http404("Napaka")
if Exam.objects.filter(exam_path=path, exam_number=exam.exam_number):
context = {
'form': form,
'error_message': 'error',
}
return render(request, 'tests.html', context)
exam.save()
return redirect('subject_id', letnik_id=letnik_id, classes_id=classes_id, subject_id=subject_id)
context = {
"form": form
}
raise Http404("error")
raise Http404("error")
ive heard that it would be best to make separated model for files, but i dont know how to make views that would connect to parent(exam) model.
Help is appreciated!
You need to create a separate model that would look something like this
class ExamFile(models.Model):
file = models.ImageField()
exam = models.ForeignKey(Exam, null=False)
Then in your view, instead of adding the exam_file to the exam, you will instead use it to create this new model. This will look something like this
from .models import Exam, ExamFile
...
exam_file = ExamFile.objects.create(
file = request.FILES['exam_file'],
exam=exam
)
For more information on fixing up the forms, you can check out the docs found here