Update several records at once using Django - python

I want to know a way on how to update the data once is edited from the input boxes all with one click. I found this post on how to do it with checkboxes:
Updating several records at once using Django
but I'm not sure how to do it for input boxes.
here is my code:
<table class="table table-striped table-bordered table-hover dataTables-example" >
<thead>
<tr>
<th>Local</th>
<th>line</th>
<th>rack</th>
</tr>
</thead>
<tbody>
{% for linea in lineas_de_reporte %}
<tr>
<td>{{ linea.local }}</td>
<td><input type="text" name="case-opened" value="{{ linea.rack }}" id="caseOpened"/></td>
<td><input type="text" name="case-opened" value="{{ linea.line }}" id="caseOpened"/></td>
</tr>
{% endfor %}
</tbody>
Here is how it looks:
Is there a way bu just sending all the values (by id) to a function in a list using Django?
EDIT:
forms.py
class TVSForm(forms.Form):
rack = forms.CharField()
line = forms.CharField()
views.py
def search_folio(request):
if request.method == 'POST':
form = FolioSearchForm(request.POST)
if form.is_valid():
folio_number = request.POST.get('folio_number', '')
folio = 'FOLIO' + str(folio_number)
folio_query = InventoryFolioManagement.objects.filter(folio=folio)
context = {
'lineas_de_reporte': folio_query,
'folio': ' | ' + folio
}
return render(request, 'inv-search-folio.html', context)
else:
form = FolioSearchForm()
if request.GET.get('rack'):
# ... this means that user clicked on the submit button
# get the id of linea
linea_id = request.GET.get('rack-id')
new_case = request.GET.get('rack')
# fetch object from db, based on that id (aka pk)
linea = TechnicalValidationSystem.objects.get(id=linea_id)
# change its attribute to True
linea.case_opened = new_case
# update db with the new value
linea.save(update_fields=['rack'])
return render(request, 'inv-search-folio.html')

Related

how to instance and update multiple row in a table with Django

I have a simple table with some rows:
My goal is to instantiate the current value of the quantity and eventually save the new data for all the lines.
At the moment I have a simple view:
#login_required
def compilaDocMultiRow(request,pk):
member = get_object_or_404(testaDoc, pk=pk)
family = corpoDoc.objects.filter(doc=pk)
if request.method == "POST":
form = multiCorpoDocForm(request.POST or None)
if form.is_valid():
reg = form.save(commit=False)
reg.doc_id = member.pk
reg.save()
return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
else:
print(form.errors)
else:
form = multiCorpoDocForm()
return render(request, "compilaDocMultiRow.html", {'family':family, 'member':member, 'form':form})
Is there a way to do this using only Django?
EDIT 1
I was able to instantiate the value with widget tweaks. I am left with the problem of passing the pk of the line to the form and saving the value.
This is the html code:
{% for item in family %}
<tr>
<td>{{ item.item}}</td>
<td>{{ item.desc }}</td>
{% with field=form.qt %}
<td width="15%">{% render_field field class="form-control" placeholder=item.qt %}
</td>
{% endwith %}
<td></td>
<td></td>
</tr>
{% endfor %}

Display part of django model in html table

