I am using a Django model to represent day-hour combinations. The goal is to render a matrix-like form with the days on the x-axis and the hours on the y-axis. The user can check each combination to define when a vehicle is available during a week.
The model looks as follows:
class TimeMatrix(models.Model):
MO00 = models.BooleanField(default=False)
MO01 = models.BooleanField(default=False)
MO02 = models.BooleanField(default=False)
MO03 = models.BooleanField(default=False)
....
SO22 = models.BooleanField(default=False)
SO23 = models.BooleanField(default=False)
I like to render the corresponding form coming from the CreateView as the mentioned matrix. The html to do this requires a list of days = ['MON', 'TUE', ..., 'SUN'] and hours = ['00', '01', ..., '23'] in order to render the form dynamically. The following html shows this without using the form the Django CreateView provides:
<form action="#">
<div class="table-responsive">
<table class="table">
<thead class="thead-light">
<tr>
<th scope="col">Day</th>
{% for h in hours %}
<th scope="col">{{h}}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for d in days %}
<tr>
<th scope="row" class="wt-col">{{d}}</th>
{% for h in hours %}
<td><input type="checkbox" name="{{d}}{{h}}" value="{{d}}{{h}}" id="id_{{d}}{{h}}"></td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</form>
Since I like to use the security measures build into Django forms I like this to make use of the form the CreateView provides. Following this explanation, the individual form can be accessed using form.<field_name>. Combining this with the html would require a dynamic way to access the form fields, which for me raises two questions:
Following this advice I was able to implement getattr functionality for the templates which works with my models, but fails on the form the CreateView provides (e.g. {{form|getattribute:'MON00'}}). What am I missing?
Since I cannot concat the day and hour string in the template ({{form|getattribute:d+h}} will not work), what is a suitable way to access the required form field?
Related
So I have a django DetailView that I can easily render by getting all the data that I need from get_context_data in my class based view. But the problem is that each time to render this template I would need to choose a date in this template, get the date somehow and then re-render that same template from the date picked.
I've been googling how to make this happen, there are something I could maybe do with AJAX, but maybe there is something easier to try, because I have little to no experience with AJAX/JS stuff
class PlaceDetailView(LoginRequiredMixin, PermissionCheckMixin, PlaceViewMixin, DetailView):
template_name = "places/place_detail.html"
def get_context_data(self, **kwargs):
context = super(PlaceDetailView, self).get_context_data(**kwargs)
place = context.get("object")
contract = Contract.objects.filter(pk=place.id).first()
context["renter"] = User.objects.filter(pk=contract.renter_id).first()
now = timezone.now()
meters = MeterInstallation.objects.filter(places=place.id)
context["active_meters"] = meters.filter(active_until__gte=now)
context["old_meters"] = meters.filter(active_until__lt=now)
context["services"] = ServiceTask.objects.filter(place=place)
# Need to add more context values from more models, but the date has to be given, how?
return context
place_detail_view = PlaceDetailView.as_view()
<div class="tab-pane fade show active" id="values" role="tabpanel" aria-labelledby="values-tab">
{% if values %}
<div class="table-responsive-sm">
<table class="table small">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Values</th>
</tr>
</thead>
<tbody>
{% for value in values %}
<tr>
<th scope="row">{{ forloop.counter }}</th>
<!-- todo add needed values (type, values from/to, diff, tariff, total_price) -->
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
No values.
{% endif %}
</div>
I would like to know is there an option to re-render this template when a date is being picked? Or maybe there is a better option to make this happen?:)
I'm trying to learn Django and web development aspects and have set myself a challenge of writing some 3rd party tools for the popular action RPG, Path of Exile.
A key feature of any ARPG is collecting loot items, which may have any number of 'stats', these are represented in the model as a ManyToManyField. I'd like to list a group of items and their stats in table. I know how to do this with HTML tags in the relevant template.html but would like to use django_tables2 if possible, to reduce repetition etc.
I've played around a bit and read the documentation and the tables.html template but can't see an obvious way of doing this or find any other posts etc, I'd be grateful for any help or a nudge in the right direction.
Here is a mockup of what I'd like the table to look like I'm not too bothered about having cell dividers or not but would like to be able to sort the columns of these many to many aspects.
modely.py
class Stats(models.Model):
name = models.ForeignKey(StatNames, models.DO_NOTHING)
min_value = models.IntegerField()
max_value = models.IntegerField()
class ItemName(models.Model):
name = models.CharField(unique=True, max_length=50)
i_level = models.SmallIntegerField()
min_dmg = models.SmallIntegerField(blank=True, null=True)
max_dmg = models.SmallIntegerField(blank=True, null=True)
stats = models.ManyToManyField(Stats)
tables.py
class ItemTable(tables.Table):
class Meta:
model = poe.models.ItemName
print("ItemName.type", poe.models.ItemName.type)
fields = (
'name',
'i_level',
'stat_name',
'min_value',
'max_value',
)
Here's an example of the html approach I tried out, the variable names are a little different from above but it demonstrates what I had in mind.
<table>
<thead>
<tr>
<th>Name</th>
<th>Something</th>
<th>Something Else</th>
<th colspan='3'>Stats!</th>
</tr>
</thead>
<tbody>
{% for obj in object_list %}
{% with obj.stats.count|default:1 as rowspan %}
<tr>
<td rowspan='{{rowspan}}'>{{obj.name}}</td>
<td rowspan='{{rowspan}}'>{{obj.something}}</td>
<td rowspan='{{rowspan}}'>{{obj.something_else}}</td>
{% for stat in obj.stats.all %}
<td>{{stat.name}}</td>
<td>{{stat.min_value}}</td>
<td>{{stat.max_value}}</td>
{% empty %}
<td colspan='3'>No stats</td>
{% endfor %}
</tr>
{% endwith %}
{% endfor %}
</tbody>
</table>
I hope someone can give me a little help on how to do the following with Django (excuse me if I don't explain everything correct, still new to Django and don't know about a lot of things) :
I have a table of Movies, those Movies have a "Description" Datafield, where when they click on it a form opens up with the current description of the movie. If they double click on this description they are allowed to change it and then save the value. I've made a small gif to visualize the idea:
At least thats the basic Idea behind this, so far I've managed to make most of the things run, but sadly not the Django part where the "new" data from the user is send to the Databank and replaces the old data of the Description.
So could someone explain to me how I can make that work? I know that I'd probably have to write a function to my views.py and then create a new url pattern, but I just can't figure out how exactly. So any help is welcome! Below is my code (I hope I've included every file you guys need):
views.py
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views import generic
from django.views.generic.list import ListView
from .models import *
class AllMovies(generic.ListView):
model = Movie
template_name = "consilium/index.html"
context_object_name = "latest_movie_list"
class MovieDetails(generic.DetailView):
model = Movie
template_name = "consilium/detail.html"
urls.py
from django.conf.urls import url
from . import views
from .models import *
from django.views.generic.list import ListView
app_name = "consilium"
urlpatterns = [
url(r'^$', views.AllMovies.as_view(), name="index"),
url(r'^(?P<slug>[\w_0-9]+)/$', views.MovieDetails.as_view(), name='detail'),
]
models.py
from django.db import models
from decimal import Decimal
from django import forms
from django.contrib import admin
class Movie(models.Model):
// removed the other models for better overview
description = models.TextField('Movie Description')
def __str__(self):
return self.title
index.html
{% extends "consilium/base.html" %}
{% block body %}
<table class="table">
<thead>
<tr>
<th></th>
<th colspan="2">My Movielist</th>
<th>
</tr>
<tr>
<th></th>
<th>TITLE</th>
<th>GENRE</th>
<th>RELEASE DATE</th>
<th>DIRECTOR</th>
<th>DESCRIPTION</th>
<th>RUNTIME</th>
<th>STATUS</th>
<th>IMDB</th>
</tr>
</thead>
<tbody>
{% if latest_movie_list %}
{% for movie in latest_movie_list %}
<tr>
<td></td>
<td>
<a href="{% url 'consilium:detail' movie.slug %}" data-toggle="popover" data-placement="left" data-content='<img class="title-image" src="{{movie.image.url}}"/>'>{{ movie.title }}</a>
</td>
<td>{{ movie.get_genre_display}}</td>
<td>{{ movie.date}}</td>
<td>{{ movie.director}}</td>
<td id="icn-change" data-toggle="collapse" data-target=".demo{{ forloop.counter }}">
Description <i class="fa fa-caret-right"></i>
</td>
<td>{{ movie.runtime}} min</td>
<td>{{ movie.get_status_display}}</td>
<td>{{ movie.imdb}}</td>
</tr>
<tr>
<td></td>
<td class="hiddenRow" colspan="8">
<div class="container collapse demo{{ forloop.counter }}">
<div class="row justify-content-center">
<div class="col">
<form method="post" id="usrform">{% csrf_token %}
<textarea id="text" class ="form-control" readonly="true" onkeydown="expandtext(this)" ondblclick="this.readOnly='';">{{movie.description}}</textarea>
</form>
</div>
</div>
<div class="row justify-content-center">
<div class="col align-self-start">Double Click to Edit</div>
<div class="col align-self-end">
<input type="submit" id="set" class="pull-right"/>
</div>
</div>
</div>
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td>No Movies are available.</td>
</tr>
{% endif %}
</tbody>
</table>
{% endblock %}
script.js
// removed all other code for overview
// replace description text with user input
$('#set').click(function() {
var test = $('#text').val();
localStorage.setItem("test", test);
});
$('#text').text(localStorage.getItem("test"));
I hope I didn't miss anything, thanks for everyone who can help me!
I worked on a similar project, and here is what I did.
from django.forms.models import model_to_dict
#login_required
def edit_profile(request):
profile, created = ClientProfile.objects.get_or_create(user_id=request.user.id)
if request.method == 'POST':
form = ProfileSubmissionForm(request.POST, instance=profile)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('jobs:list'))
else:
profile_dict = model_to_dict(profile)
form = ProfileSubmissionForm(profile_dict)
return render(request, 'jobs/profile.html', {'form': form})
Essentially, the model_to_dict renders the values stored in the database in the form. The instance=profile makes sure I'm updating the form and not creating a new object.
Figured it out thanks to the great help of the pythondev slack community!
views.py: getting the description field of my Movie Model
class MovieUpdateForm(forms.ModelForm):
class Meta:
model = Movie
fields = ['description']
reverse_lazy is important, so that when I click on my button it won't redirect me to consilium(my appname)/2/update and stays on the index site where I have my table
class MovieUpdateView(UpdateView):
model = Movie
form_class = MovieUpdateForm
success_url = reverse_lazy('consilium:index')
urls.py:
url(r'^(?P<pk>[0-9]+)/update/$', views.MovieUpdateView.as_view(), name='movie_update'),
here it was important to put this before my slug url pattern I had in my urls.py, otherwise it didn't work:
url(r'^(?P<slug>[\w_0-9]+)/$', views.MovieDetails.as_view(), name='detail'),
My form in my html: using pk=movie.pk so it will grab the correct movie and giving my textarea the name of "description" so my method knows where the data is coming from
<form action="{% url 'consilium:movie_update' pk=movie.pk %}" method="post" id="usrform">{% csrf_token %}
<textarea id="text" class ="form-control" name="description" readonly="true" onkeydown="expandtext(this)" ondblclick="this.readOnly='';">{{movie.description}}</textarea>
<input type="submit" id="set" class="pull-right"/>
</form>
I'm not sure the best way to explain it so I created an example picture and made up some data:
I looked at this post and know I need to use some forloop template stuff: Displaying a Table in Django from Database
The parts that are throwing me off are how to have a table within a table. For example, the doctor 'Bob" has 3 different patients. Bob has one row but Bob's patient column has 3 rows within it.
<table class="table table-striped table-bordered">
<thead>
<th>Name</th>
<th>Total Patient Meetings</th>
<th>Patient</th>
<th>Meetings for Patient</th>
</thread>
<tbody>
{% for doctor in query_results %}
<tr>
<td> {{ doctor.name }} </td>
<td> {{ doctor.total_meetings }}</td>
//*Would I have a nested forloop in here?*//
{% for patient in query_results2 %}
<td> {{patient.name }} </td>
<td> {{patient.meeting_number }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
I'm having trouble finding an example like this to work off of and am not sure how to approach it.
I also need those patients to link to the individual patient pages. So if I click on Bob's patient 'C755' I will be directed to that patient's page. I was thinking something like:
`<p>{{patient.name}}:</p>`
Thanks for any help. Just not sure the best way to approach this.
"A 'related manager' is a manager used in a one-to-many or many-to-many
related context."
https://docs.djangoproject.com/en/1.10/ref/models/relations/
I can't see how your relation between doctor and patient is, but supposing it is something like this:
class Patient(models.Model):
name = models.CharField(max_length=50)
class Doctor(models.Model):
patient = models.ManyToManyField(Patient, verbose_name='patients')
You can easly iterate over doctor.patient using:
{% for doctor in doctors %}
{% for patient in doctor.patients.all %}
{{ patient.name }}
{% endfor %}
{% endfor %}
If you don't have a verbose_name attribute for the relation, then instead of using doctor.patients.all you use doctor.patients_set.all.
And to the patient's page, you can use a method inside your class Patient to easly do this:
{{ patient.name }}
"with get_absolute_url on your model it can make dealing with them on a per-object basis much simpler and cleaner across your entire site"
https://godjango.com/67-understanding-get_absolute_url/
A picture is worth a thousand words. Here is what I'm trying to accomplish:
This is simple enough to do by just manually creating a table within the template like so:
<form>
<table class="table">
<thead><tr><th>{% trans 'Name' %}</th><th>{% trans 'Available Quantity' %}</th></tr></thead>
<tbody>
{% for p in products %}
<tr><td>{{p.name}}</td><td>{{p.available}}</td><td><input name="{{p.id}}" type="number" /></td></tr>
{% endfor %}
</tbody>
</table>
<form>
However, doing it this way makes it a hassle to deal with the submitted form data as well as do error validation.
I'd prefer to do it in a django form (formset seems more suitable). I've tried this approach but that doesn't make what i want any easier to accomplish.
Here's a minified version of my (relevant) models:
class Product(models.Model):
name = models.CharField("Name", max_length=50)
class OrderItem(models.Model):
product = models.ForeignKey('Product', verbose_name=_("Product"))
quantity = models.FloatField("Quantity")
Is there an elegant way to do this in django that I'm not considering?