django Ordering a field with user signed in - django

I am a newbee in Django, And I am trying to alter one of my view to order by the user signed in. For example, If 'test#example.com' is signed in, then the Tview should give data related to Test#example.com in the first row. At the moment it is in no specific order.
Current order: for a user signed as test#example.com
GEL_TEACT trea#example.com
TREAT_ACT test#example.com
I want to order this as:
Product OWNER
TREAT_ACT test#example.com
GEL_TEACT trea#example.com
my View:
class PListView(ListView):
model = Product
template_name = "app/product_list.html"
project_list_view = PListView.as_view()
my template:
<tbody>
{% for product in object_list %}
<tr>
<td>{{ product.title }}</td>
<td>
<a href="{% url "product-update" project_id=project.pk %}">
<i class="fi-pencil"></i>
</a>
</td>
</tr>
{% endfor %}
</tbody>
Thanks for your time.

These are three different options, depending on what you need. Just use one of them.
In your example, a logged in user should be displayed first. That is just one item to put in front of the list. So its easiest to do that right in the template
<ul>
<li>{{ user.username }}</a></li>
{% for item in users %}
{% if item != user %}
<li>{{ item.username }}</a></li>
{% endif %}
{% endfor %}
</ul>
However, if you want to get the list in a particular order, there are two ways to achieve that. If the order is just for this one ListView, then use the get_queryset() method of ListView()
class PListView(ListView):
model = Product
template_name = "app/product_list.html"
get_queryset(self):
return Product.objects.all().order_by('name')
However, if the data should always be ordered in this way, on all lists of the Product model, you can order it right on the model instead
class Product(models.Model):
name = models.CharField(max_length=50)
class Meta:
ordering = ['name', ]

Related

How to reassign a model to a different app for display only purposes in Django Admin

I know I can change the display title for a model in Django Admin using
class Meta:
verbose_name='Custom Model Name Here'
However, is there a way to display which app heading a model is displayed under?
For example, if I create a custom user model Users in a new app also called users then the default user model goes from Authentication and Authorization > Users to Users > Users.
I would like to retain it under the original heading Authentication and Authorization > Users.
I have read this answer which suggests changes the app verbose_name, however it only changes the verbose name of the app associated with the model. I want to show the model in a different group on the admin panel. You can see the issue that approach takes here:
You could set up a proxy model
In app_1.models.py
class MyModel(models.Model):
...
In app_2.models.py
from app_1.models import MyModel
class MyModelProxy(MyModel):
class Meta:
proxy = True
Then register the MyModelProxy in admin as normal
There is no simple way of doing what you're intending, check out the Django code/template that generates the view:
#never_cache
def index(self, request, extra_context=None):
"""
Display the main admin index page, which lists all of the installed
apps that have been registered in this site.
"""
app_list = self.get_app_list(request)
context = {
**self.each_context(request),
'title': self.index_title,
'app_list': app_list,
**(extra_context or {}),
}
request.current_app = self.name
return TemplateResponse(request, self.index_template or 'admin/index.html', context)
templates/admin/index.html:
{% for app in app_list %}
<div class="app-{{ app.app_label }} module">
<table>
<caption>
{{ app.name }}
</caption>
{% for model in app.models %}
<tr class="model-{{ model.object_name|lower }}">
{% if model.admin_url %}
<th scope="row">{{ model.name }}</th>
{% else %}
<th scope="row">{{ model.name }}</th>
{% endif %}
{% if model.add_url %}
<td>{% trans 'Add' %}</td>
{% else %}
<td> </td>
{% endif %}
{% if model.admin_url %}
{% if model.view_only %}
<td>{% trans 'View' %}</td>
{% else %}
<td>{% trans 'Change' %}</td>
{% endif %}
{% else %}
<td> </td>
{% endif %}
</tr>
{% endfor %}
</table>
</div>
{% endfor %}
As you can see, Django admin template is looping your app_list directy, so the only way of doing it would be to override the admin/index.html template to place your models in your desired order.
From Django docs:
For those templates that cannot be overridden in this way, you may still override them for your entire project. Just place the new version in your templates/admin directory. This is particularly useful to create custom 404 and 500 pages.
https://docs.djangoproject.com/en/2.2/ref/contrib/admin/#overriding-vs-replacing-an-admin-template
In firstapp.models.py
class ActualModel(models.Model):
class DisplayModel(ActualModel):
class Meta:
proxy = True
in secondapp.admin.py
from firstapp.models import DisplayModel
admin.site.register(DisplayModel)
Easier way to do that:
In model class Meta add
app_label = 'app2'
db_table = 'app1_modelname'
so you assigning model to another app with app_label and assigning db_table with old (current) table name to prevent making migrations and table renami

