Django redirect inside a function - python

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)
# ^^^^

Related

How can I use __init__() in python django

Good day, I have the following problem that I'm trying to resolve. What I need to achieve is having the patient id generated as i run the app and print it. But it is not doing what I want. I want each time that I will run the app, and calling the view, a new id as to get generated and printed for now.
Here's a class that I have created to generate the id:
import uuid
class PatientId:
def __init__(self, id_number):
self.id_number = id_number
#staticmethod
def generate_patient_id_number():
prefix = 'HSCM'
generated_id = str(uuid.uuid4().hex[:6].upper())
return '%s-%s' % (prefix, generated_id)
and in my views.py,
from utilities.id_number import PatientId
# Create your views here.
def show_id(request, self):
id = PatientId(self).generate_patient_id_number()
print(id)
return render(request, 'index.html', {})
Will appreciate any help
Not sure why you have PatientId as a class, but with that given class you can use it like this, since generate_patient_id_number() is a static method
id = PatientId.generate_patient_id_number()
# id is e.g. 'HSCM-E9E10C'
You don't need a class for this
In Python you don't need to make everything into a class, so if you had a module called id_number you can simply put that function there (and then you can use it from anywhere, a view, a class, a Django model, etc)
# id_number.py
def generate_patient_id_number():
prefix = 'HSCM'
generated_id = str(uuid.uuid4().hex[:6].upper())
return '%s-%s' % (prefix, generated_id)
and use it like this
from utilities import id_number
def show_id(request):
id = id_number.generate_patient_id_number()
print(id)
return render(request, 'index.html', {})

Django forms initial value user_full_name

Is the any solution to get django's user_full_name as a initial value for form? My idea was to display a django's form on the end of shopping to finish a order. I want also do put into a form total value, but this is for later.
I did something like this:
user_dane = request.user.get_full_name
koszyk = request.session.get('koszyk', [])
produkty = list(Produkt.objects.filter(pk__in=koszyk))
suma_cen = Produkt.objects.filter(pk__in=koszyk).aggregate(suma=Sum('cena'))
suma_wszystkich_cen = suma_cen['suma']
form=ZamowienieForm(initial={'imie_nazwisko':user_dane, 'kwota_do_zaplaty':suma_wszystkich_cen})
but this is working only when request.method is POST.
if request.method =='POST':
form = ZamowienieForm()
According to documentation I shouldn't initial a empty form with POST... Is there any chance to have a user full name into a form?
Here is the form class:
class ZamowienieForm(forms.ModelForm):
class Meta:
model = Zamowienie
fields = ('imie_nazwisko', 'kwota_do_zaplaty', 'miejscowosc',
'ulica','numer_domu', 'numer_mi‌​eszkania', 'kod_pocztowy',)
class NewMeta:
readonly = ('imie_nazwisko','kwota_do_zaplaty',)
Maybe try something like this inside ZamowienieForm class
def __init__(self, *args, **kwargs):
super(ZamowienieForm, self).__init__(*args, **kwargs)
self.fields['imie_nazwisko'] = self.initial.get('imie_nazwisko')
self.fields['kwota_do_zaplaty'] = self.initial.get('kwota_do_zaplaty')
Although I don't understand why "initial" is not working out of the box
In this case, you only need to initialize your form once, and not inside a conditional check if the request is a GET or POST:
def your_view(request):
form = ZamowienieForm(
request.POST or None,
initial={'imie_nazwisko': request.user.get_full_name(),
'kwota_do_zaplaty': suma_wszystkich_cen}
)
if request.method == 'POST' and form.is_valid():
# do whatever
This way you are always passing in the initial value, and if request.method == 'GET', then None is passed as the first positional argument to the form.
Also, user.get_full_name is an instance method, not a property, so using request.user.get_full_name only returns the bound method, not the actual value. You have have to call the function using ()
Finally, this will only work for users that are authenticated. The anonymous user object in Django won't return any user-specific information.

change url title if id changes - django

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.

Using request in django model

