list.reverse() doesn't work properly in Django - python

I am on my first project with the Django framework, and I decided to create a blog, since it is easy to find stuff about it online. I, then, found out about the Paginator module, and decided to use it. The problem is, whenever I add a post it goes to the end of the Database, so I have a blog that, so far, displays old posts first.
Because of that, I decided to use .reverse(), like this:
def index(request):
posts = Post.objects.all()
posts.reverse()
paginator = Paginator(posts, 2)
try:
page = int(request.GET.get("page", "1"))
except ValueError:
page = 1
try:
posts = paginator.page(page)
except (InvalidPage, EmptyPage):
posts = paginator.page(paginator.num_pages)
return render_to_response('index.html', {
'Posts': posts,
'Sideposts': Sidepost.objects.all(),
})
The only problem is, this doesn't work, at least not with Paginator. When I stop using Paginator it works, but otherwise it doesn't.
I think this is a really weird behaviour, and I had a look around but couldn't find anything that helped me with this problem. Am I doing anything wrong?

Let the database do the ordering:
posts = Post.objects.all().order_by('-id')
Of course, it would be better to use a date field or something.

First, Post.objects.all() does not return a list object, but queryset object.
And reverse method does not change the queryset itself, but returns reversed version of queryset.
Convert it to list posts = list(Post.objects.all()) to use reverse method if you want list object.
Maybe following is more preferable:
posts = Post.objects.all().reverse()

Related

How to get rid of <QuerySet[]> tag when getting the data on my template from the database? Django

I'm having a bad time figuring this out through searching different stackoverflow question but I'm using a function based view to make my day simplier. But when i'm retrieving this single data from a database and showing only one record using slice. It throws beside it a tag which commonly see when we test print in our terminals. But how exactly to get rid of this?
tutorials = Tutorial.objects.values_list('id', flat=True)
courses = Course.objects.all()
tutorial_title = Tutorial.objects.filter(id__in=tutorials).values('title').values_list('title', flat=True)
context = {'tutorial': tutorials,'courses': courses, 'tutorial_title': tutorial_title}
Here's my code snippet, where when i call {{ tutorial_title | slice:'1'}}. It should only call one latest record, which works flawlessly but there is a <QuerySet tag beside the shown data.
Why not just pass it to the template as a signle title:
courses = Course.objects.all()
tutorial_titles = ', '.join(Tutorial.objects.values_list('title', flat=True))
context = {
'courses': courses,
'tutorial_titles': tutorial_titles
}
Here tutorial_titles is a comma seperated string of tutorial titles.
Or if you only want the first title:
courses = Course.objects.all()
tutorial_title = Tutorial.objects.values_list('title', flat=True).first()
context = {
'courses': courses,
'tutorial_title': tutorial_title
}
I think i just discover the answer by an accident. So i know the QuerySet is a List so in my views.py, I think i could just set a for loop on the Query itself and throw it to a empty List that will throw to the template using the context. lmao
tutorials = Tutorial.objects.values('id')
courses = Course.objects.all()
**tutorial_titleList = []**
tutorial_title = Tutorial.objects.filter(id__in=tutorials).values('title').values_list('title', flat=True)
**for tutorial in tutorial_title:
tutorial_titleList.append(tutorial)**
context = {'tutorial': tutorials,'courses': courses, 'tutorial_title': tutorial_titleList}
and in my template tag. Since it still returns a List, i just put | join: "" template tag beside

Django filtering queryset

