I am trying to make one simple application but seems like facing issue. I have created many to many object between student and course and has also define dept.
My model is mentioned below:
class Course(models.Model):
courseId = models.AutoField(primary_key=True)
courseName = models.CharField(max_length=100)
enrolledStu = models.IntegerField(max_length=3)
students = models.ManyToManyField(Student)
dept = models.ForeignKey(Dept, on_delete=models.CASCADE)
def __str__(self):
return '%s %s %s %s' % (self.courseName,self.enrolledStu,self.students,self.dept)
class Dept(models.Model):
deptId = models.AutoField(primary_key=True)
deptName = models.CharField(max_length=100)
def __str__(self):
return '%s %s' % (self.deptId, self.deptName)
class Student(models.Model):
stuName = models.CharField(max_length=100)
stuCity = models.CharField(max_length=100)
stuPhone = models.IntegerField(max_length=10)
stuNationality = models.CharField(max_length=50)
stuCreatedt = models.DateTimeField(default=timezone.now)
def __str__(self):
return '%s %s %s' % (self.stuName,self.stuCity,self.stuNationality)
my form is :
class StudentForm(forms.ModelForm):
class Meta:
model = Student
fields = ('stuName','stuCity','stuPhone','stuNationality','stuCreatedt')
class CourseForm(forms.ModelForm):
class Meta:
model = Course
fields = ('courseId','courseName','enrolledStu','students','dept')
class DeptForm(forms.ModelForm):
class Meta:
model = Dept
fields = ('deptId','deptName')
I have displayed list of course , students and dept in html template now i am trying to edit it with code :
def edtStudent(request,pk):
course = Course.objects.filter(pk=1).prefetch_related('students').select_related('dept').get()
if request.method =="POST":
form = CourseForm(request.POST,instance=Course)
if form.is_valid():
course = form.save(commit=False)
print(form.cleaned_data)
course.courseName = request.POST['courseName']
course.enrolledStu = request.Post['enrolledStu']
course.save()
course.save_m2m()
return redirect('liststudent')
else:
print(course.__dict__)
print(course.students)
#form = CourseForm()
#return render(request, 'stuApp/edtStudent.html', {'form':form})
#form = CourseForm(instance=course[0]) worked
form = CourseForm(instance=course)
return render_to_response('stuApp/edtStudent.html', {'form': form})
so instead of getting one student i am getting all students for course.. Seems like my query is incorrect. Can you help with that..
Another question i have is how can i print values for objects in many to many relationship.. for now if i print course object i am getting results like
{'_state': <django.db.models.base.ModelState object at 0x000000000457ED68>, 'courseId': 1, 'courseName': 'Account', 'enrolledStu': 1, 'dept_id': 1, '_dept_cache': <Dept: 1 Finance>, '_prefetched_objects_cache': {'students': <QuerySet [<Student: Mamta Mumbai Indian>]>}}
..
so from Query Set i would like to take only student name...
Jordan
I have follow up question for this.. when i try to edit course for html template it gets the values which are correct ,but for student its gets all attribute like studentname , city , natinality etc.. which wrong.. i want only student name from student and display it in template.
I am using following query to get course related information.
course = Course.objects.filter(pk=1).prefetch_related('students').select_related('dept').get()
getting results from query but for student it gets all attribute
Now in my views i am using this code:
course = Course.objects.filter(pk=1).prefetch_related('students').select_related('dept').get()
form = CourseForm(instance=course)
return render_to_response('stuApp/edtStudent.html', {'form': form})
i figured out how to get value for student name instead of all atributes.
course.students = course.students.value_list('stuName', flat=True)
but i am not sure how can i set above value to form and display it in template..
this where i am failing..
Related
I have manytomanyfield inside my model.The manytomanyfield field lists the products in the products table.
I want to enter the amount for each product I choose. How can I relate manytomanyfield to floatfield field?
That's my model:
`
class TaskSources(models.Model):
id = models.AutoField(primary_key=True)
user_task_id = models.ForeignKey(UserTask,on_delete=models.CASCADE)
product_id = models.ManyToManyField(Product, verbose_name="Product",default=None)
product_amount = models.FloatField(max_length=255,verbose_name="Product Amount")
`
The form:
`
class TaskSourcesForm(forms.ModelForm):
class Meta:
model = TaskSources
fields = ['product_id', 'product_amount']
`
The views:
`
#login_required(login_url="login")
def addUserTask(request):
user_task_form = UserTaskForm(request.POST or None,initial={'user_id': request.user})
task_sources_form = TaskSourcesForm(request.POST or None)
if request.method == 'POST':
if user_task_form.is_valid():
user_task = user_task_form.save(commit=False)
user_task.author = request.user
user_task.save()
print(user_task.id)
if task_sources_form.is_valid():
task_sources = task_sources_form.save(commit=False)
task_sources.user_task_id = UserTask(id = user_task.id)
task_sources.save()
task_sources_form.save_m2m()
messages.success(request,"Task added successfully!")
return redirect(".")
context = {
"user_task_form" : user_task_form,
"task_sources_form" : task_sources_form,
}
return render(request,"user/addtask.html",context)
`
Thanks for care.
I tried associating the two fields with each other, but I could not succeed.
If I got it right I think that what you need is an intermediate table between your models. That way you can link an amount of a product to a TaskSource, something similar to this:
class Product(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class ProductAmount(models.Model):
amount = models.FloatField(max_length=255,verbose_name="Product Amount")
product = models.ManyToManyField(Product, through='TaskSources')
def __str__(self):
return self.name
class UserTask(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class TaskSources(models.Model):
id = models.AutoField(primary_key=True) # this is not really necessary
task = models.ForeignKey(UserTask,on_delete=models.CASCADE)
product_amount = models.ForeignKey(ProductAmount, on_delete=models.CASCADE)
I have a django view that generates a form depending on POST or GET. It works well with little data on the Student model but stagnates when the data gets big. Is there a remedy I can apply??
Here's the view
def My_View(request,pk):
if request.method == 'POST':
try:
form = NewIssueForm(request.POST,school= request.user.school,pk=pk,issuer = request.user)
if form.is_valid():
name = form.cleaned_data['borrower_id'].id
form.save(commit=True)
books = Books.objects.get(id=pk)
Books.Claimbook(books)
return redirect('view_books')
messages.success(request,f'Issued successfully')
except Exception as e:
messages.warning(request,f"{e}")
return redirect('view_books')
else:
form = NewIssueForm(school= request.user.school,pk=pk,issuer = request.user)
return render(request, 'new_issue.html', {'form': form})
Here's the form
class NewIssueForm(forms.ModelForm):
def __init__(self,*args, pk,school,issuer, **kwargs):
super(NewIssueForm, self).__init__(*args, **kwargs)
booqs = Books.objects.filter(school=school).get(id=pk)
self.fields['issuer'].initial = issuer
self.fields['borrower_id'].Student.objects.filter(school = school)
self.fields['book_id'].label = str(booqs.book_name) + " - " + str(booqs.reg_no)
self.fields['book_id'].initial = pk
class Meta:
model = Issue
fields = ['issuer','book_id','borrower_id','due_days']
widgets = {
'book_id':forms.TextInput(attrs={"class":'form-control','type':''}),
'issuer':forms.TextInput(attrs={"class":'form-control','type':'hidden'}),
'borrower_id': Select2Widget(attrs={'data-placeholder': 'Select Student','style':'width:100%','class':'form-control'}),
'due_days':forms.TextInput(attrs={"class":"form-control"}),
Student model
class Student(models.Model):
school = models.ForeignKey(School, on_delete=models.CASCADE)
name = models.CharField(max_length=200,help_text="The student's name in full")
now = datetime.datetime.now()
YEAR = [(str(a), str(a)) for a in range(now.year-5, now.year+1)]
year = models.CharField(max_length=4, choices = YEAR,help_text='The year the student is admitted in school')
student_id = models.CharField(max_length=40,help_text = "This is the student's admission number")
klass = models.ForeignKey(Klass,on_delete=models.CASCADE)
stream = models.ForeignKey(Stream,on_delete=models.CASCADE)
graduated = models.BooleanField(default=False,help_text = "Tick the box to mark the student as graduated")
prefect = models.BooleanField(default=False,help_text = "Tick the box to select the student as a prefect")
def __str__(self):
return "%s - %s - F%s %s"%(self.student_id,self.name,self.klass,self.stream)
class Meta:
verbose_name_plural = 'Students'
unique_together = ("school", "student_id",)
indexes = [models.Index(fields=['student_id']),
models.Index(fields=['name', ]),
The reason this happens is because when you render the Student, it will need to fetch the related Klass and Stream objects, and will make a query per Student object. This problem is called an N+1 problem since fetching n student requires one query to fetch all the Students, and then one query per Student for the Klasses, and one query per Student for the Streams.
You can select the data when you select the students with:
self.fields['borrower_id'].Student.objects.filter(
school=school
).select_related('klass', 'stream')
Depending on the __str__ implementations of other models, you might have to select data along with these models as well.
Can't guess your model but it seems like select_related may play a trick.
I need to create the new object or just update if already existing. I receive: QuerySet' object has no attribute "seat". Don't know what I'm doing wrong.
models:
class rows_and_seats(models.Model):
movie = models.ForeignKey(Movies, on_delete=models.CASCADE)
row = models.CharField(max_length = 1)
number = models.IntegerField()
def __str__(self):
return f'{self.movie}'
class Reservation(models.Model):
customer = models.ForeignKey(User, on_delete=models.CASCADE)
movie = models.ForeignKey(Movies, on_delete=models.CASCADE)
seat = models.ManyToManyField(rows_and_seats)
ordered = models.DateTimeField(default=datetime.now().strftime("%Y-%m-%d %H:%M:%S"), blank=True, null=True)
def __str__(self):
return f'{self.customer.username}:{self.movie.title}:{self.ordered}'
views
#login_required
def buy_seats(request, pk):
if request.method == "POST" and request.session.get("seats"):
seats = request.session.pop("seats")
movie = Movies.objects.get(pk=pk)
customer = User.objects.get(pk=request.user.id)
for s in seats:
user_reserved_seats = rows_and_seats.objects.get(movie=movie, row=s[:1], number=int(s[2:]))
reservation_check = Reservation.objects.filter(customer=customer, movie=movie)
if reservation_check.exists():
reservation_check.seat.add(user_reserved_seats)
else:
new_reservation = Reservation.objects.create(customer=customer, movie=movie)
new_reservation.seat.add(user_reserved_seats)
messages.success(request,"You have succesfully reserved the seats.")
return redirect("home")
return redirect("home")
My goal is to keep rows_and_seat in manyTomany in order to display only one reservation of user in admin panel, instead of the list of repeating itself titles.
You can access the value after the exists() check:
if reservation_check.exists():
reservation_check.first().seat.add(user_reserved_seats)
else:
new_reservation = Reservation.objects.create(customer=customer, movie=movie)
new_reservation.seat.add(user_reserved_seats)
Maybe you can use something like get_or_create:
user_reserved_seats = rows_and_seats.objects.get(movie=movie, row=s[:1], number=int(s[2:]))
reservation, created = Reservation.objects.get_or_create(
customer=customer, movie=movie,
)
reservation.seat.add(user_reserved_seats)
Also you might be looping over the seats too many times, maybe you can add all the seats in only one assignment.
Have a models:
class Product(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
variation_1 = models.BooleanField(default=True)
variation_2 = models.BooleanField(default=True)
variation_3 = models.BooleanField(default=True)
class Order(models.Model):
buyer = models.ForeignKey(User, related_name='buyer')
product = models.ForeignKey(Product)
variations_select = models.CharField(max_length=50, choices=VARIATIONS)
in forms.py
class OrderForm(forms.ModelForm):
variations_select = forms.ChoiceField(choices=VARIATIONS)
class Meta:
model = Order
fields = [
'variations_select'
]
i need to create a clean function that will check if variation_1 or variation_2 or variation_3 are availiable in Product. For this a need request Product.id to def clean_variations_select(self): How to do this?
def clean_variations_select(self):
product = Product.object.get(id = product.id)
variations_select = self.cleaned_data.get("variations_select")
if variations_select == "Variation_1" and product.variation_1 == False:
raise forms.ValidationError("variation_1 was sold already")
else:
return variations_select
product = Product.object.get(id = product.id) - don't work cause Order isn't created to database yet(but in rendering view link to new order creation i have that ../product.id/new_order).
You need to define an __init__ method for your class which should accept your product id as an argument.
def __init__(self,*args,**kwargs):
self.product_id = kwargs.pop('product_id')
super(OrderForm,self).__init__(*args,**kwargs)
When you initialize your form, you pass your product_id as a keyword argument.
OrderForm(request.POST, product_id=product_id)
And in clean method you can use self.product_id to get the Product object you want.
def clean_variations_select(self):
product = Product.object.get(id=self.product_id)
variations_select = self.cleaned_data.get("variations_select")
if variations_select == "Variation_1" and product.variation_1 == False:
raise forms.ValidationError("variation_1 was sold already")
else:
return variations_select
I have a model that looks like this
class RSVP (models.Model):
def __unicode__(self):
return self.firstName + " " + self.lastName
firstName = models.CharField(max_length=30)
lastName = models.CharField(max_length=30)
rsvpID = models.CharField(max_length=9, unique = True)
allowedAdults = models.IntegerField(default = 2)
allowedChildren = models.IntegerField(default = 0)
adultsAttending = models.IntegerField(default = 0)
childrenAttending = models.IntegerField(default = 0)
and I have a ModelForm that looks like this
class RsvpForm(ModelForm):
class Meta:
model = RSVP
exclude= ('firstName', 'lastName', 'allowedAdults', 'allowedChildren')
What I would like to happen is that instead of a text field for the adultsAttending, a dropdown box with the values 0 to allowedAdults shows up. This is for a wedding rsvp site and I'd like to set the max number of +1's an invitee can bring on an individual basis
Any thoughts on how to go about this?
I'm thinking you want to fork the allowed children/ adults as well as the name to another model:
models.py
class Invited(models.Model):
f_name = models.CharField()
l_name = models.CharField()
allowed_adults = models.IntegerField()
allowed_children = models.IntegerField()
class RSVP(models.Model):
invited = models.ForeignKey(Invited)
adults_attending = models.IntegerField()
children_attending = models.IntegerField()
Then you would create the invited objects and assign the allowed adults and children. And the RSVP form would take those number into account when generating the choices for your drop down box.
The drop down can be implemented by overriding the IntegerField widget with a ChoiceField
forms.py
class InvitedForm(forms.ModelForm):
class Meta:
model = Invited
class RSVPForm(forms.ModelForm):
class Meta:
model = RSVP
exclude = ['invited',]
def __init__(self, *args, **kwargs):
max_adults = kwargs.pop('max_adults',2) #default to 2 if no max set
max_children = kwargs.pop('max_children',2) #default to 2 if no max set
super(RSVPForm, self).__init__(*args, **kwargs)
adult_choices = ( (x,str(x)) for x in range(max_adults+1)) )
children_choices = ( (x,str(x)) for x in range(max_children+1)) )
self.fields['adults_attending'] = forms.ChoiceField(choices = adult_choices)
self.fields['children_attending'] = forms.ChoiceField(choices = children_choices)
views.py
def rsvp_view(request, invited_id):
invited = get_object_or_404(Invited, pk=invited_id)
if request.method=='POST':
form = RSVPForm(request.POST, max_adults=invited.allowed_adults,
max_children=invited.allowed_children)
if form.is_valid():
rsvp = form.save(commit=False)
rsvp.invited = invited
rsvp.save()
return HttpResponse("Success")
else:
form = RSVPForm(max_adults=invited.allowed_adults, max_children=invited.allowed_children)
context = { 'form':form,
'invited':invited }
return render_to_response('rsvp.html', context,
context_instance=RequestContext(request))