Django inline formset render by order - python

I Use Django 4.0.6 and Python 3.10.
I have a Form with nested inline formset. The inline formset is orderable (can_order=True). The 'ORDER' value of the form will be set to an instance field "index". I use Javascript to order those forms in the template.
When I submit the whole form and the form is not valid then the forms are not rendered by the 'ORDER'/'index' attribute. They will be rendered in the order they were created. To solve this I overwrite the __iter__ function of the formset to "Yield the forms in the order they should be rendered." (see django docs - BaseFormSet).
My __iter__ function:
def __iter__(self):
"""Yield the forms in the order they should be rendered."""
if self.is_bound:
return iter(sorted(self.forms, key=lambda x: x.instance.index, reverse=False))
#return iter(sorted(self.forms, key=lambda x: x.cleaned_data['ORDER'], reverse=False))
else:
return iter(self.forms)
When I submit the form I get the following errors according to the values that I want to access (cleaned_data or instance).
Error when accessing order through cleaned_data: FormXY has not attribute 'cleaned_data'
Error when accessing index through instance: '<' not supported between instances of 'NoneType' and 'NoneType'
I set a breakpoint in the __iter__ function to see whats the problem, but there is no problem. When I set a breakpoint there is no error. When I unset the breakpoint the error occurs.
It seems that the whole form data is not fully available when __iter__ is called.
I tried also to order the forms in the template through a custom template tag. I get the same errors.
The forms attribute of a formset is a #cached_property.
Has anyone a idea how to solve the problem or how to order forms by a specific instance attribute.

Related

Django models class object is not iterable

In a django project i have created a model class having a foreign key.
model class
When i tried to get objects in a variable by classname.objects.get(parameters=value).
assigning objects into a variable
Now when to display the object's attributes html by django template.
iterating through objects
now when i run the program i am getting error of 'Bid' object is not iterable.
how to correct this code to working?
thankyou
filter() will always give you a QuerySet, even if only a single object matches the query.
If you know there is only one object that matches your query, you can use the get() method on a Manager which returns the object directly.
That means you .get() will only return a single element which is not iterable.
So, you could use .filter instead of .get() in your view (listingpage) and fix it.
bids = Bid.objects.filter(title = title_id)

Sort queryset by added field

I'm trying to add an extra field to the instances of my queryset and then sort the set by the new field.
But I get a field error( Cannot resolve keyword 'foo' into field. Choices are: ... )
My view(abstract):
def view(request):
instances = Model.objects.all()
for counter, instance in enumerate(instances):
instance.foo = 'bar' + str(counter)
instances.order_by('foo') #this line causes trouble
return render(request, 'template.html', {'instances': instance})
My template:
{% for instance in instances %}
{{instance.foo}}
{% endfor %}
If I leave out the order_by line the templates renders as expected, so the field seems to be there.
So why do I get a field error?
It would be awesome, if somebody could help me to understand what I'm doing wrong.
Thanks in advance.
I found a possible solution to change the template to
{% for instance in instances|dictsort:'foo' %}
and that works fine, but from what I understand there should be as little logic as possible in the view, so I figure sorting should be done in the view.
Or is this actually the right way?
The Django ORM aims to construct database queries. As a result, you can only query on what a database "knows". Methods, properties, or attributes you added yourself are unknown to the database. The .order_by thus has no effect, since you "patched" the objects in the instances queryset.
If you however call an instances.order_by you construct a new queryset. This queryset takes the context of the parent, and thus represents a (slightly) modified query, but again, a query. Whether the old queryset is already evaluated or patched, is of no importance.
Furthermore even if there was a column foo, it would not help, since the instance.order_by does not order the instance queryset, it constructs a new one, one that looks approximately like the old one, except that the rows are ordered.
You thus will have to sort in Python now. You can for example construct a list of ordered elements with sorted(..), like:
from operator import attrgetter
def view(request):
instances = Model.objects.all()
for counter, instance in enumerate(instances):
instance.foo = 'bar' + str(counter)
mydata = sorted(instances, key=attrgetter('foo'))
return render(request, 'template.html', {'instances': mydata})
So now mydata is no longer a QuerySet, but a vanilla list. Furthermore note that ordering in a database might be slightly different than ordering in Python. In Python exceptions can occur if not all elements have the same type, and furthermore it is not guaranteed that the semantics behind the order relation is exactly the same.
The new attribute in the Python Objects does not exist in the database and only in those instances. order_by changes the queryset and not your current list of objects stored in memory.
One approach would be to use the builtin python sorting functions in the view like: sorted or even list.sort().

How to do type hinting for a template parameter in pycharm3?

I noticed that when I use the function render or render_to_reponse in a django view, I can auto complete and referenced the template in the template string.
When I tried to do the same for my method the string does not response the same way even though I named the parameter template_name same as the "render" method.
def my_render(self, template_name):
"""
My custom render method
:type template_name: Template|str
"""
return render(self.request, template_name, self.context)
Those code insight features are attached to specific full-qualified function names from the Django implementation. It's unfortunately not currently possible to enable those features for a function in your own project.

Reverse relation (one-to-one) lookup not working in Django view (django-plans)

I've just installed django-plans. They link a UserPlan object to the used settings.AUTH_USER_MODEL through a one-to-one relation. As I understand it, this relation does not require a related_name for reverse lookups. Therefore, it should be callable using the Class name in without Caps, e.g. userplan.
My problem is that the reverse lookup works in the python shell:
>>> from profiles.models import CustomUser
>>> s=CustomUser.objects.get(email="test#test.com")
>>> s <CustomUser: test#test.com>
>>> s.userplan <UserPlan: test#test.com [Starter]>
But when I use the code in a view, it returns an Attribute Error:
'CustomUser' object has no attribute 'userplan'
This is the code I'm using in the view:
u = CustomUser.objects.get(email="test#test.com")
up = u.userplan
First I thought it had to do with request.user being a SimpleLazyObject, but even when fetching a "real" user it didn't seem to work in the view.
Any suggestions?
P.S. As you might have noticed, we're using a custom user model.

Make object attribute displayabe instead of object django

In django admin, I have a model in which there are several objects. Now in admin, I have the link to Mymodel. If i click that, I get a list, all of which say
Mymodel object
If I need to find a particular record from the table, then I simply have to search the whole list. How can I change the setting so that instead of MyModel object I get to see an attribute, say name of that particular object??
You should define __unicode__ method in your model class:
def __unicode__(self):
return self.name # to display name attribute
From django docs:
The __unicode__() method is called whenever you call unicode() on an
object. Django uses unicode(obj) (or the related function, str(obj))
in a number of places. Most notably, to display an object in the
Django admin site and as the value inserted into a template when it
displays an object. Thus, you should always return a nice,
human-readable representation of the model from the __unicode__()
method.

Categories

Resources