Here is my simple view:
def transaction_list(request):
current_user = request.user
month = datetime.date.today().month
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
objects = Transaction.objects.filter(user=current_user, date__month=month)
p = Paginator(objects, 10, request=request)
transactions = p.page(page)
return render(request, 'transaction/list.html',
{'transactions': transactions})
It shows a list of transactions which occured in the current month.
I want to add an option to change the month of the transactions being displayed but I have no clue how to tackle this and make it work. Should it be done in a view? maybe template? I would appreciate any ideas
Take some time to read some Django docs as they may prove really valuable (not to mention they are very clean and well written for every version available). I would focus on Working With Forms
In short, you'll pass the month from your django template (maybe via ajax or a simple HTML form POST), to your view, and use your view function to get the POST data and use that in your queryset.
It is hard to provide a good, thorough answer because there are different ways to do this. Do you want AJAX? Simple form with page reload, etc? 
Okay, here, in detail, is how I usually handle a POST request. This isn't tested code, it's just psuedo code, but should work as far as I can tell, aside from a few minor typos probably. BUT, it should give you an idea of how to handle ajax requests in Django.
This is pretty 101 and taking some time to read the docs and run through some of the early projects covers a these concepts much I, so my going into more depth isn't really valuable to SO readers.
views.py
class change_date_form(forms.Form):
new_date = forms.DateField()
def change_transaction_date(request):
#Do some checks to make sure user is authorized to do this
current_user = ...
customer_data = []
if request.method == 'POST':
form = change_date_form(request.POST, request.FILES)
if form.is_valid():
change_date = form.cleaned_data.get('new_date')
objects = Transaction.objects.filter(user=current_user, date__month=change_date)
for i in objects:
customer_data.append(objects.name)
response_data = json.dumps(customer_data)
return HttpResponse(response_data, content_type='application/json')
urls.py
...
url(r'^change_date_view/', 'module.views.change_transaction_date'),
Jquery:
$('button_handler').on('click', function() {
var new_date_value = $(date_field_selector).val()
$.ajax({
url: "/change_date_view/",
type: "POST",
data: {
new_date: button_handler,
},
success:function(data) {
//build your html via javascript with response data
}
})
})

Saving data from a modelform Django

Now heads up! I am fresh noob off the NOOB-BUS from NOOBSVILLE!
So i am workin on a form to load up information and edit that form information and im in a headache. so i am using:
Django: 1.8
Pyhton: 3.5.1
backend is sqlite
I am using a form.ModelForm to load information into but when it comes to saving this is where i am stuck. the documentation is very confusing should i use all or just one clean.
this is the forms.py
class EditContact(forms.ModelForm):
class Meta:
model = Contact
#the list of all fields
exclude = ['date_modified']
def clean(self):
if self.date_of_entry is None:
print("looking to see what works")
self.date_of_entry = datetime.date.today()
return
def clean_ContactID(self):
#see this line below this comment i dunno what it does
ContactID= self.cleaned_data.get('ContactID')
print ("cleaning it")
# i also dont know what validation code suppose to look like
# i cant find any working examples of how to clean data
return ContactID
now there are mainly more def clean_methods but i think what i want to use is clean which should use all but in my view.
this is in view.py
def saveContactInfo (request):
#this part i get
if request.user.is_authenticated():
ContactID= request.POST['ContactID']
a = ListofContacts.objects.get(ContactID=ContactID)
f = EditContact(request.POST,instance=a)
print("plz work!")
if f.is_valid():
f.save()
return render (request,"Contactmanager/editContact.html", {'contactID': contactID})
else:
return HttpResponse("something isnt savin")
else:
return HttpResponse("Hello, you shouldnt ")
and this is model.py
def clean(self):
if self.ConactID is None:
raise ValidationError(_('ContactID cant be NULL!'))
if self.date_of_entry is None:
print("think it might call here first?")
self.date_of_entry = datetime.date.today()
print ( self.date_of_entry )
if self.modified_by is not None:
self.modified_by="darnellefornow"
print(self.modified_by )
if self.entered_by is not None:
self.entered_by = "darnellefornow"
print(self.entered_by )
ContactID = self.cleaned_data.get('ContactID')
return
now above the model has the fields and the types which all have blank = true and null = true except for the excluded field date_of_entry
and ive gotten to find out that when calling is_valid() in views it calls the models.clean() but it fails to save!!! and i dont know why! i dont know how to do the validation. i would like to know the process and what is required and even an example of form validation a field.
I think you're wanting info/answers on a couple of things here, looking at your code comments. Hopefully this helps:
1) You only need to use the clean_FIELDNAME functions if you need to handle something custom specifically for that field. The Django docs show this as an example:
def clean_recipients(self):
data = self.cleaned_data['recipients']
if "fred#example.com" not in data:
raise forms.ValidationError("You have forgotten about Fred!")
# Always return the cleaned data, whether you have changed it or
# not.
return data
So in that block, they are checking to see if the email list provided contains a particular email.
2) That also shows another question you asked in your comments about how to handle the validation. You'll see in that snippet above, you could raise a forms.ValidationError. This is discussed more here: https://docs.djangoproject.com/en/1.10/ref/forms/validation/
So, if an error is raised in any of those clean_ methods or in the main clean method, the form.is_valid() will be false.
Does that help?