How to display only some columns of Django model in a HTML template?
And also: how do I perform a function on one of the records? (amount)?
Right now I'm displaying a whole table of model like that:
my models.py
class Tabela(models.Model):
block_id = models.CharField(max_length=64)
timestamp = models.DateTimeField()
type = models.CharField(max_length=32)
link = models.CharField(max_length=64)
link_as_account = models.CharField(max_length=100)
account = models.CharField(max_length=100)
amount = models.CharField(max_length=64)
def __str__(self):
return self.block_id
My views.py
def search_results(request):
model = Tabela
query_addresse = request.GET.get('addressee', None)
query_hash = request.GET.get('hash', None)
if not query_hash and not query_addresse and request.method == 'GET':
return render(request, 'nanosite/index.html', {})
if query_hash and request.method == 'GET':
if query_addresse:
result = Tabela.objects.filter(account=query_addresse, block_id=query_hash)
else:
result = Tabela.objects.filter(block_id=query_hash)
field_names = [f.name for f in model._meta.get_fields()]
data = [[getattr(ins, name) for name in field_names]
for ins in result]
elif query_addresse and request.method == 'GET':
result = Tabela.objects.filter(account=query_addresse)
field_names = [f.name for f in model._meta.get_fields()]
data = [[getattr(ins, name) for name in field_names]
for ins in result]
return render(request, 'nanosite/index.html', {'field_names': field_names, 'data': data})
My index.html
<div id="bottomhalf" class="table-responsive">
<table class="table table-sm table-dark table-hover">
<thead class="thead-light">
{% for head in field_names %}
<th scope="col">{{ head }}</th>
{% endfor %}
</thead>
<tbody>
{% for row in data %}
<tr scope="row">
{% for cell in row %}
<td>{{ cell }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
What I'd like to do is display only block_id, timestamp, account and amount in html. I've tried different approaches like using only the result part of views without field_names and data, but of course it didn't work.
My other question is, how can I modify the field amount and perform an operation on it to be displayed in template like amound divided by certain digit with a $ sign before it (for example if amount=1488 to be divided by 124 and displayed as '$12')?
Pass the queryset qs selecting the objects to display to the template and iterate over it to generate your table:
{% for obj in qs %}
<tr>
<td> {{obj.block_id}} </td>
<!-- etc ... -->
</tr>
{% endfor %}
Now, if you also want to pass a variable specifying the names of the fields of the object to tabulate, and in what order, you find out that the Django template engine is by design (!) incapable of doing that. You can either do what you are doing, and generate a list-of-rows in Python which you pass to the Template, or you need a Django custom template tag such as
#register.filter
def attr( obj, name):
return getattr( obj, name, '')
and then you can run an inner loop in your template
<tr>
{% for name in selected_field_names %}
<td> {{obj|attr:name}} </td>
{% endfor %}
</tr>
The answer to the second question, is to define a property on your model to return the field suitably transmogrified:
class Tabela(models.Model):
...
#property
def funny_amount(self):
val = self.amount/12.0
return f'$ {val:.2f}'
and refer to {{obj.funny_amount}} in your template

Get value/state of checkbox for each row in a Django when POST

I want to display a table with :
on rows: the date for each weekday (calculate in my views.py)
on columns: the Mealselection of an user.
I can get value from models and display it :
https://i.imgur.com/TyvI0DH.png
But when i look source code on the page i see https://i.imgur.com/wY0QC62l.png
So obviously it does not work when i try to save the user choice because it will update only one date, today for exemple, since there are the same form id i think.
I try with a formset but i can't pass initial value to the template "selection_template.html" (i try with the exemple below but don't work because i need to display the user selection in relation with date of weekday.
formset = ArticleFormSet(initial=[{'title': "Form %d" % (i+1),
'pub_date': datetime.date.today()} for i in range(10)])
I know how to display multi form using formset but don't know how to pass value to the template.
models.py
class MealSelection(models.Model):
user = models.ForeignKey('User', on_delete=models.CASCADE)
date = models.DateField(auto_now_add=True)
salad = models.BooleanField(default=False)
meal = models.BooleanField(default=False)
sandwich = models.BooleanField(default=False)
forms.py
class GetUserMeal(forms.ModelForm):
class Meta:
model = MealSelection
fields = ['meal', 'salad', 'sandwich']
widget = forms.CheckboxInput(
attrs={
'name': 'choices'
}
)
views.py
for day in weekDay:
try:
userSelection = MealSelection.objects.get(user=u1,date=startWeek + datetime.timedelta(days=daysCount))
userSelection = {'meal':userSelection.meal, 'salad':userSelection.salad, 'sandwich':userSelection.sandwich}
except:
userSelection = {'meal':False, 'salad':False, 'sandwich':False}
userSelection = forms.GetUserMeal(userSelection)
dateDayCorresp[day] = {'date':startWeek + datetime.timedelta(days=daysCount),'userSelection': userSelection}
daysCount += 1
selection_template.html
<form method="post">
<table class="table table-hover table-bordered vertical-align">
<thead>
<tr class="table-primary">
<th rowspan="2">Jour</th>
<th colspan="3">Repas</th>
</tr>
<tr class="table-success">
<th scope="col">Repas</th>
<th scope="col">Salade</th>
<th scope="col">Sandwich</th>
</tr>
</thead>
<tbody>
{% csrf_token %}
{% for day in dateDayCorresp.items %}
<tr>
<th scope="row" class="table-warning">
{{day.0}} ({{day.1.date}})
<!-- {{day.1.userSelection}} -->
</th>
{% for field in day.1.userSelection %}
<td>
<label>{{ field }}</label>
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<button type="submit" class="btn btn-primary btn-lg btn-block fixed-bottom" id="buttonSave">Save</button>
</form>

Loop through items into Django 1.8 template

I have this method:
def profile(request):
parsedData = []
if request.method == 'POST':
username = request.POST.get('user')
req = requests.get('https://api.github.com/users/' + username + '/repos')
jsonList = []
jsonList=req.json()
userData = {}
for data in jsonList:
userData['html_url'] = data['html_url']
userData['created_at'] = data['created_at']
userData['updated_at'] = data['updated_at']
userData['forks_count'] = data['forks_count']
parsedData.append(userData)
return render(request, 'app/profile.html', {'data': parsedData})
This code looks into an url like this githubtraining
As You can see, the response contains lots of repositories, however, not every github user has more than 1 repo.
Anyways, on my html view I have this:
<div class="table-responsive">
<table class="table table-bordered table-hover table-striped tablesorter">
<thead>
<tr>
<th class="header"> Url <i class="icon-sort"></i></th>
<th class="header"> Created at <i class="icon-sort"></i></th>
<th class="header"> Updated at <i class="icon-sort"></i></th>
<th class="header"> Forks count <i class="icon-sort"></i></th>
</tr>
</thead>
<tbody>
{% for key in data %}
<tr>
<td>{{ key.html_url }}</td>
<td>{{ key.created_at }}</td>
<td>{{ key.updated_at }}</td>
<td>{{ key.forks_count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
What happens then? Well, right now, if, for instance, I query the githubtraining user to see it's repos, it shows only the last one, on that and every other user, so, what am I doing wrong here? The loop is there, what am I missing?
You append data only after forloop is finished inside your view. You need to append it after each iteration instead:
for data in jsonList:
userData = {}
userData['html_url'] = data['html_url']
userData['created_at'] = data['created_at']
userData['updated_at'] = data['updated_at']
userData['forks_count'] = data['forks_count']
parsedData.append(userData)
With your current code:
userData = {}
for data in jsonList:
userData['html_url'] = data['html_url']
userData['created_at'] = data['created_at']
userData['updated_at'] = data['updated_at']
userData['forks_count'] = data['forks_count']
parsedData.append(userData)
new userData overrides previous one inside for cycle. And when cycle finishing you have only one record in the list.

Edit form creates new data instead

I defined a route and template to edit data. Instead, it creates new data. How do I fix this?
#home_blueprint.route('/table/<int:data_id>/edit', methods=['GET', 'POST'])
def edit(data_id):
ed_form = EditTableForm(request.form)
data_to_edit = db.session.query(Diary).filter_by(id=data_id)
if ed_form.validate_on_submit():
if ed_form.title.data:
data_to_edit.title = ed_form.title.data
if ed_form.weight.data:
data_to_edit.weight = ed_form.weight.data
if ed_form.kkal.data:
data_to_edit.kkal = ed_form.kkal.data
if ed_form.carbs.data:
data_to_edit.carbs = ed_form.carbs.data
if ed_form.proteins.data:
data_to_edit.proteins = ed_form.proteins.data
if ed_form.fats.data:
data_to_edit.fats = ed_form.fats.data
db.session.add(data_to_edit)
db.session.commit()
flash('New data was successfully posted. Thanks.')
return redirect(url_for('home.table'))
else:
return render_template('edit.html', data_to_edit=data_to_edit, ed_form=ed_form, data_id=data_id)
return render_template("edit.html", diary=diary)
<table class="table table-bordered">
<thead>
<tr>
<th>Product</th>
<th>Weith</th>
<th>Kkal</th>
<th>Protein</th>
<th>Fat</th>
<th>Carbs</th>
</tr>
</thead>
<tbody>
{% for data in data_to_edit %}
<tr>
<form class="form-message" role="form" method="post" action="/table">
{{ ed_form.csrf_token }}
<td>{{ed_form.title(placeholder=data.title)}}</td>
<td>{{ed_form.weight(placeholder=data.weight)}}</td>
<td>{{ed_form.kkal(placeholder=data.kkal)}}</td>
<td>{{ed_form.carbs(placeholder=data.carbs)}}</td>
<td>{{ed_form.proteins(placeholder=data.proteins)}}</td>
<td>{{ed_form.fats(placeholder=data.fats)}}</td>
<td><button class="btn btn-sm btn-success" type="submit">Post</button></td>
</form>
</tr>
{% endfor %}
</tbody>
</table>
Link to projects Git repository. Each users input into table has own id, I query data by id and then trying to Edit data there with no luck so far :)
UPDATE
I have changed code to:
data_to_edit = db.session.query(Diary).filter_by(id=data_id).first()
if ed_form.validate_on_submit():
if not data_to_edit:
data_to_edit = Diary(
ed_form.title.data,
ed_form.weight.data,
ed_form.kkal.data,
ed_form.carbs.data,
ed_form.proteins.data,
ed_form.fats.data,
current_user.id
)
db.session.add(data_to_edit)
db.session.commit()
But yet no luck, it doesn't change old data but ads new.
The issue is that you are adding the object again in session, thus inserting it into the database.
Sample code
data_to_edit = db.session.query(Diary).filter_by(Diary.id=data_id).first()
if not data_to_edit:
data_to_edit = Diary()
db.session.add(data_to_edit)
...
# edit properties
...
db.session.commit()
The idea is to add the new object only when it's actually new.

Categories