Good day.
The challenge is:
Create a form that will change the parameters of the model fields, based on user input.
My logic is this. I tried to create a form for entering changes:
In the lists , I recorded all the ID and field names of the model;
class RefDataForm(forms.Form):
NODE_ID_LIST=[('YE102_4G','YE102_4G'),('AG001_4G','AG001_4G')]
ANRFUNC_PARAM_LIST=[('zzztemporary7','zzztemporary7'),('zzztemporary2','zzztemporary2')]
change_id = forms.CharField(label='Node ID for Change', widget=forms.Select(choices=NODE_ID_LIST))
change_param_name = forms.CharField(label='Parameter name for Change', widget=forms.Select(choices=ANRFUNC_PARAM_LIST))
value = forms.CharField(label='Value')
Next in view.py, I'm trying to create a .update command that should accept changes.
def ref_test(request, template_name ='ref_test.html'):
if request.method == 'POST':
test=RefDataForm(request.POST)
if test.is_valid():
change_id = request.POST['change_id']
change_param_name = request.POST['change_param_name']
change_value = request.POST['value']
update_form = Ran4GRfAnrfunction.objects.filter(pk__in=change_id).update(change_param_name=change_value)
else:
test=RefDataForm()
return render(request, template_name, {'test':test})
My html is :
<form method="post">
{% csrf_token %}
{{ test.change_id }}
{{ test.change_param_name }}
{{ test.value }}
<button type="submit">Search</button>
</form>
However, I get an error
*Ran4GRfAnrfunction has no field named 'change_param_name' *
How do I pass field_name through a form?
In manage.py shell, I tried to do it - and its work.
from dumper.models import *
change_id = ['AG001_4G', 'AG002_4G']
change_value = ('Okay')
change_param_name = ('zzztemporary2')
Ran4GRfAnrfunction.objects.filter (pk__in = change_id) .update (zzztemporary2 = change_value)
How do I pass the value of change_param_name to .update ?
Maybe you've already figured this out since the questions been here for five hours at this point.
I can't exactly test this, but it looks like your problem is right here. This line is telling it to change the change_param_name field - not to change the field matching the name stored in change_param_name.
.update(change_param_name=change_value)
You should be able to fix this by putting the values into a dictionary and unpacking it.
.update(**{change_param_name: change_value})
Related
Most of the info I find online is for multiple checkboxes. I just want 1.
I have:
class CategoryForm(FlaskForm):
category = StringField('category',validators=[DataRequired()])
checkbox = BooleanField('Private?')
#app.route('/category/<categoryid>',methods=('GET','POST'))
def category(categoryid):
category = Category.query.get(categoryid)
if request.method == 'POST':
if request.form.get('category'):
category.name = request.form['category']
category.private = request.form['private']
db.session.add(category)
db.session.commit()
return redirect(url_for('index'))
c_form = CategoryForm()
c_form.category.data = category.name
return render_template('category.html',form =c_form,category=category)
And my 'category' template:
<form method="post">
{{ form.hidden_tag() }}
{{ form.checkbox }}
<button type="submit">Go!</button>
</form>
right now my browser renders this:
<peewee.BooleanField object at 0x105122ad0> Go!
Obviously I would like it to render the checkbox instead. How can I do this? Do I need a widget ?
I'm having the impression that you're using the fields from peewee as the fields in your form, that isn't going to work. The most likely case is that you're importing both and one import is overwriting the other.
If you need to have both the model and the form in the same file, use aliases.
from peewee import BooleanField as PeeBool
from wtforms import BooleanField as WTBool
I'm a django newbie so a verbose answer will be greatly appreciated. I'm enforcing a capacity limit on any newly created Bottle objects in my model, like so:
class Bottle(models.Model):
name = models.CharField(max_length=150, blank=False, default="")
brand = models.ForeignKey(Brand, on_delete=models.CASCADE, related_name="bottles")
vintage = models.IntegerField('vintage', choices=YEAR_CHOICES, default=datetime.datetime.now().year)
capacity = models.IntegerField(default=750,
validators=[MaxValueValidator(2000, message="Must be less than 2000")
,MinValueValidator(50, message="Must be more than 50")])
My BottleForm looks like so:
class BottleForm(ModelForm):
class Meta:
model = Bottle
fields = '__all__'
My view (with form validation logic based on this answer):
def index(request):
args = {}
user = request.user
object = Bottle.objects.filter(brand__business__owner_id=user.id).all(). \
values('brand__name', 'name', 'capacity', 'vintage').annotate(Count('brand')).order_by('brand__count')
args['object'] = object
if request.method == "POST":
form = BottleForm(request.POST)
if form.is_valid():
bottle = form.save(commit=False)
bottle.save()
return redirect('index')
else:
form = BottleForm()
args['form'] = form
return render(request, template_name="index.pug", context=args)
And my template (in pug format), like so:
form(class="form-horizontal")(method="post" action=".")
| {% csrf_token %}
for field in da_form
div(class="form-group")
label(class="col-lg-3 col-md-3 col-sm-3 control-label") {{field.label_tag}}
div(class="col-lg-9 col-md-9 col-sm-9")
| {{ field|add_class:"form-control" }}
input(class="btn btn-primary")(type="submit" value="submit")
After a few hours of messing with my code and browsing SO, I managed to display the error by adding {{ form.errors }} to my template, but that only shows after the page has already been reloaded and in a very ugly form: see here.
What I'd like is to utilize django's built-in popover error messages without reloading page (see example on default non-empty field), which is so much better from a UX standpoint.
That is not a Django message. That is an HTML5 validation message, which is enforced directly by your browser. Django simply outputs the input field as type number with a max attribute:
<input type="number" name="capacity" max="750">
I'm not sure if your (horrible) pug templating thing is getting in the way, or whether it's just that Django doesn't pass on these arguments when you use validators. You may need to redefine the field in the form, specifying the max and min values:
class BottleForm(ModelForm):
capacity = forms.IntegerField(initial=750, max_value=2000, min_value=250)
(Note, doing {{ field.errors }} alongside each field gives a much better display than just doing {{ form.errors }} at the top, anyway.)
Here's the goal: when the user submits the form, use one view to send the submitted data to the database, then redirect back to the form, but with the data pre-populated. This is mostly working, but something about my implementation is wrapping extra quotes around the string. For now, I'm just using a super-simple form, btw. I enter Billy, and the pre-pop is: "Billy", if I click submit again, it comes back as: "\"Billy\"", then "\"\\\"Billy\\\"\"", and so on (as far as I have tested, anyways.
relevant views are:
def editUsers(request):
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = usersForm(request.POST)
# check whether it's valid:
# process the data in form.cleaned_data as required
# redirect to a new URL:
name = json.dumps(form.data['user_name'])
request.session['editUserName'] = name
# call out to limboLogic.py to update values
test = name
return redirect('../users')
# if a GET (or any other method) we'll create a blank form
else:
return redirect('../users')
from .forms import *
def users(request):
form = None
if 'editUserName' not in request.session:
# create a blank form
form = usersForm()
else:
# form = equipmentForm(initial='jim') - used to make sure I was branching the if/else correctly
form = usersForm(initial={'user_name':request.session['editUserName']}, auto_id=False) #limboLogic.GetUserInfo(name))
return render(request, 'limboHtml/UserManagement.html', {'form': form})
form is simply:
class usersForm(forms.Form):
user_name = forms.CharField(label='New User\'s name', max_length=100)
and the template is:
{% extends "base.html" %}
{% block content %}
<div class="row">
<p>This is the user management page</p><br>
<form action="/edit/users.html" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="OK">
</form>
<br><p class="bold">This is below the form</p>
</div>
{% endblock %}
thoughts?
I can't quite say what the intracies are here, but the problem involves the fact that I was using a json class. I used this site as a guide and managed to fix the problem. note that the key aspect is inside the second if:
name = form.cleaned_data['user_name'] works fine,
name = json.dumps(form.data['user_name']) does not
the whole function as it now stands:
def editUsers(request):
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = usersForm(request.POST)
# check whether it's valid:
# process the data in form.cleaned_data as required
# redirect to a new URL:
if form.is_valid():
name = form.cleaned_data['user_name']
# name = json.dumps(form.data['user_name'])
request.session['editUserName'] = name
# call out to limboLogic.py to update values
test = name
return redirect('../users')
# if a GET (or any other method) we'll create a blank form
return redirect('../users')
I'm trying to let the user select one 'thing' from a list (from the database), then go find other stuff in the database using that record. But I cannot get the selection info from the selection page.
I'll try to make this a pretty complete snapshot of the relevant code, but I may remove too much or leave too much in, sorry.
my models.py:
urlpatterns = patterns('',
url(r'^$', 'dblook.views.index', name='home'),
url(r'^dblook3/', 'dblook.views.try3', name='home2'),
url(r'^dblook4/', 'dblook.views.try4', name='home3'),
)
my dblook/models.py:
from django.db import models
class serial_number(models.Model):
def __unicode__(self):
return self.serialno
#return self.question
class Meta:
managed=False
db_table='serial_number'
sn_id = models.AutoField(primary_key=True)
serialno = models.CharField(max_length=128)
comment = models.ForeignKey(comment,null=True,db_column='comment')
my views.py (I will skip all the imports other than the database model import. If anyone really wants them I'll update with them)
from dblook.models import *
class SerialnoSelectForm(forms.Form):
serialno = forms.CharField(max_length=16)
selected = forms.BooleanField()
class serialform(ModelForm):
class Meta:
model = serial_number
exclude=('comment','sn_id')
selected = forms.BooleanField()
class snselect(forms.Form):
sno = forms.ChoiceField()
def try3(request):
if ( request.POST ):
output = "HEllo world, thanks for posting"
return HttpResponse(output)
else:
sslst = snselect(serial_number.objects.filter(serialno__startswith="A128").order_by('-serialno'))
t = loader.get_template('select_serialno.html')
c = Context({
'sslst': sslst,
})
c.update(csrf(request))
return HttpResponse(t.render(c))
def try4(request,dsn):
if ( request.POST ):
output = "HEllo world, thanks for posting to 4"
return HttpResponse(output)
else:
return HttpResponse("Error")
And my template (select_serialno.html) is:
<h1>Select a serial number</h1>
<ul>
<form method='post' action'='/dbtest4/{{serial_number.sn_id}}/showme'>
{% csrf_token %}
{% for sn in sslst %}
<input type="submit" name="sn.serialno" id="choice{{ forloop.counter }}" value="{{choice.id}}"/>
<label for="choice{{ forloop.counter }}">{{ sn.serialno }}</label><br/>
{% endfor %}
<input type="submit" value="data" />
</form>
When I go to dblook3, I get a nice list from the database of serial numbers, along with a button that, if I hit goes immediately to the dblook4 URL (in this case, its ALWAYS '/dbtest4//showme/' instead of something like '/dbtest4/3/showme/). Unfortunately, I cannot seem to have any way to tell what button they hit.
No matter WHAT I put in for the 'stuff' in <form method='post' action'='/dbtest/{{stuff}}/showme'>, it is always empty.
I also tried things like if( 'choice' in request.POST ): in try4 in veiws.py, but that didn't work either.
So, how do I get ANY information about what was selected from 'look3' over to 'look4'? I'll take just about anything... However, if you can explain why I'm doing that hopefully your answer will not only solve my problem, but help others understand...
(if the above looks pretty 'evolutionary' that's because I've been hacking on this for 3 days now...)
Thanks!
You need to POST the information to the look4 dblook form:
<form method='post' action'='{% url dblook.views.try4 %}'>
At the moment you have /dbtest/{{serial_number.sn_id}}/showme which doesn't make any sense. You don't have a serial_number variable in your context so I don't know where that comes from. You have def try4(request,dsn): as your view definition which suggests that you are trying to load information on the try4 view depending on what was selected fromt he try3 view (although I am guessing this as you haven't explained what you are trying to do). If that is the case, you need to do that based on the data passed via POST instead of url parameters. Something very vaguely like the following:
def try4(request):
if request.method == "POST":
form = snselect(request.POST)
if form.is_valid():
data = form.cleaned_data
# Get the selected item from your choice field and retrieve the
# corresonding model object with that id
...
I'm new to Django and I'm creating an app to create and display employee data for my company.
Currently the model, new employee form, employee table display, login/logout, all works. I am working on editing the current listings.
I have hover on row links to pass the pk (employeeid) over the url and the form is populating correctly- except the manytomanyfields are not populating, and the pk is incrementing, resulting in a duplicate entry (other than any data changes made).
I will only put in sample of the code because the model/form has 35 total fields which makes for very long code the way i did the form fields manually (to achieve a prettier format).
#view.py #SEE EDIT BELOW FOR CORRECT METHOD
#login_required
def employee_details(request, empid): #empid passed through URL/link
obj_list = Employee.objects.all()
e = Employee.objects.filter(pk=int(empid)).values()[0]
form = EmployeeForm(e)
context_instance=RequestContext(request) #I seem to always need this for {%extend "base.html" %} to work correctly
return render_to_response('employee_create.html', locals(), context_instance,)
#URLconf
(r'^employee/(?P<empid>\d+)/$', employee_details),
# snippets of employee_create.html. The same template used for create and update/edit, may be a source of problems, they do have different views- just render to same template to stay DRY, but could add an additional layer of extend for differences needed between the new and edit requests EDIT: added a 3rd layer of templates to solve this "problem". not shown in code here- easy enough to add another child template
{% extends "base.html" %}
{% block title %}New Entry{% endblock %}
{% block content %}
<div id="employeeform">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<form action="/newemp/" method="post" class="employeeform">{% csrf_token %} #SEE EDIT
<div class="left_field">
{{ form.employeeid.value }}
{{ form.currentemployee.errors }}
<label for="currentemployee" >Current Employee?</label>
{{ form.currentemployee }}<br/><br/>
{{ form.employer.errors }}
<label for="employer" class="fixedwidth">Employer:</label>
{{ form.employer }}<br/>
{{ form.last_name.errors }}
<label for="last_name" class="fixedwidth">Last Name:</label>
{{ form.last_name }}<br/>
{{ form.facility.errors }} #ManyToMany
<label for="facility" class="fixedwidth">Facility:</label>
{{ form.facility }}<br/><br/>
</div>
<div id="submit"><br/>
<input type="submit" value="Submit">
</div>
</form>
#models.py
class Employee(models.Model):
employeeid = models.AutoField(primary_key=True, verbose_name='Employee ID #')
currentemployee = models.BooleanField(null=False, blank=True, verbose_name='Current Employee?')
employer = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
facility = models.ForeignKey(Facility, null=True, blank=True)
base.html just has a header on top, a menu on the left and a big empty div where the forms, employee tables, etc all extend into.
screenshot2
So, how do I need to change my view and/or the in the template to update an entry, rather than creating a new one? (
And how do I populate the correct foriegnkeys? (the drop down boxes have the right options available, but the "-----" is selected even though the original database entry contains the right information.
Let me know if i need to include some more files/code
I have more pics too but i cant link more or insert them as a new user :< I'll just have to contribute and help out other people! :D
EDIT:
I've been working on this more and haven't gotten too far. I still can't get the drop-down fields to select the values saved in the database (SQLite3).
But the main issue I'm trying to figure out is how to save as an update, rather than a new entry. save(force_update=True) is not working with the default ModelForm save parameters.
views.py
def employee_details(request, empid):
context_instance=RequestContext(request)
obj_list = Employee.objects.all()
if request.method == 'POST':
e = Employee.objects.get(pk=int(empid))
form = EmployeeForm(request.POST, instance=e)
if form.is_valid():
form.save()
return HttpResponseRedirect('/emp_submited/')
else:
e = Employee.objects.get(pk=int(empid))
form = EmployeeForm(instance=e)
return render_to_response('employee_details.html', {'form': form}, context_instance,)
also changed template form action to "" (from /newemp/ which was the correct location for my new employee tempalte, but not the update.
Thanks to this similar question.
updating a form in djnago is simple:
steps:
1. extract the previous data of the form and populate the edit form with this these details to show to user
2. get the new data from the edit form and store it into the database
step1:
getting the previous data
views.py
def edit_user_post(request, topic_id):
if request.method == 'POST':
form = UserPostForm(request.POST)
if form.is_valid():
#let user here be foreign key for the PostTopicModel
user = User.objects.get(username = request.user.username)
#now set the user for the form like: user = user
#get the other form values and post them
#eg:topic_heading = form.cleaned_data('topic_heading')
#save the details into db
#redirect
else:
#get the current post details
post_details = UserPostModel.objcets.get(id = topic_id)
data = {'topic_heading':topic.topic_heading,'topic_detail':topic.topic_detail,'topic_link':topic.topic_link,'tags':topic.tags}
#populate the edit form with previous details:
form = UserPostForm(initial = data)
return render(request,'link_to_template',{'form':form})