I've got 2 models
class Post(models.Model):
user = models.ForeignKey(User, verbose_name='User')
content = models.TextField(verbose_name='Text', max_length=4000)
date = models.DateTimeField(verbose_name='Date', default=now())
class Vote(models.Model):
vote = models.IntegerField(choices=VOTE, verbose_name='Vote')
post = models.ForeignKey(Post, verbose_name='Post')
user = models.ForeignKey(User, verbose_name='User')
and view which load last 15 posts:
posts = Post.objects.all().order_by('-date')[:15]
Now I want to have information about active user vote in all of my queryset objects
I thought about custom method in Post model which will check logged user and get vote objects:
def user_vote(self):
try:
data = Vote.objects.filter(post=self, user=request.user)
return data.vote
except ObjectDoesNotExist:
#not voted
But it seems django dont allow to use request in model.
Any other ideas?
You can pass user as argument to method like this:
def user_vote(self, user):
also I guess you need to get a Vote instance, not queryset, so you should user .get method instead .filter:
def user_vote(self, user):
try:
data = Vote.objects.get(post=self, user=user)
return data.vote
except ObjectDoesNotExist:
#not voted
then you can call this method with Post instance:
post.user_vote(request.user)
UPDATE
Django not allow to use method with arguments in template. So in your case better to refactor this method into templatetag:
def get_user_vote(post, user):
try:
data = Vote.objects.get(post=post, user=user)
return data.vote
except ObjectDoesNotExist:
#not voted
You can find manual here https://stackoverflow.com/a/6493001/3291969
don't forget to register it :)
That's not a django problem, it's because request isn't anywhere in the scope of your code. If you pass request to your model's method it will work. Something like:
def user_vote(self, request):
try:
data = Vote.objects.get(post=self, user=request.user)
return data.vote
except Vote.DoesNotExist:
#not voted
and call it like this with your Post instance:
# Note the request being passed as a parameter
vote = post.user_vote(request)
UPDATE:
To get all votes from a user you could do something like this:
votes = Vote.objects.filter(post=self, user=request.user)
return reduce(lambda x, y: x.vote + y.vote, votes, 0)
we set a 0 at the end, so in cases where there's no votes from this user, we'll get a 0 as a return.
This will sum every vote and return it.
If you don't want to sum these votes, change the line:
return reduce(lambda x, y: x.vote + y.vote, votes, 0)
to:
return map(lambda x, y: x.vote + y.vote, votes)
and this will get you a list with all the votes from the request.user user
I think you're looking for this package:
https://pypi.python.org/pypi/django-crequest/1.0
Description:
crequest will bring you current request object of your django application from anywhere in your code.
And it is used like this:
from crequest.middleware import CrequestMiddleware
current_request = CrequestMiddleware.get_request()

Django Call Class based view from another class based view

i am trying to call a class based view and i am able to do it, but for some reason i am not getting the context of the new class that i am calling
class ShowAppsView(LoginRequiredMixin, CurrentUserIdMixin, TemplateView):
template_name = "accounts/thing.html"
#method_decorator(csrf_exempt)
def dispatch(self, *args, **kwargs):
return super(ShowAppsView, self).dispatch(*args, **kwargs)
def get(self, request, username, **kwargs):
u = get_object_or_404(User, pk=self.current_user_id(request))
if u.username == username:
cities_list=City.objects.filter(user_id__exact=self.current_user_id(request)).order_by('-kms')
allcategories = Category.objects.all()
allcities = City.objects.all()
rating_list = Rating.objects.filter(user=u)
totalMiles = 0
for city in cities_list:
totalMiles = totalMiles + city.kms
return self.render_to_response({'totalMiles': totalMiles , 'cities_list':cities_list,'rating_list':rating_list,'allcities' : allcities, 'allcategories':allcategories})
class ManageAppView(LoginRequiredMixin, CheckTokenMixin, CurrentUserIdMixin,TemplateView):
template_name = "accounts/thing.html"
def compute_context(self, request, username):
#some logic here
if u.username == username:
if request.GET.get('action') == 'delete':
#some logic here and then:
ShowAppsView.as_view()(request,username)
What am i doing wrong guys?
Instead of
ShowAppsView.as_view()(self.request)
I had to do this
return ShowAppsView.as_view()(self.request)
Things get more complicated when you start using multiple inheritance in python so you could easily be trampling your context with that from an inherited mixin.
You don't quite say which context you are getting and which one you want (you're not defining a new context), so it's difficult to completely diagnose, but try rearranging the order of your mixins;
class ShowAppsView(LoginRequiredMixin, CurrentUserIdMixin, TemplateView):
this implies that LoginRequiredMixin will be the first class to inherit from, and so it will take precedence over the others if it has the attribute you're looking for - if it hasn't then python will look in CurrentUserIdMixin and so on.
If you want to be really sure that you get the context that you're after, you could add an override like
def get_context(self, request):
super(<my desired context mixin>), self).get_context(request)
to ensure that the context you get is the one from the mixin that you want.
* Edit *
I don't know where you've found compute_context but it's not a django attribute so will only get called from ShowAppsView.get() and never in ManageAppView.

Categories

Resources