change url title if id changes - django - python

I have
def newsprofile(request, newstitle, newsid):
newsobj = get_object_or_404(NewsModel, pk=int(newsid))
return render(request, 'newsprofile.html', {'newsobj': newsobj})
but now, if I change the id 1 to 2 in url inside adressbar and hit the enter button e.g. /sometitle_and_and_blabla/1/,
i will get another news but the title doesnot change, it only becomes like:
/sometitle_and_and_blabla/2/
How can I change the title also if id changes?
the urls.py looks like this:
url(r'^news/(?P<newstitle>[^\/]*)/(?P<newsid>\d+)/$', 'newsprofile', name='newsprofile'),

Try like this,
def newsprofile(request, newstitle, newsid):
newsobj = get_object_or_404(NewsModel, pk=int(newsid))
if newstitle != newsobj.newstitle:
return HttpResponsePermanentRedirect('/%s/%s/' % (newsobj.newstitle, newsid))
.....

As you are using named urls (e.g. newsprofile) I recommend the following solution. This is flexible and easy to maintain, even if your urls change as long as you use the same url parameters:
from django.http import HttpResponseRedirect
...
def newsprofile(request, newstitle, newsid):
newsobj = get_object_or_404(NewsModel, pk=int(newsid))
if newsobj.newstitle != newstitle:
return HttpResponseRedirect(reverse("newsprofile", args=[newstitle, newsid]))
return render(request, 'newsprofile.html', {'newsobj': newsobj})
See Django docs here for reverse resolution of URLs.

Related

How to use while loop for showing more items in Django view?

I am making a small Django project, but I have an issue. When I write names to one form and topics to other one and press button, I want to see list of randomly attached names and topics. In my current code I don´t get a list but just one name and one topic. How can I solve that problem?
My views.py file:
from django.shortcuts import render
from .losovaci_zarizeni import UvodniTabulka
from random import choice
def losovani_view(request):
form = UvodniTabulka(request.GET)
spoluzaci = request.GET.get("spoluzaci")
temata = request.GET.get("temata")
spoluzaci_list = spoluzaci.split()
temata_list = temata.split()
while True:
spoluzak = choice(spoluzaci_list)
spoluzaci_list.remove(spoluzak)
tema = choice(temata_list)
temata_list.remove(tema)
if len(spoluzaci_list)==0:
break
return render(request, "losovani.html", {"form":form, "spoluzak": spoluzak, "tema":tema})
My file with UvodniTabulka:
from django import forms
class UvodniTabulka(forms.Form):
spoluzaci = forms.CharField(max_length=500)
temata = forms.CharField(max_length=500)

How to create a custom generic view from a web2py RESTFUL service?

Using Web2Py RESTFUL services, I'd like the following html to render in the browser after navigating to this link (http://127.0.0.1:8000/app/default/api/example_data.html_table/?limit=1):
<div><table><thead><tr><th>example_data.id</th><th>example_data.Firstname</th><th>example_data.Lastname</th><th>example_data.Age</th></tr></thead><tbody><tr class="w2p_odd odd"><td>1</td><td>SUUUUPPPEEEERRRR LONGGGGG FIRSTTTT NAMEEEE</td><td>Smith</td><td>1</td></tr></tbody></table></div>
However, I currently receive the following:
<div><table><thead><tr><th>example_data.id</th><th>example_data.Firstname</th><th>example_data.Lastname</th><th>example_data.Age</th></tr></thead><tbody><tr class="w2p_odd odd"><td>1</td><td>SUUUUPPPEEEER...</td><td>Smith</td><td>1</td></tr></tbody></table></div>
The difference is that Web2Py is shortening "SUUUUPPPEEEERRRR LONGGGGG FIRSTTTT NAMEEEE" to "SUUUUPPPEEEER..." but I need the entire text
My View called generic.html_table that generates this is the following:
{{=BEAUTIFY(response._vars[next(iter(response._vars))])}}
Controller
#request.restful()
def api():
response.view = 'generic.' + request.extension
def GET(*args,**vars):
patterns = 'auto'
parser = db.parse_as_rest(patterns,args,vars)
return dict(content=parser.response)
def POST(table_name,**vars):
if 'id' in vars.keys():
return db[table_name].update_or_insert(db[table_name]._id == vars['id'],**vars)
else:
return db[table_name].validate_and_insert(**vars)
def PUT(table_name,**vars):
record_id = vars['id']
return db(db[table_name]._id==record_id).update(**vars)
def DELETE(table_name,record_id):
return db(db[table_name]._id==record_id).delete()
return dict(GET=GET, POST=POST, PUT=PUT, DELETE=DELETE)
MODEL
db.define_table('example_data', Field('Firstname', 'string'),Field('Lastname', 'string'),Field('Age', 'integer'))
I've also tried the following views:
{{=response._vars[next(iter(response._vars))]}}
RESULT (first name still cut off):
<table><thead><tr><th>example_data.id</th><th>example_data.Firstname</th><th>example_data.Lastname</th><th>example_data.Age</th></tr></thead><tbody><tr class="w2p_odd odd"><td>1</td><td>Jill</td><td>Smith</td><td>1</td></tr><tr class="w2p_even even"><td>2</td><td>Eve</td><td>Jackson</td><td>33</td></tr><tr class="w2p_odd odd"><td>3</td><td>afdaskfdlasjf...</td><td>Jackson</td><td>33</td></tr><tr class="w2p_even even"><td>4</td><td>SUUUUPPPEEEER...</td><td>Jackson</td><td>33</td></tr></tbody></table>
I've also tried the following views:
{{=XML(response._vars[next(iter(response._vars))])}}
RESULT (Lost all HTML formatting):
example_data.id,example_data.Firstname,example_data.Lastname,example_data.Age
1,Jill,Smith,1
2,Eve,Jackson,33
3,afdaskfdlasjfkdlsjfklajdfskasjfklsdajfdklsajfklsajfdskalfdjsakldfjklasfjkdlsajfdsakljdklsadcjklasjcklsjackldsjakfldajsfklasdfjklasjfdklajfdsklsjafkldasjfkldasjkldsjcklajsckljackldajsdfklfjkalsncklacnkalsdfjkldasnckldasjckljsdaklfdnfkldsajfdklasjldsk,Jackson,33
4,SUUUUPPPEEEERRRR LONGGGGG FIRSTTTT NAMEEEE,Jackson,33
All of those methods ultimately result in the DAL Rows object being passed to SQLTABLE for rendering in the view. By default, fields are truncated to 16 characters. If you want to change that, you will have to call SQLTABLE explicitly:
{{=SQLTABLE(content, truncate=100)}}

