How do I populate my form fields with data from the database Django - html

Hello I have a form page and I only need users to fill in certain fields, with the rest of the fields being pre-filled for them based on the module they pick.
While I can fetch the objects from my database -- i.e. the dropdown list shows Module Object (1), Module Object (2) -- I need only certain fields in these objects, which is why this similar sounding post couldn't answer my question:
Populate a django form with data from database in view
Here's my forms.py
class inputClassInformation(forms.Form):
module = forms.ModelChoiceField(queryset=Module.objects.all())
duration = forms.CharField(disabled=True, required=False)
description = forms.CharField()
assigned_professors = forms.ModelChoiceField(queryset=Class.objects.filter(id='assigned_professors'))
models.py -- not the full models are shown to reduce the post's length
class Module(models.Model):
subject = models.CharField(max_length=200, default="")
class Class(models.Model):
module = models.ForeignKey(Module, on_delete=models.CASCADE, default="")
duration = models.CharField(max_length=200, default="")
description = models.CharField(max_length=200, default="")
assigned_professors = models.CharField(max_length=200, default="")
So an expected result would be:
1) The Module field shows the subjects, instead of Module objects in its dropdown list and
2) The duration field is automatically filled in for the user, based on the module they picked. The reason is so that the user only has to manually fill in certain fields, while the rest are automatically generated.
This has had me stuck for a long while, help is appreciated. Thanks!

So an expected result would be:
1) The Module field shows the subjects, instead of Module objects in its dropdown list and
2) The duration field is automatically filled in for the user.
These are essentially two different questions.
To answer the first: you can override the:
__str__ method for your Model class for python 3 and django 1.8) and the
__unicode__ method for your Model class for django <1.8 and not python3.
For example, to make subjects appear instead of "XXXX Object" for your class do:
class Module(models.Model):
subject = models.CharField(max_length=200, default="")
def __unicode__(self):
return self.subject
Similarly, change __unicode__ for __str__ as appropriate for your django version.
Now, to answer your second question:
2) The duration field is automatically filled in for the user.
You need to do two things:
Do not display the duration field in your form (unless you want to give the users the chance to sometimes fill it in manually)
Override the save method
An example:
class Class(models.Model):
module = models.ForeignKey(Module, on_delete=models.CASCADE, default="")
duration = models.CharField(max_length=200, default="")
description = models.CharField(max_length=200, default="")
assigned_professors = models.CharField(max_length=200, default="")
def save(self, *args, **kwargs):
self.duration = #The value you'd want to automatically set here#
super(Model, self).save(*args, **kwargs)

Related

How do I access a method from my Model in Django in React

In the following model...
class Question(models.Model):
question_text = models.CharField(max_length=200)
likes = models.IntegerField(default=0)
dislikes = models.IntegerField(default=0)
pub_at = models.DateTimeField(auto_now_add=True)
category = models.ForeignKey(
Category, on_delete=models.SET_NULL, null=True)
def __str__(self):
return f"{self.question_text}"
def validity(self):
total_likes = self.likes + self.dislikes
if total_likes != 0:
return (self.likes / total_likes) * 100
else:
return 100
I want to be able to access Question.objects.get(pk=1).validity() assuming that pk=1 exists in this case. In python shell I can do this easily. But how do I do this using React. I am able to get all my questions and the fields in React without a problem but I don't think I have a way to access the validity method I created.
In this case I would suggest the following. First, remove the property from the model:
# models.py
class Question(models.Model):
question_text = models.CharField(max_length=200)
likes = models.IntegerField(default=0)
dislikes = models.IntegerField(default=0)
pub_at = models.DateTimeField(auto_now_add=True)
category = models.ForeignKey(
Category, on_delete=models.SET_NULL, null=True)
def __str__(self):
return f"{self.question_text}"
Then add a SerializerMethodField (docs) to your serializer. It is read-only and can be used to pass computed values to your views:
# serializers.py
class QuestionSerializer(serializers.ModelSerializer):
validity = serializers.SerializerMethodField()
class Meta:
model = Question
fields = ['question_text', 'likes', 'dislikes', 'pub_at', 'category', 'validity']
def get_validity(self, instance):
total_likes = instance.likes + instance.dislikes
# Your approach is not wrong. This is a more explicit way of dealing with that particular error type
try:
return (instance.likes / total_likes) * 100
except ZeroDivisionError:
return 100
Bear in mind that the Foreign Key category will be serialized as its database unique id value (Primary Key) in this case.
You might want to use the #property decorator so that you can access the value the same way you would access any of the other fields on your Question model:
class Question(models.Model):
question_text = models.CharField(max_length=200)
likes = models.IntegerField(default=0)
dislikes = models.IntegerField(default=0)
pub_at = models.DateTimeField(auto_now_add=True)
category = models.ForeignKey(
Category, on_delete=models.SET_NULL, null=True)
def __str__(self):
return f"{self.question_text}"
#property
def validity(self):
total_likes = self.likes + self.dislikes
percentage = (self.likes / total_likes) * 100
return percentage
Explanations can be found in the docs or here. Keep in mind that it will not be saved like the other attributes as columns on the database when you run migrations.
I am answering my own question here I found a solution to. Although, #property does work when rendering using a simple Django template when using React and rendering json responses validity is still not available.
In my serializers.py file I did the following...
class QuestionSerializer(serializers.ModelSerializer):
validity = serializers.ReadOnlyField()
class Meta:
model = Question
fields = '__all__'
Take away the #property from the models as it is no longer needed. This has worked for me and you can go to the Django rest_framework or test it in your React application to see if you have access to this.
I would like to know if there are any issues doing this and/or a better way. I was also trying to do validity = serializers.Field() instead of validity = serializers.ReadOnlyField() but got an error saying I needed a Field.to_representation() that takes in self, value as positional arguments.
What arguments exactly do I pass in here. I tried self, Question.validity and did not work. I am not sure what I am doing here.
As an update the method in the model I updated to...
def validity(self):
total_likes = self.likes + self.dislikes
if total_likes != 0:
return (self.likes / total_likes) * 100
else:
return 100
I did not notice before and does not really matter for the question but division by zero is not allowed being that by default division by zero will always occur.

