Django: Want to display an empty field as blank rather displaying None - python

I have a template called client_details.html that displays user, note and datetime. Now sometimes, a client may not have an entry for user, note and datetime. What my program will do instead is display None if these fields are empty. I do not want the to display None. If a field has no value I don't want to see any value e.g. let it be blank if possible instead of displaying None.
views.py
#login_required
def get_client(request, client_id = 0):
client = None
try:
client = models.Client.objects.get(pk = client_id)
except:
pass
return render_to_response('client_details.html', {'client':client}, context_instance = RequestContext(request))
template
{{client.datetime}}<br/>
{{client.datetime.time}}<br/>
{{client.user}}<br/>
{{client.note}}<br/>

Use the built-in default_if_none filter.
{{ client.user|default_if_none:" " }}
{{ client.user|default_if_none:"" }}

you may use:
{% if client %} {{client.user}} {% else %} {% endif %}
Checking with an if is enough, so you may not user else block if you want...

this is such a strange problem.
I have a good idea for it. If you want to modify your field at display time than rather checking it at template , check it at your model class.
ExampleModel(models.Model):
myfield = models.CharField(blank=True, null = True)
#property
def get_myfield(self)
if self.myfield:
return self.myfield
else:
return ""
Use it in your template directly instead of field.
{{ExampleModel.get_myfield}}
you never need to change your template to change this field in future, just modify you property.

Related

How to link checkbox value to a model's attribute?

The idea is to have something like this:
template.html
{% for item in items %}
<input type="checkbox" checked= {{ item.status }}>
{% endfor %}
views.py
def index(request):
context = { 'items' : Item.objects.all() }
return render(request, 'template.html', context)
But the status by design isn't simply True or False:
models.py
class Item(models.Model):
class Status(models.TextChoices):
ON = 1
OFF = 0
status = models.IntegerField(choices=Status.choices)
# other attributes..
How will I link these two values so that they're two-way connected? (Loading template.html yields the checkbox's checked-ness based on the retrieved item.status (checked for ON, unchecked for OFF, while checking or unchecking the checkboxes will change the related item.status value?)
The only thing I've seen closest to my problem is this, but it's not the same at all. Mine is a single binary attribute but has different kinds of values.
First of all, it seems that your status should be a BooleanField... But let's assume you really need those choices.
You need to tell your form to use a CheckboxInput instead of a Select.
You need to tell the widget which value should check the widget.
You need to convert the returned boolean as an Iteam.Status attribute.
class Form(forms.ModelForm):
class Meta:
model = Item
fields = ('status',)
widgets = {
'status': forms.CheckboxInput(
check_test=lambda status: status == Item.Status.ON,
),
}
def clean_status(self):
return (
Item.Status.ON if self.cleaned_data.get('status')
else Item.Status.OFF
)
Here are the part of the doc you need:
Override default fields
CheckboxInput
Cleaning specific field

Why is the return value of a model method in Django not showing up to the template?

I have this function inside my model that is not appearing when I try to run the server. I think I am accessing the method correctly but when I tried writing print("ENTER") inside the total_balance() function, nothing showed up which makes me think that it's not even entering the method at all. Oddly, the function works if I take out the search functionality.
model.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
def total_balance():
transaction_list = Transaction.objects.filter(user=User)
total_balance_amount = 0
for transaction in transaction_list:
if transaction.category=='Income':
total_balance_amount += transaction.amount
elif transaction.category=='Expense':
total_balance_amount -= transaction.amount
return total_balance_amount
views.py
def profile(request):
if request.method == 'GET':
query = request.GET.get('q')
if query and query!="":
results = Transaction.objects.filter(Q(tag__icontains=query))
else:
results = Transaction.objects.all()
transactions = {
'transactions' : results,
}
profile = {
'profile' : Profile.objects.all()
}
return render(request, 'users/profile.html', transactions, profile)
template.py
<h5 class="card-title">Total Balance</h5>
<p class="card-text">₱{{ profile.total_balance }}</p>
Can someone please help me identify the reason this is not working and how I might be able to fix it? Thank you.
There are at least four things wrong here.
Firstly, for some reason you are passing two separate dictionaries to render. That doesn't work; you need a single dictionary with multiple entries.
context = {
'transactions' : results,
'profile' : Profile.objects.all()
}
return render(request, 'users/profile.html', context )
Secondly, profile - despite the singular name - is a queryset of all profiles. You would need to iterate through it in your template:
{% for prof in profile %}
<p class="card-text">₱{{ prof.total_balance }}</p>
{% endfor %}
Ideally, you would use a more appropriate name for the context variable, ie profiles.
Next, your total_balance method itself has two issues. Firstly, any method in Python needs to take the self parameter. And secondly, you need to use that parameter to access the value of the user field, not the class User. So:
def total_balance(self):
transaction_list = Transaction.objects.filter(user=self.user)
although note that that second line could be more easily written:
transaction_list = self.user.transaction_set.all()