Django: How do I access post data and match with a criteria

I need some guidance on best practice implementation of the following.
I have a scenario where I am building an app, but if it matches a certain "category" or "locale" and want to redirect it to a page in between else just go the normal route.
Here is my simple views.py
if form.is_valid():
...
kwargs = {'project_id':project_id, 'categories':request.POST['categories'], 'locale':request.POST['locale']}
process_se(request, **kwargs)
return HttpResponseRedirect(obj.next_url)
Here is what I have in my models.py file but it seems to be very inconsistent.
Is there a better way to handle this request?
def process_se(self, request, **kwargs):
if "All" or "Sweden" in kwargs['locale']:
if "Technology" or "Internet" in kwargs['categories']:
next_url = request.build_absolute_uri(reverse('project_new_se', kwargs={'project_id': self.id}))
else:
next_url = request.build_absolute_uri(reverse('project_new_step2', kwargs={'project_id': self.id}))
self.next_url = next_url
UPDATES:
I am using forms.ModelForm, categories and locales are ManyToManyField's
I have simulated a for in the shell and still seem to get no result
Here is the cleaned_data output
f.cleaned_data
{'locale': [<Locale: Sweden>, <Locale: All>], 'categories': [<Category: Technology>, <Category: Internet>]}
Although running this for fields in the form seem to render perfectly fine based on your solution
I originally proposed putting this code in the form class, but ApPeL revised the question to point out that locale and categories are many-to-many fields on the model. So now I suggest putting a method like this in your model:
def requires_swedish_setup(self):
"""
Return True if this project requires extra Swedish setup.
"""
return (self.locale.filter(name__in = ('All', 'Sweden')).exists())
and self.categories.filter(name__in = ('Technology', 'Internet')).exists())
and then implementing your view like this:
if form.is_valid():
project = form.save()
next = 'project_new_step2'
if project.requires_swedish_setup():
next = 'project_new_se'
next_url = reverse(next, kwargs={'project_id': project.id})
return HttpResponseRedirect(next_url)
Some notes:
I'm assuming that Locale and Category objects have name fields (if not, use whatever field contains the name you are testing).
It's not a good idea to read form data out of request.POST (widgets haven't had a chance to run, and it hasn't been validated): it's better to use form.cleaned_data.
You don't need to call request.build_absolute_uri in this case: it's fine to feed the result of reverse directly to HttpResponseRedirect.
"All" or "Sweden" in kwargs['locale'] is probably not what you mean: it parses like "All" or ("Sweden" in kwargs['locale']) and so is always true.

Change number of items per page or view all in a view using a paginator in django

I am using django 1.3 and I have a view that takes a paginated queryset (set to use 50 objects). Here is the relevant part of the get_context_data() method in the view:
#build paginator for querysets
paginated_scanned_assets = Paginator(scanned_assets_qs, 50)
#get the specified page
try:
page_num = int(self.request.GET.get('page', '1'))
except ValueError:
page_num = 1
#get a paginated list of object
try:
scanned_assets = paginated_scanned_assets.page(page_num)
except (EmptyPage, InvalidPage):
scanned_assets = paginated_scanned_assets.page(paginated_scanned_assets.num_pages)
The template it renders to just builds a table from the queryset and has links to go to the next and previous pages.
What I want to do is either have a link to view all, which would just display the queryset unpaginated, or an option to modify the number of objects per page (which would recreate the paginator). I haven't worked with views or design much though so I am not sure how to do this. Is it something I can do with js, and if so how? Otherwise can I just do it with django and html? It might be really simple, I am just pretty inexperienced and haven't found an answer or example anywhere.
Thanks!
What you want to do is add an optional parameter to the view called 'page_size' and then do something like:
def your_view(request, ..., page_size=50):
scanned_assets_qs = # get your scanned_assets QuerySet
if page_size == -1:
page_size = scanned_assets_qs.count()
paginator = Paginator(scanned_assets_qs, page_size)
Then you can pass in an arbitrary page_size, and a -1 for a view all page (I would do that with the appropriate urls, plus a url for /viewall/ that passes in -1 no matter what)

Categories