Django redirect inside a function

I am trying to build forum. When processing urls there is a board id and a board name. The board name exists just for user readability meaning if someone enters the id correctly but the board name is wrong or has changed it will redirect them to the correct url. I created a function to manage this because there are multiple times I need to check if the board is right, not just this one url.
# urls.py
...
url(r'^boards/(?P<board_id>\d+)/(?P<board_name>[^/]+)/$', views.board, name='board'),
...
# views.py
def board(request, board_id, board_name):
RedirectIfWrong(request, board_id, board_name)
...
return render(request, 'forums/board.html', {'board': board})
def RedirectIfWrong(request, pk, name):
board = Board.objects.all().get(pk=pk)
if (board.name != name):
return redirect(request.get_full_path().replace(name, board.name, 1))
However when I call redirect inside a function it does not work. I have also heard of using middleware to do this. How does that work and how do I make it only apply to urls involving a board?
def board(request, board_id, board_name):
bad = RedirectIfWrong(request, board_id, board_name)
if bad:
return bad
...
return render(request, 'forums/board.html', {'board': board})
Add the return
def board(request, board_id, board_name):
return RedirectIfWrong(request, board_id, board_name)
# ^^^^

Views in Django with arbitrary number of url parameters

I want to write universal View with Django, in this function i want to handle several situations: first when i have url like vkusers3/11122233/1/2/ and also i want it working when 2 or third arguments is missing in url, like: vkusers3/11122233/ or vkusers3/11122233/1/
I cannot find it tutorials how to do that (https://docs.djangoproject.com/en/1.6/topics/http/urls/ etc).
The problem that this became a nightmare when you have more than 5 combinations in url parameters, then you should write 5 different url configurations, 5 times in html template hardcode this pattern.
BUT wait, even more!, what about combinatorics: i want /user/group/sex/smoking/ but also i want /user/group/smoking/ i.e. all users from group who is smoking of both man and woman. So the number is huge.
def list_groupmembers_sex(request, group_id, sex=None, smoking=None):
success = False
if group_id and sex and smoking==None:
vkusers = Vkuser._get_collection().find({"member_of_group": int(group_id), 'sex': int(sex)})# 62740364 81099158
success = True
elif group_id and sex and smoking!=None:
vkusers = Vkuser._get_collection().find({"member_of_group": int(group_id), 'sex': int(sex), 'personal.smoking': int(smoking)})
success = True
else:
vkusers = Vkuser._get_collection().find({'personal.smoking': 1})
ctx = {'vkuser_list': vkusers, 'group_id': group_id, 'sex': sex, 'smoking':smoking, 'success': success}
return render_to_response('blog/vkuser_list.html', ctx, context_instance = RequestContext(request))
In my urls.py:
url(r'^vkusers3/(\d{1,8})/(\d{1})/(\d{1})/$', 'blog.views.list_groupmembers_sex', name='vkuser-list3'),
In my base.html:
<li class="menu-level-1">users</li>
Django 1.6.10, MongoDB 2.7.1, mongoengine
At this point, you should probably bite the bullet and just go for query parameters - vkusers3/?sex=1&smoking=2&group= 11122233. You can drop the parameters completely from the URL and the view definition, and just use request.GET['sex'] etc in the view body.
You don't need so hairy logic. Just populate the search critera with arguments passed to the view like this:
criteria = {}
if group_id:
criteria['member_of_group'] = int(group_id)
if sex:
criteria['sex'] = int(sex)
if smoking:
criteria['personal.smoking'] = int(smoking)
vkusers = Vkuser._get_collection().find(criteria)
And yes, consider to switch to the regular GET parameters like #daniel-roseman suggested. With urls like in your question you can't determine the /user/group/sex/ url from the /user/group/smoking/.
UPDATE: request.GET is a dict-like object so you can use the in expression:
if 'sex' in request.GET:
criteria['sex'] = int(request.GET['sex'])

How to get the label of a choice in a Django forms ChoiceField?

I have a ChoiceField, now how do I get the label when I need it?
class ContactForm(forms.Form):
reason = forms.ChoiceField(choices=[("feature", "A feature"),
("order", "An order")],
widget=forms.RadioSelect)
form.cleaned_data["reason"] only gives me the feature or order values or so.
See the docs on Model.get_FOO_display(). So, should be something like :
ContactForm.get_reason_display()
In a template, use like this:
{{ OBJNAME.get_FIELDNAME_display }}
This may help:
reason = form.cleaned_data['reason']
reason = dict(form.fields['reason'].choices)[reason]
This the easiest way to do this: Model instance reference: Model.get_FOO_display()
You can use this function which will return the display name: ObjectName.get_FieldName_display()
Replace ObjectName with your class name and FieldName with the field of which you need to fetch the display name of.
If the form instance is bound, you can use
chosen_label = form.instance.get_FOO_display()
Here is a way I came up with. There may be an easier way. I tested it using python manage.py shell:
>>> cf = ContactForm({'reason': 'feature'})
>>> cf.is_valid()
True
>>> cf.fields['reason'].choices
[('feature', 'A feature')]
>>> for val in cf.fields['reason'].choices:
... if val[0] == cf.cleaned_data['reason']:
... print val[1]
... break
...
A feature
Note: This probably isn't very Pythonic, but it demonstrates where the data you need can be found.
You can have your form like this:
#forms.py
CHOICES = [('feature', "A feature"), ("order", "An order")]
class ContactForm(forms.Form):
reason = forms.ChoiceField(choices=CHOICES,
widget=forms.RadioSelect)
Then this would give you what you want:
reason = dict(CHOICES)[form.cleaned_data["reason"]]
OK. I know this is very old post, but reading it helped me a lot. And I think I have something to add.
The crux of the matter here is that the the model method.
ObjectName.get_FieldName_display()
does not work for forms.
If you have a form, that is not based on a model and that form has a choice field, how do you get the display value of a given choice.
Here is some code that might help you.
You can use this code to get the display value of a choice field from a posted form.
display_of_choice = dict(dateform.fields['fieldnane'].choices)[int(request.POST.get('fieldname'))]
the 'int' is there on the basis the choice selection was a integer. If the choice index was a string then you just remove the int(...)
Im using #Andrés Torres Marroquín way, and I want share my implementation.
GOOD_CATEGORY_CHOICES = (
('paper', 'this is paper'),
('glass', 'this is glass'),
...
)
class Good(models.Model):
...
good_category = models.CharField(max_length=255, null=True, blank=False)
....
class GoodForm(ModelForm):
class Meta:
model = Good
...
good_category = forms.ChoiceField(required=True, choices=GOOD_CATEGORY_CHOICES)
...
def clean_good_category(self):
value = self.cleaned_data.get('good_category')
return dict(self.fields['good_category'].choices)[value]
And the result is this is paper instead of paper.
Hope this help
I think maybe #webjunkie is right.
If you're reading from the form from a POST then you would do
def contact_view(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
contact = form.save()
contact.reason = form.cleaned_data['reason']
contact.save()
confirm that Ardi's and Paul's response are best for forms and not models. Generalizing Ardi's to any parameter:
class AnyForm(forms.Form):
def get_field_name_display(self, field_name):
return dict(self.fields[field_name].choices[self.cleaned_data[field_name]]
Or put this method in a separate class, and sub-class it in your form
class ChoiceFieldDisplayMixin:
def get_field_name_display(self, field_name):
return dict(self.fields[field_name].choices[self.cleaned_data[field_name]]
class AnyCustomForm(forms.Form, ChoiceFieldDisplayMixin):
choice_field_form = forms.ChoiceField(choices=[...])
Now call the same method for any Choice Field:
form_instance = AnyCustomForm()
form_instance.is_valid()
form_instance.get_field_name_display('choice_field_form')

Categories

Resources