validate_on_submit() fails when RadioButton choices are dynamically generated

I am creating quiz-like web application for learning languages using Flask, Jinja, WTForms, SqlAlchemy etc. Once an user completes such a language course by successfully going through all levels stored in JSON file I want the app offer him a practice mode, where the user will answer randomly selected levels.
When I run the app, I can see radio buttons generated with values from random level as I want, but when I choose any answer and submit it, form.validate_on_submit() returns False and form.errors returns {'practiceform': [u'Not a valid choice']}. When I hard-code value to currentLevel variable, it works properly.
views.py
#user_blueprint.route('/courses/<course>/quiz/practice',methods=['GET','POST'])
#login_required
def practice(course):
courseClass = class_for_name("project.models", course.capitalize())
courses = courseClass.query.filter_by(email=current_user.email).first()
maxLevel = courseClass.query.filter_by(email=current_user.email).first().get_maxLevel()
currentLevel = randint(0, maxLevel-1) # If this value is hard-coded or fetched from db, it works correctly
dic = generateQuestion(course, currentLevel)
display = dic["display"]
correct = dic["correct"]
options = dic["options"]
form = PracticeForm(request.form)
form.practiceform.choices = [(option, option) for option in options]
if form.validate_on_submit():
practiceForm = form.practiceform.data
if ((practiceForm == correct) and courses):
# Do something
flash("Nice job", 'success')
return redirect(url_for('user.practice', course=course))
else:
# Do something else
flash("Wrong answer", 'danger')
return redirect(url_for('user.practice', course=course))
return render_template('courses/practice.html', form=form, display=display)
forms.py
class PracticeForm(Form):
practiceform = RadioField('practice')
practice.html
{% extends "_base.html" %}
{% block content %}
<form action='' method='POST' role='form'>
<p>
<!-- Tried put form.csrf, form.csrf_token, form.hidden_tag() here -->
{{ form.practiceform() }}
</p>
<input type="submit" value="submit" />
</form>
{% endblock %}
So what am I missing there? What makes difference between lets say hardcoded level 25, which works properly or if the number 25 is randomly generated within randint?
My guess is that option is a int, bug WTForms get a str from request.form.
When data comes back from requests it is treated as a string by WTForms unless you specify a type explicitly with the coerce kwarg of the wtforms.fields.*Field constructor:
practiceform = RadioField('practice', coerce=int)
So I found that randint() caused the problem because the practice(course) method was called on both GET and POST actions which led to having two different integers -> two different forms most of the time. So I refactored the code. kept the practice(course) method for GET action and created a new method which handles POST action and this solved the problem.

django: request.POST key is empty if the choicefield value is not set

I am currently beginning web development using django. In my application, I want a form with a varied number of questions and their choices to be presented.
In models.py, a table is create to store the questions
class QuizItems(models.Model):
question = models.CharField(max_length=255)
choices = SeparatedValuesField(token="$")
answer = models.IntegerField()
In form.py, I overload the __init__ method in Form class so as to pass qchoose, a list of QuizItems instances to create the form fields.
def choiceItem(question):
return [(unicode(idx), q) for idx, q in enumerate(question.choices)]
class QuizForm(forms.Form):
def __init__(self, qchoose, *args, **kwargs):
super(QuizForm, self).__init__(*args, **kwargs)
for q in qchoose:
self.fields[str(q.id)] = forms.ChoiceField(required=True,
label=q.question, widget=forms.RadioSelect(),choices=choiceItem(q))
Then in view.py
if request.method == 'POST':
idlst = request.POST.keys()
else:
# qchoose is a list of quizitems
form = QuizForm(qchoose)
In quiz.html
{% for field in form %}
<li><b> {{ field.label }} </b></li>
<ul> {{ field }} </ul>
{% endfor %}
I want to get idlst, the list of question id, that I can get the correct answers from. It works fine when all the choicefields are filled. The problem is if there is any choicefield value is empty, I won't get its key. I think since the request.POST is a dictionary, it is supposed to return all the keys even if its value is empty.
Could anyone help me what is wrong with my code or anything missing? Thank you!
You're supposed to use the form on POST as well, then call is_valid() and access the form's cleaned_data dict.