How to create two columns from a QuerySet in a Django template [duplicate]

I am trying to split a list from my model across two columns, using this html code in the template:
< div class ="col-md-6" >
{%for value in object_list %}
<ul>< ahref="/sites/{{value.url}}/">{{value.Site}}</a></ul>
{% endfor %}
I was planning to achieve this with the slice tag to filter the list, e.g.:
{%for value in object_list|slice:"10:20" %}
It does not work however, and I think it might be because I have context data i.e. {{value.Site}}, instead of just {{Site}} for example. This is the corresponding view:
class homeview(ListView):
template_name = 'annual_means/home.html'
def get_queryset(self):
return AnnualMean.objects.values("Site", "url").distinct()
What do I need to do to get the slice to work?
I think, what you need is this:
<table>
<tr>
<th>URL</th>
<th>SITE</th>
</tr>
{% for value in object_list %}
<tr>
<td>{{value.url}}</td>
<td>{{value.Site}}</td>
</tr>
{% endfor %}
</table>
URLs and Sites will be displayed as a table.

Pre-process model childeren from a template in Django

I've got a DetailView to display a Menu (restaurant), with the following structure:
Menu > Courses > Course_Categories > Dishes
i.e. (Theather Menu) > (Starters, Entrees, Desserts) > (Fish Soup, Ribs, etc.)
I want to prefetch the course_categories and dishes, in addition to that I want to set a property on each dish to be used in the template. This property (the price) is dependent on time of day, therefore it's not simple stored as a value on the Dish.
I tried the following:
class MenuView(generic.DetailView):
template_name = "cms/detail/menu.html"
model = Menu
def get_object(self, queryset=None):
pkValue = pk = self.kwargs.get(self.pk_url_kwarg, None)
menu = Menu.objects.get(id=pkValue)
courses = menu.courses.all().prefetch_related('course_categories').prefetch_related('dishes')
for course in courses.all().iterator():
for course_category in course.course_categories.all().iterator():
for dish in course_category.dishes.all().iterator():
dish.price = "0.00"
return menu
When I iterate the data in my template, it shows everything, but no value for the dish.price property. What I think happens is that the related sets are re-retrieved, and therefore my custom set property doesn't show.
Template:
{% for course in menu.courses.iterator %}
<tr>
<td><strong>{{ course.name }}</strong></td>
</tr>
{% for course_category in course.course_categories.iterator %}
<tr>
<td><em> {{ course_category.name }}</em></td>
</tr>
{% for dish in course_category.dishes.iterator %}
<tr>
<td> {{ dish.name }} {{ dish.price}}</td>
</tr>
{% endfor %}
{% endfor %}
{% endfor %}
Any suggestions?
You are using iterator() which explicitly does not cache the results. When you do {% for course in menu.courses.iterator %}, the results are fetched from the database again.
Use simply .all() in your view instead of .all().iterator(), and stop using .iterator in your template, and you shouldn't have the problem.

django filter a regroup within a forloop

