Trying to render attributes of objects that are linked with another object via m2m field.
#models
class Arm(models.Model):
cmrs = models.ManyToManyField(CMR, null=True)
class CMR(models.Model):
client = models.ForeignKey('Client', on_delete=models.CASCADE,
null=True, default="", blank=True)
The view
if us.groups.filter(name__in = ['prime']):
query_set = Plan.objects.order_by('-pk')
query_ys = Arm.objects.filter(date=ys)
query_rn = Arm.objects.filter(date=rn)
query_tm = Arm.objects.filter(date=tm)
client_rn = query_rn.prefetch_related('cmrs')
args = {'query_rn': query_rn,
'cl_rn': client_rn,
'query_tm': query_tm,
'query_ys': query_ys,
'query_set': query_set
}
return render(request, 'personnel/schedule/test-schedule-full.html', args)
And the template
<tbody id="add">
{% for query in query_rn %}
<tr class="row100 body {{ query.status }}" data-href="/personnel/arm/{{ query.id }}">
<td class="cell100 column1">{{ query.driver }}</td>
<td class="cell100 column2">{% for idem in cl_rn.cmrs.all %} {{ idem.client }} {% endfor %}</td>
<td class="cell100 column3">{{ query.des_from}}</td>
<td class="cell100 columnarrow"><i class="fas fa-arrow-circle-right"></i></td>
<td class="cell100 column4">{{ query.des_to }}</td>
</tr>
{% endfor %}
</tbody>
What I am trying to do is to show all the values of the client field of an CMR objects that are linked with Arm in <td class="cell100 column2"></td> but it shows nothing instead.
It doesn't make sense to have separate querysets for the prefetch_related call. You're iterating through query_rn, you need to define the prefetch_related on that same queryset and then iterate through the related objects from there; you don't need client_rn at all. So:
query_rn = Arm.objects.filter(date=rn).prefetch_related('cmrs')
...
{% for query in query_rn %}
{% for idem in query.cmrs.all %} {{ idem.client }} {% endfor %}
{% endfor %}
Note also, the first line of your code is a bit off. You shouldn't use __in with a single-list element, just check for equality; and since you just want to check that the related group exists, you should use the exists() method, which is slightly more efficient:
if us.groups.filter(name='prime').exists():
Related
I have two Django models that record time. Model one records time during the morning and Model two records time during the evening. I want to present both of these times along with the difference between the times within an HTML table but am confused about how to do it. I am new to Django and would really appreciate some advice.
This is what I have so far:
models.py:
class Alltime(models.Model):
id= models.ForeignKey(User, on_delete = models.CASCADE)
mtime = models.DateTimeField()
etime = models.DateTimeField()
views.py:
def panel(request):
time_data = User.objects.filter(pk__gt=1) #I need all data except for the default Super User account
get_time = Alltime.objects.all()
return render(request, 'users/interface.html', {'data': time_data, "get_time": get_time})
panel.html:
<form>
{% csrf_token %}
<table>
<tr>
<th>Name</th>
<th>Morning timeE</th>
<th>Evening time</th>
<th>Difference in hours</th>
</tr>
{% for data in data %}
<tr>
<td>{{data.username}}</td>
{% endfor %}
{% if get_time %}
{% for m in get_time %}
<td>{{m.mtime}}</td>
<td>{{m.etime}}</td>
{% endfor %}
{% else %}
<td> Not available </td>
{% endif %}
</tr>
</table>
</form>
How can I get the difference between the times and place them within the HTML table?
If I understand correctly what you want to do, then you can/need to structure your data differently. An easy way is to prepare the data in your view:
def panel(request):
time_data = User.objects.filter(pk__gt=1)
time_table=[]
for user in time_data:
morning_time = Morning.objects.filter(user=user)
evening_time = Evening.objects.filter(user=user)
diff = morning_time - evening_time
time_table.append((user.name, morning_time, evening_time, diff))
return render(request, 'users/interface.html', {'data': time_table})
And in the template:
<table>
<tr>
<th>Name</th>
<th>Morning timeE</th>
<th>Evening time</th>
<th>Difference in hours</th>
</tr>
{% for line in data %}
<tr>
<td>{{line.0}}</td>
<td>{{line.1}}</td>
<td>{{line.2}}</td>
<td>{{line.3}}</td>
</tr>
{% endfor %}
</table>
You need to add the handling of not existing data in the view code.
Some remarks:
The whole thing does not really make sense to me. I guess you will need to filter for dates too. But you should get the idea from this. And why is it in a form?
You can add a property to the Alltime model that returns the difference between the morning and evening time
#property
def diff(self):
return self.etime - self.mtime
Then in your template you can use this property
{% for m in get_time %}
<td>{{m.mtime}}</td>
<td>{{m.etime}}</td>
<td>{{m.diff}}</td>
{% endfor %}
I have written a nested loop and doing value comparison between data coming from outer loop with inner loop. Below is my template code :-
<tbody>
{% for col in filter2.qs %}
<tr>
{% for mso in filter1.qs %}
{{ col.box_id }} vs {{ mso.box_id }}
<br>
{% if mso.box_id == forloop.parentloop.col.box_id %}
<td>{{ mso.mso_id }}</td>
<td>{{ col.box_id }}</td>
<td>{{ col.channel_id }}</td>
{% endif %}
{% endfor %}
</tr>
{% empty %}
<tr>
<td colspan="5">No data</td>
</tr>
{% endfor %}
</tbody>
Problems are :
When i do print {{ col.box_id }} vs {{ mso.box_id }} i can see values
When i do print {{ col.box_id|length }} vs {{ mso.box_id|length }} i see length of outer loop value as 0.
If condition below the prints never runs hence no data is inserted in the table.
I am getting data for both the loops from views.py
def search(request):
user_list1 = VCB_Execution_Details.objects.all()
user_filter1 = ReportFilter_VCB_Execution_Details(request.GET, queryset=user_list1)
user_list2 = VCB_Details.objects.all()
user_filter2 = ReportFilter_VCB_Details(request.GET, queryset=user_list2)
print(user_filter2.qs)
print(type(user_filter1))
return render(request, 'user_list.html', {'filter1':user_filter2,'filter2': user_filter1})
filters.py
class ReportFilter_VCB_Execution_Details(django_filters.FilterSet):
class Meta:
model = VCB_Execution_Details
fields = ['box_id','channel_id']
class ReportFilter_VCB_Details(django_filters.FilterSet):
class Meta:
model = VCB_Details
fields = ['box_id','mso_id']
So Finally i got the answer, problem was the object type was VCB_Execution_Details vs str. I tried checking the data type in def search(request): by printing variable type for each data in queryset of user_list1 and user_list2
models.py
class Transaction(models.Model):
created_date = models.DateField('created_date')
price = models.IntegerField(default=0)
abc = models.IntegerField(default=0)
pqr = models.IntegerField(default=0)
ghi = models.IntegerField(default=0)
Then I take a user input
input.html
<form method="POST" action="search/" style="margin-left:5em;">
{% csrf_token %}
<input type="radio" name="account" value="price"> price<br>
<input type="radio" name="account" value="abc"> abc<br>
<input type="radio" name="account" value="pqr"> pqr<br>
<input type="radio" name="account" value="ghi"> ghi<br>
</form>
views. py
def search(request):
if request.method == 'POST':
search_id = request.POST.get("account", None)
selected_transactions = Transaction.objects.exclude(search_id=0)
return render(request, 'stats/account_details.html', {'selected_transactions': selected_transactions,
'search_id': search_id})
else:
return render(request, 'stats/index.html')
I have to display contents based on user input.
account_details.html
<table>
<tr>
<th>Transaction date</th>
<th>{{ search_id }}</th>
</tr>
{% for transaction in selected_transactions %}
<tr>
<td>{{ transaction.created_date }}</td>
<td>{{ transaction.{{ search_id }} }}</td>
</tr>
{% endfor %}
</table>
I have two issues here.
1.Transaction.objects.exclude(search_id=0) doesn't work. It does not take the value of variable search_id. How do I exclude dynamically those transactions where user input attribute=0?
2.{{ transaction.{{ search_id }} }} in account_details.html doesn't work as it is a syntax error. I need to display data varying on user input. How do I use two variables inside a single tag in my template?
I get that I can resolve both using if else statements, but I have a large no. of attributes. So, is there a shorter way to do it?
Any help is appreciated.
Issue 1: You are trying to use an attribute in a query set filter which is not present in your model. You might want to use any of your attributes of your model like price or any other attribute.
Issue 2: Code below:
<td>{{ transaction.created_date }}</td>
<td>{{ transaction.{{ search_id }} }}</td>
is not correct for various reasons. First thing that you are trying to access created_date attribute which is not present in your queryset attribute. Either you have to remove this attribute or add it into your model. Your second line is incorrect because its a syntax error. Below one might be helpful to you and its syntactically correct.
<td> {{ search_id }} </td>
Edit: You can put if else to compare which search_id is selected by the user and based on that corresponding data can be displayed.
{% if search_id == "abc" %}
{{ transaction.abc }}
{% elif search_id == "pqr" %}
{{ transaction.pqr }}
{% endif %}
(sorry for my bad english)
I need to delete an object, but directly from a list of the objects that y have in my template.
I have a work orders, that have spare parts but i don't know how to create the deleteview for the spare parts using only a buton in the detailview of the work order. The idea is that the user make click in the Delete button.
This is the model of the Spare Parts
class OrderSparePart(models.Model):
# Relations
workorder = models.ForeignKey(
WorkOrder,
verbose_name=_('order'),
)
# Attributes - Mandatory
spare_part = models.CharField(
max_length=80,
verbose_name=_('spare part'),
)
# Attributes - Optional
price = models.DecimalField(
max_digits=6,
decimal_places=2,
null=True,
blank=True,
verbose_name=_('price'),
)
# Object Manager
# Custom Properties
# Methods
def get_absolute_url(self):
return reverse('work_orders:detail', kwargs={'order_id': self.workorder.id})
# Meta and String
class Meta:
verbose_name = _("order spare part")
verbose_name_plural = _("order spare parts")
This is where is showed in the template
{% if spare_parts %}
<table class="table">
<thead>
<tr>
<th>{% trans "Spare Part" %}</th>
<th>{% trans "Price" %}</th>
<th>{% trans "Delete" %}</th>
</tr>
</thead>
<tbody>
{% for part in spare_parts %}
<tr>
<td><i class="fa fa-gear"></i> {{ part.spare_part }}</td>
{% if part.price %}
<td>$ {{ part.price }}</td>
{% else %}
<td></td>
{% endif %}
<td><i class="fa fa-trash"></i></td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>NO HAY REPUESTOS ASENTADOS AÚN</p>
{% endif %}
The the idea is use the to delete the spare part.
how i have to make the deleteview and the link to this???
Thanks!
here in fa fa-thrash pass the id and the URL as I did it:-
{% if spare_parts %}
<table class="table">
<thead>
<tr>
<th>{% trans "Spare Part" %}</th>
<th>{% trans "Price" %}</th>
<th>{% trans "Delete" %}</th>
</tr>
</thead>
<tbody>
{% for part in spare_parts %}
<tr>
<td><i class="fa fa-gear"></i> {{ part.spare_part }}</td>
{% if part.price %}
<td>$ {{ part.price }}</td>
{% else %}
<td></td>
{% endif %}
<td></i></td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>NO HAY REPUESTOS ASENTADOS AÚN</p>
{% endif %}
ur url would be sonething like that:
url(r'^delete/(?P<part_id>[0-9]+)/$', view.function, name='delete_view'),
in ur view:
def function(request,part_id =None):
object = YourModel.objects.get(id=part_id)
object.delete()
return render(request,'ur template where you want to redirect')
In your html template inside for loop use the form tag inside <td> to create delete button as below (css class will work if you are using bootstrap3):
<form action="{% url 'delete_view' pk=part.pk %}" method="POST">
{% csrf_token %}
<input class="btn btn-default btn-danger" type="submit" value="Delete"/>
</form>
add urlpattern in urls.py
url(r'^delete-entry/(?P<pk>\d+)/$', views.DeleteView.as_view(), name='delete_view'),
delete view will be like below in views.py
class DeleteView(SuccessMessageMixin, DeleteView):
model = OrderSparePart
success_url = '/'
success_message = "deleted..."
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
name = self.object.name
request.session['name'] = name # name will be change according to your need
message = request.session['name'] + ' deleted successfully'
messages.success(self.request, message)
return super(DeleteView, self).delete(request, *args, **kwargs)
Note: import necessary imports shown in links or you need not to worry if you are using IDE such as pyCharm it will prompt you which import to make.
My solutions works best for django 4.0.3 and is the combination of gahan and Abi waqas answers. Use this one if you are using django 3 or above
Add the following to views.py
def delete_object_function(request, id):
# OrderSparePart is the Model of which the object is present
ob = OrderSparePart.objects.get(id=id)
ob.delete()
return redirect('page-delete.html') # for best results, redirect to the same page from where delete function is called
Add the following to urls.py
path('page-delete/<int:id>', views.delete_object_function, name='delete_object'),
Add the following code to the django template from where the delete function is to be called.
Let's say page-delete.html
<form action="{% url 'delete_object' id=part.id %}" method="post">
{% csrf_token %}
<button class="btn btn-danger" type="submit" ><i class="fa fa-trash"></i></button>
</form>
This works as I've used this solution in my own code.
well it's quiet simple.
2 models with ManyToMany relation:
class Artist(models.Model):
name = models.CharField(max_length=100, unique=True)
slug = models.SlugField(max_length=100, unique=True,
help_text='Uniq value for artist page URL, created from name')
birth_name = models.CharField(max_length=100, blank=True)
class Song(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255, unique=True,
help_text='Unique value for product page URL, create from name.')
youtube_link = models.URLField(blank=False)
artists = models.ManyToManyField(Artist)
my view suppose to display latest 5 songs:
def songs(request, template_name="artists/songs.html"):
song_list = Song.objects.all().order_by('-created_at')[:5]
return render_to_response(template_name, locals(),
context_instance=RequestContext(request))
and the problem is in the template... i want to display the artist name
but just dont realy know how to do it, i tried:
{% for song in song_list %}
{{ artists__name }} - {{ song.title }}
{% endfor %}
would appreciate any help !
Try changing your template code to:
{% for song in song_list %}
{% for artist in song.artists.all %}
{{ artist.name }} - {{ song.title }}
{% endfor %}
{% endfor %}
artists is another type of manager, so you have to iterate through artists.all and print the name attribute of each element.
Well, I worked on above solution of Mr #Dominic Rodger, but because am using Django version 3.2 it did not worked for me. Therefore, the problem may remain the same but according to how Django version changes, the way to solve them sometimes become different. If you're using Django 3.x use below solution.
In views.py
def songs(request):
song_list = Song.objects.all().order_by('-created_at')[:5]
song_list = {'song_list':song_list}
return render(request, 'artists/songs.html', song_list)
In your HTML Template use code below
<div class="table-responsive">
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>Artist - Song Title</th>
</tr>
</thead>
<tbody>
{% for song in song_list %}
</tr>
<td>{{ song.artist.name }} - {{ song.title }}</td>
<tr>
{% endfor %}
</tbody>
</table>
In urls.py
path('songs/', views.songs, name='songs'),
If you're running source code from localhost, then type on your browser http://127.0.0.1:8000/songs/
Thank you ....