Django database inquiries. Finding duplicates in the database and stopping them from being submitted

I'm trying to go inside of my database and see if a certain submission has been submitted before and if it has stop it from being submitted again. Currently I have this bit of code testing each field of the form (obviously changes per field but i thought I'd only show one field for simplicity)
if request.method == 'POST':
Cashtexts.objects.filter(cashTexts=request.POST['cashTexts']).exists() == False:
Then if it does not exist it goes on and save the submissions into the database. If it returns true it goes to an else statement that tells the user that what they entered has already been entered. previously this type of thing worked but I changed some variable names and now it stopped working. I've been browsing the code over a few time so I thought maybe something was fundamentally wrong with this type of filter but it makes sense in my head.
def submit_win(request):
if request.method == 'POST':
if Cashtexts.objects.filter(cashTexts=request.POST['cashTexts']).exists() or Cashtexts.objects.filter(superPoints=request.POST['superPoints']).exists() or Cashtexts.objects.filter(varolo= request.POST['varolo']).exists() or Cashtexts.objects.filter(swagbucks = request.POST['swagbucks']).exists() or Cashtexts.objects.filter(neobux = request.POST['neobux']).exists() or Cashtexts.objects.filter(topline=request.POST['topline']).exists() or Cashtexts.objects.filter(Paidviewpoint=request.POST['Paidviewpoint']).exists() or Cashtexts.objects.filter(cashcrate=request.POST['cashcrate']).exists() == False:
form = CashtextsForm(request.POST)
if form.is_valid():
form.save()
ref_create = Cashtexts.objects.filter(cashTexts=request.POST['cashTexts'])
return render_to_response('submitted_page.html', {'ref_create': ref_create})
else: #Error message reading wither you didnt insert codes or you enter the same code twice
error = 'That code has already been submitted'
ref_create = CashtextsForm()
return render_to_response('submit.html', {'ref_create': ref_create,'error':error}, context_instance=RequestContext(request))
else: #displays the page when the user asks to go to the submit page
ref_create = CashtextsForm()
return render_to_response('submit.html', {'ref_create': ref_create}, context_instance=RequestContext(request))
Also, I turned Cashtexts.objects.filter(cashTexts=request.POST['cashTexts']) intoa variable and passed it to my template to see what it was returning and it was returning objects that should have told the statement True. but it just seemed to ignore them and submit them anyway.
I suppose i could delete all the previous objects that match the thing they entered upon submission but that makes it less secure and could lead to users submitting over and over again thinking that they are getting it more in there. I'd rather just stop it before it happens.
You can just set the definition of your cashTexts field to unique in the models definition:
def Cashtexts(models.Model):
name = CharField(max_length=50, unique = True)
Just set the "unique" argument to true for each field you want to be unique and you're done. The way Django's forms API is working, the form fields will take over all the necessary error handling.
With the model fields set to unique where necessary you can have this much easier:
def view(request):
if request.method == 'POST':
form = CashtextsForm(request.POST)
""" the next line is going to check uniqueness for each
of the models fields where you have set unique = True
If the field is not unique, it s field will have an
attribute error, which you can then render to the template """
if form.is_valid():
form.save()
else:
form = CashtextsForm()
context = RequestContext(request)
# now i pass the form to the template as 'ref_create'
context.update( {'ref_create':form} )
return render_to_response('submit.html',context)
Then you simply render that form in your template (either with form.as_p(), form.as_table() or with some custom code like this):
{% for field in ref_create %}
{{ field.label_tag }}
{{ field }}
{{ field.errors }}
{% endfor %}
Each field, set to unique in the model definition, which which would not be unique in the database any more if your form is saved, will now have an error message saying something like "A Cashtext with this name allready exists".
Customizing you error messages can be done in two ways: 1: customize the forms (i do not recommend that, until you have better understandings of how Django works) 2: instead of {{ field.errors }} write something like this:
{% if field.errors %}
The Cashtext field {{field.name}} value should be unique.
{% endif %}

Categories