Django Contect_processor reversed list - python

I'm working with django and trying to make a context_processor who´s going to make a list of newsposts which can be shown in my base template. My code look like this.
from news.models import Post
def get_news_title(request):
return{
'get_news_title': Post.objects.all().reverse()[:5]
}
But still it just show my first 5 newsposts...
Any tips?

Django docs say explicitly that
reverse() should generally only be called on a QuerySet which has a
defined ordering (e.g., when querying against a model which defines a
default ordering, or when using order_by()). If no such ordering is
defined for a given QuerySet, calling reverse() on it has no real
effect (the ordering was undefined prior to calling reverse(), and
will remain undefined afterward).
so you need to use order_by('some field here').
For example:
Post.objects.order_by('id').reverse()[:5]
See docs for order_by()

Related

When should I use a lazy function in Django

I am starting out with django and I have come across functions like reverse_lazy instead of reverse and gettext_lazy instead of gettext for translation.
From the information, I could get online, it seems that these lazy functions only call the original functions when they are to be used and not immediately they are declared.
What exactly does this mean and in what real life coding senerios should I use the lazy version as against the original function.
Thanks a lot in advance
This is the sort of thing that is only needed per-specific-situation, as you've intuited yourself.
A common example is with Generic Class-based Views. The attributes of the view are evaluated when the views.py file is read. But at the time it's being read, the urls file will not have been read yet! So assigning to an attribute with reverse() will fail, because any url named in the arguments sent to reverse() will not be available to the view file. But with reverse_lazy(), you can assign a url to an attribute in the class-based view, and it will not be updated until the named url is actually available:
class RegisterView(CreateView):
form_class = CustomUserCreationForm
success_url = reverse_lazy('index') # reverse() would fail here!
template_name = 'registration/register.html')
Again: success_url is an attribute of the view, and will be evaluated when the views.py file is read. But at that time, the urls will not have been read, so 'index', a named url, will not be available yet. We use reverse_lazy() instead of reverse() to get around this problem; 'index' is not evaluated until it's actually needed, and now we can define our attribute as desired.
Note that if your view has a user-defined method, you can use the normal reverse() call inside the method, if needed, because unlike view attributes, a view's methods are not evaluated until the method is explicitly called -- and by that time, the urls will be available.
There are other use cases, for sure, but CBV's are a common case where reverse_lazy() becomes necessary, specifically when assigning urls to attributes.

Django: How to add to an ArrayField?

I have some questions about the ArrayField mentioned here: https://docs.djangoproject.com/en/3.1/ref/contrib/postgres/fields/#django.contrib.postgres.fields.ArrayField
How do you add to an ArrayField? It's clear you can treat it like a regular field and do things like
my_array_field = []
my_array_field.save()
But what's confusing is I'm seeing everyone mention my_array_field.append("something") in StackOverflow questions. This isn't mentioned in the documentation at all. Moreover, if an arrayfield is .append()ed to, does it still require .save()?
do we need to call save()?
Yes, we need to call the save() method to COMMIT the changes to Database. Unless calling the save() method, the value only persists in the scope of the variable, as the python list. So, calling the save() is a must do thing while updating the values.
how to add values to array field?
You can treat it as a normal python list object, because Django converts the db array field to native Python list object
model_instance.my_array_field = [1,2,3]
model_instance.save()
model_instance.my_array_field += [4,5,6]
model_instance.save()
This isn't mentioned in the documentation
Probably, they may be missed to include this information.
Django documentation ArrayField
recommends to add some default value, and make it callable, so just try in your models:
class SomeModel(models.Model):
...
my_array_field = ArrayField(models.CharField(max_length=255), default=list)
So you'll be able to add items in it just like with regular list in python:
my_array_field.append("something")
my_array_field.append("another_something")
And even more - you can use all methods like pop, extend, index etc.

How to define a default ForeignKey object in django using get_or_create?