I have a model called Subtopic. One of my templates runs a forloop on an object, returning a different field for each cell of a table row.
Two of the table cells look up a field which is a ManytoMany foreign key, both to the same foreign model, Resource. I want each to display different results, based on the value of a boolean field within the Resource model.
What you see below is currently working fine, but doesn't attempt to filter by the boolean field.
models.py:
class ICTResourceManager(models.Manager):
def get_query_set(self):
return super(ICTResourceManager, self).get_query_set().filter('is_ict': True)
class NonICTResourceManager(models.Manager):
def get_query_set(self):
return super(NonICTResourceManager, self).get_query_set().filter('is_ict': False)
class Resource(models.Model):
subtopics = models.ManyToManyField(Subtopic)
external_site = models.ForeignKey(ExternalSite)
link_address = models.URLField(max_length=200, unique=True, verify_exists=False)
requires_login = models.BooleanField()
is_ict = models.BooleanField()
flags = models.ManyToManyField(Flag, blank=True)
comment = models.TextField()
def __unicode__(self):
return u'%s %s' % (self.external_site, self.link_address)
objects = models.Manager()
ict_objects = ICTResourceManager()
nonict_objects = NonICTResourceManager()
class Meta:
ordering = ['external_site', 'link_address']
views.py:
def view_ks5topic(request, modulecode, topicshortname):
listofsubtopics = Subtopic.objects.filter(topic__module__code__iexact = modulecode, topic__shortname__iexact = topicshortname)
themodule = Module.objects.get(code__iexact = modulecode)
thetopic = Topic.objects.get(module__code__iexact = modulecode, shortname__iexact = topicshortname)
return render_to_response('topic_page.html', locals())
My template:
{% for whatever in listofsubtopics %}
<tr>
<td>
{{ whatever.objective_html|safe }}
<p>
{% if request.user.is_authenticated %}
{% with 'objective' as column %}
{% include "edit_text.html" %}
{% endwith %}
{% else %}
{% endif %}
</td>
<td>
{% regroup whatever.resource_set.all by external_site.name as resource_list %}
{% for external_site in resource_list %}
<h4>{{ external_site.grouper }}</h4>
<ul>
{% for item in external_site.list %}
<li>{{ item.comment }}</li>
{% endfor %}
</ul>
{% endfor %}
</td>
</tr>
{% endfor %}
As you can see, I've added extra managers to the model to do the filtering for me, but when I replace the appropriate lines in the template, I just get blanks. I have tried: for external_site.ict_objects in resource_list and for item.ict_objects in resource_list and <a href="{{ item.ict_objects.link_address }}">. If this were in the view I could probably do the filter just by .filter('is_ict': True), but with this being inside a forloop I don't know where to do the filtering.
I also tried writing regroup whatever.resource_set.filter('is_ict': True) in the template, but the syntax for regrouping seems to use resource_set.all rather than resource_set.all() (and I don't know why) so the filter text doesn't work here.
Turns out it was possible to do it using a custom template filter. The original efforts to filter within the template weren't working, given that as is well documented the template language is not a fully-fledged python environment. My original question remains open for anyone who knows an alternative method that more directly addresses the question I was originally asking, but here's how I did it:
myapp_extras.py:
from django import template
register = template.Library()
def ict(value, arg):
"filters on whether the is_ict Boolean is true"
return value.filter(is_ict=arg)
register.filter('ict', ict)
My template, note the use of the custom filter in line 2:
<td>
{% regroup whatever.resource_set.all|ict:1 by external_site.name as resource_list %}
{% for external_site in resource_list %}
<h4>{{ external_site.grouper }}</h4>
<ul>
{% for item in external_site.list %}
<li>{{ item.comment }}</li>
{% endfor %}
</ul>
{% endfor %}
</td>
After this I was able to remove the additional custom managers from the model.
One further question, when filtering for the boolean is_ict field, I found that I had to use filter(is_ict=1) and filter(is_ict=0). Is that the only way to refer to a True or False value?

How can insert Hyperlinks for image fields in Django template

I am displaying the database field names and values in html table in django templae with this code
<table id="listTable" >
<tr>
{% for fieldname in object_fields %}<th>{{ fieldname }}</th>{% endfor %}
</tr>
{% for object in object_list %}
<tr class="{% cycle 'row1' 'row2' as rowcolors %}">
{% for fieldvalue in object %}<td>{{ fieldvalue }}</td>{% endfor %}
</tr>
{% endfor %}
</table>
Now the problem i have one field called image_name and i want that for that there should be hyperlink inserted with the text but how can do that so that other columns don't get affected.
I use this code for all the tables
What I would do in this case is add a property to the class that wraps the value of the field in an anchor tag and add that property to your object_list instead of the default value of the field. Here's a quick and dirty example to get you going.
#models.py
class MyClass(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField()
#property
def email_link(self):
return u'%(email)s' % {'email' : self.email}