Django Query values_list getting last value

Lets say I have a blog and a class user in a model. Furthermore I have a class comment connected with a foreign key.
class User(models.Model):
UserName = models.CharField(max_length=50, blank=True)
UserCountry = models.CharField(max_length=2, blank=True)
class Comment(models.Model):
commentText = models.TextField(max_length=1000)
commentSub = models.ForeignKey(User, related_name='comLink')
created_at = models.DateTimeField(auto_now_add=True)
Now I want to make an csv export in model admin and a I have a queryset with values_list.
I am wondering whether there exists a possibility to get each User once and e.g. only the last comment?
myList = queryset.values_list('UserName', 'UserCountry', 'comLink__commentText')
comLink is the related name. Now I just want the last comment. A timestamp is existing and I have not figured out how to filter or reverse etc.
You can do it with Subquery, I don`t know your model design, so it would be approximately like that:
from django.db.models import OuterRef, Subquery
com = Comment.objects.filter(commentSub=OuterRef('pk')).order_by('-created_at')
myList = queryset.annotate(LastComment=Subquery(com.values('commentText')[:1]))
myList = myList.values_list('UserName', 'UserCountry', 'LastComment')
https://docs.djangoproject.com/en/2.0/ref/models/expressions/#subquery-expressions

Django CheckboxSelectMultiple widget : render only selected data by default

Greeting, I have a manytomany field call user in my model_A model, in my form, how can I display only the list of selected data associated to the model_A by default instead of listing entire entries from the User model in my html page? my intention is to create a setting page where I can remove the user associated to a project
below is my code :
model.py :
class model_A(models.Model):
user = models.ManyToManyField(User, blank=True)
form.py :
class EditForm(forms.ModelForm):
prefix = 'edit_form'
class Meta:
model = model_A
fields = '__all__'
widgets = {'user':forms.CheckboxSelectMultiple}
html :
<div class="field">
{{form.user}}
</div>
Any help is much appreciated thanks
Change user queryset inside __init__ method of EditForm class.
class EditForm(forms.ModelForm):
prefix = 'edit_form'
class Meta:
model = model_A
fields = '__all__'
widgets = {'user':forms.CheckboxSelectMultiple}
def __init__(self, **kwargs):
self.event = kwargs.pop('event')
super().__init__(**kwargs)
# replace dots with your conditions in filter
self.fields['user'].queryset = self.user.filter(...)
UPDATE
List users that are associated with Model_A
self.fields['user'].queryset = self.user.all()

Django form performance

I asked this in Code Review but it was rejected with a cause of "broken code." That is why I'm asking it here. This site is probably more appropriate for this question than the Code Review one.
In my app, a user can modify a course that they created. One field is a "teacher" field and the user can select a different person to be the teacher. This ForeignKey creates 138 duplicated queries and I can't figure out how to make it more efficient.
Model:
class CourseCatalog(models.Model):
course_name = models.CharField(verbose_name="Course name", max_length=50)
course_desc = models.TextField(verbose_name="Course Description")
teacher = models.ForeignKey(Teacher, blank=True, null=True,
verbose_name='Course Owner', on_delete=models.PROTECT)
...
View:
class EditCourseCatalog(UpdateView):
model = CourseCatalog
fields = ['course_name','course_desc', 'teacher']
template_name = 'school/course_catalog/new_edit_form.html'
Template:
...
<h3>Course Form</h3>
{{ user.teacher }}
<form action="" method="post">{% csrf_token %}
{{form|crispy}}
...
Here is the query from debug that is duplicated 138 times. The only difference between the queries is the school_familymember.id = 220.
SELECT `school_familymember`.`id`, `school_familymember`.`password`,
school_familymember.last_login, school_familymember.is_superuser,
school_familymember.username, school_familymember.first_name,
school_familymember.last_name, school_familymember.email.school_familymember.is_staff, school_familymember.is_active, school_familymember.date_joined, school_familymember.family_id, school_familymember.middle_name, school_familymember.family_member_role_id, school_familymember.address1, school_familymember.address2, school_familymember.city, school_familymember.state, school_familymember.zip_code, school_familymember.notes, school_familymember.gender, school_familymember.phone_number, school_familymember.cell_phone_number FROM school_familymember WHERE school_familymember.id = 220
The Teacher model is also a foreign key to the FamilyMember table and this is where I think I'm having the issue. I'm wondering if there is a way to make one single query to collect the family names and ids and then use that for the drop down list in the form. Can I do this with the built in form managers or do I have to scrap that and create the queries in the view and pass them to the form?
class Teacher(models.Model):
family_member = models.OneToOneField(FamilyMember, verbose_name='name')
notes = models.TextField(blank=True)
Create a custom model form, and in the __init__ method change the teachers queryset to use select_related to be more efficient.
class CourseCatalogForm(forms.ModelForm):
class Meta:
fields = ['course_name','course_desc', 'teacher']
def __init__(self, *args, **kwargs):
super(CourseCatalogForm, self).__init__(*args, **kwargs)
self.fields['teacher'].queryset = self.fields['teacher'].queryset.select_related('family_member')
Then use your new model form class in your view instead of specifying fields.
class EditCourseCatalog(UpdateView):
model = CourseCatalog
template_name = 'school/course_catalog/new_edit_form.html'
form_class = CourseCatalogForm

How to specify an association relation using declarative base

I have been trying to create an association relation between two tables, intake and module . Each intake has a one-to-many relationship with the modules.
However there is a coursework assigned to each module, and each coursework has a duedate which is unique to each intake.
I tried this but it didnt work:
intake_modules_table = Table('tg_intakemodules',metadata,
Column('intake_id',Integer,ForeignKey('tg_intake.intake_id',
onupdate="CASCADE",ondelete="CASCADE")),
Column('module_id',Integer,ForeignKey('tg_module.module_id',
onupdate ="CASCADE",ondelete="CASCADE")),
Column('dueddate', Unicode(16))
)
class Intake(DeclarativeBase):
__tablename__ = 'tg_intake'
#{ Columns
intake_id = Column(Integer, autoincrement=True, primary_key=True)
code = Column(Unicode(16))
commencement = Column(DateTime)
completion = Column(DateTime)
#{ Special methods
def __repr__(self):
return '"%s"' %self.code
def __unicode__(self):
return self.code
#}
class Module(DeclarativeBase):
__tablename__ ='tg_module'
#{ Columns
module_id = Column(Integer, autoincrement=True, primary_key=True)
code = Column(Unicode(16))
title = Column(Unicode(30))
#{ relations
intakes = relation('Intake',
secondary=intake_modules_table, backref='modules')
#{ Special methods
def __repr__(self):
return '"%s"'%self.title
def __unicode__(self):
return '"%s"'%self.title
#}
When I do this the column duedate specified in the intake_module_table is not created.
Please some help will be appreciated here.
thanks in advance
Actually column duedate is created, but you don't get it as some model attribute when querying your models. I you need to define intermediate model for intake_modules_table table and setup relation to it instead of Intake. Sure, the access to columns of relation will be a bit longer (module.infakes[0].duedate, module.infakes[0].infake.code). Also you can setup association proxy to access list of Infake objects the same way you do now.