I have two models which I want to relate: User and Group.
Each user belongs to a group. I've tried to create a default user by using in get_or_create():
group = models.ForeignKey(Group.objects.get_or_create(name="Free")[0])
But it raises the following error:
(fields.E300) Field defines a relation with model 'Group', which is either not installed, or is abstract.
What can I do to fix this issue?
Each user must have a non-null group value. So I've read about this get_or_create() method. But I've also seen that it can return more than one object... and I don't want it to happen. I thought about creating a unique name parameter but is there a better solution for it?
Can you help me, please? I appreciate your help.
A more comprehensive answer can be found here: How to set a Django model field's default value to a function call / callable (e.g., a date relative to the time of model object creation)
You need to specifify the related Model and set the default.
class User(models.Model):
def default_group(self):
return Group.objects.get_or_create(name="Free")[0]
group = models.ForeignKey('app_name.Group', default=default_group)
Your default value would be evaluated at model definition time, but Django allows you to provide a callable as default, which is called for each instance creation.
To explain the error - code that is not inside a function, such as the line in your question, is executed as soon as your models.py file is loaded by Python. This happens early in the start-up of your Django process, when Django looks for a models.py file in each of the INSTALLED_APPS and imports it. The problem is that you don't know which other models have been imported yet. The error here is because the Group model (from django.auth.models) has not been imported yet, so it is as if it doesn't exist (yet).
Others have suggested you could put the Group.objects.get_or_create(name="Free")[0] in a function so that it is not executed immediately, Django will instead call the function only when it needs to know the value. At this point all the models in your project, and Django's own models, will have been imported and it will work.
Regarding the second part of your question... yes, any time you use get or get_or_create methods you need to query on a unique field otherwise you may get MultipleObjectsReturned exception.
In fact I think you should not use get_or_create for what you are trying to do here. Instead you should use an initial data fixture:
https://docs.djangoproject.com/en/1.9/howto/initial-data/
...to ensure that the default group already exists (and with a known primary key value) before you run your site.
That way you will know the unique pk of the default Group and you can do a get query:
def default_group():
return Group.objects.get(pk=1)
class YourModel(models.model):
group = models.ForeignKey(Group, default=default_group)

Using extra in django querystet combined with django lookups (not constant parameters in extra)

I want to call a postgresql function in django queryset and parameters of this function are related to current row.
Lets assume I have following queryset:
queryset = Baz.objects.filter(foo = 'foo', foo__bar = 'bar').
and I would like to add an extra argument that calls a function, and argument of this function should be name that django lookup foo_baz resolves to.
In ideal world i would like to write:
queryset.extra(were = "my_function(foo__baz)")
that woul render to:
my_function("FOO_TABLE".baz)
You reference columns like this with F() objects generally, but I'm not sure if you can use them with extra() in a case like this. Hopefully that's a starting point for you to experiment though.
Here is response for this problem from django developers:
extra often creates more problem than it solves. The current trend is to
deprecate it rather than extend it.
The recommended way to achieve your goal is to use raw SQL.

Can django-tastypie display a different set of fields in the list and detail views of a single resource?

I would like for a particular django-tastypie model resource to have only a subset of fields when listing objects, and all fields when showing a detail. Is this possible?
You can also now use the use_in attribute on a field to specify the relevant resource to show the field in. This can either be list or detail, or a callback.
You would have to specify all fields in the actual ModelResource then override the get_list method to filter out only the fields you want to show. See the internal implementation of get_list on Resource to see how to override it.
However, note this will only apply on GET requests, you should still be able to POST/PUT/PATCH on the resource with all fields if you authorization limits allow you to do so.
In a nut shell, you want to hot patch the internal field list before full_dehydrate is called on all ORM objects returned by obj_get_list.
Alternatively, you can let the full dehydrate mechanism take place and just at the end of it remove the fields you don't want to show if you don't care about squeezing out as much as speed as possible. Of course you would need to do this only if the URL is invoked as a consequence of get_list call. There is a convenience method for this alter_list_data_to_serialize(request, to_be_serialized).
Just do:
class SomeResource(Resource):
class Meta(...):
...
field_list_to_remove = [ 'field1', 'field2' ]
...
def alter_list_data_to_serialize(request, to_be_serialized):
for obj in to_be_serialized['objects']:
for field_name in self._meta.field_list_to_remove:
del obj.data[field_name]
return to_be_serialized
There is an open issue for this on GitHub, with a number of workarounds suggested there.
Can also use the dehydrate(self, bundle) method.
def dehydrate(self, bundle):
del bundle.data['attr-to-del]
return bundle

Categories