So, I've read around here and elsewhere, and I've seen people load different html templates, or do something in the template itself to change what is displayed, but what I am wanting to do is load a different view or form based on an element in the user profile.
My urls.py looks something like this:
urlpatterns = patterns('',
url(r'^$', MySearchView(
searchqueryset=sqs,
form_class=BasicPropertySearchForm
), name="haystack_search"),
)
I can set the line
form_class=
to either BasicPropertySearchForm or PaidPropertySearchForm manually, and the corresponding search page will load properly and function, no problem.
But what I'd like to do is have the form_class automated so it loads BasicPropertySearchForm or PaidPropertySearchForm based on the user profile.
I tried accomplishing this with request.user.get_profile() in the view like this:
class MySearchView(SearchView):
#extends the default haystack SearchView
def which_view(self):
if self.request.user.get_profile().is_paid:
return PaidPropertySearchForm
else:
return BasicPropertySearchForm
and changing
form_class=MySearchView().which_view
but that results in the error
which_view() takes exactly 1 argument (4 given)
I have tried many other variations including using a method that's not within a class in the views.py, doing the if statment in the urls.py (which i realized wouldn't work since I'm imagining I have to access the request.user.get_profile() from withing a view)...
I also tried doing this:
urls.py:
urlpatterns = patterns('',
url(r'^$', 'property_listings.views.search_views', name="haystack_search"),
)
and views.py:
def search_views(request, *args, **kwargs):
sqs = SearchQuerySet().all
if request.user.get_profile().is_paid:
return SearchView(
searchqueryset=sqs,
form_class=PaidPropertySearchForm
)(request, *args, **kwargs)
else:
return SearchView(
searchqueryset=sqs,
form_class=BasicPropertySearchForm
)(request, *args, **kwargs)
but then my forms gave me all sorts of errors about stuff not being defined, like self.searchqueryset.all() all does not exist for that or something or another..
Any help would be appreciated, I must've read 50 different blogs, doc pages, stack overflow posts, etc. over the last few days and I'm banging my head against a wall here..
Related
This is a view for get all the records in the EducationalRecord model:
def all_education_resume(request):
RESUME_INFO['view'] = 'education'
educations_resume = EducationalRecord.objects.all().order_by('-created_date')
template = 'resumes/all_resume.html'
context = {'educations_resume': educations_resume, 'resume_info': RESUME_INFO}
return render(request, template, context)
Now, if I want to write exactly this view for other models (like job resumes, research resumes , etc.),
I must another view one separately.
My question is:
How can I get a view for all these requests, so first check the URL of
the request and then do the relevant query? How can I control URL
requests in my views?
My other question is exactly the same as my first question,with this difference:
control view that must render in specific template.In other words,in
second question the ratio between the template and the view is instead
of the ratio of the view to the url or how to create a template for
multiple views (for example, for a variety of database resume
resumes, I have a template) and then, depending on which view render,
the template output is different.
I have implemented these two issues as follows:
I wrote a view for each of request!
In each view, I set the value of RESUME_INFO['view'], and then I've checked it in a template page and specified the corresponding template.
What is the best solution to these two questions?
How can I get a view for all these requests, so first check the URL of the request and then do the relevant query? How can I control URL requests in my views?
You can access request.path, or you can let the url(..)s pass a parameter with kwargs that holds a reference to the model for example, but this is usually bad design. Typically if you use different models, you will likely have to order these different as well, filter these differently, render these differently, etc. If not, then this typically indicates that something is wrong with the modeling.
You can however make use of class-based views [Django-doc], to remove as much boilerplate as posssible. Your view looks like a ListView [Django-doc], by using such view, and patching where necessary, we can omit most of the "boilerplate" code:
# app/views.py
from django.views.generic.list import ListView
class MyBaseListView(ListView):
resume_info = None
template = 'resumes/all_resume.html'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['resume_info'] = {'view': self.resume_info}
return context
In the individual listviews, you then only need to specify the resume_info and the model or queryset to render it with the 'all_resume.html' template, for example:
# app/views.py
# ...
class EducationalResumeView(MyBaseListView):
queryset = EducationalRecord.objects.order_by('-created_date')
resume_info = 'education'
class OtherModelView(MyBaseListView):
model = OtherModel
resume_info = 'other_info'
So we can here use inheritance to define common things only once, and use it in multiple views. In case we need to change something in a specific view, we can override it at that level.
In the urls.py, you define such view with the .as_view() method [Django-doc]. For example:
# app/urls.py
from django.urls import path
from app.views import EducationalResumeView, OtherModelView
urlpatterns = [
path('education/', EducationalResumeView.as_view()),
path('other/', OtherModelView.as_view()),
]
I am trying to make urls pattern to catch all urls from root.
my main urls.py is:
path('', (include('myapp.urls', namespace='app1')
I am using two url patterns in app1.urls:
re_path(r'^(?P<url_var1>[-\w./]+)/$', DetailView1.as_view(), name='DetailView1'),
re_path(r'^(?P<url_var2>[-\w./]+)/$', DetailView2.as_view(), name='DetailView2'),
My views.py file is as:
class DetailView1(View):
template_name = 'detail.html'
def get(self, request, url_var1):
obj1 = model1.objects.get(my_url=url_var1)
return render(request, self.template_name, {'obj1':obj1})
class DetailView2(View):
template_name = 'detail.html'
def get(self, request, url_var2):
obj2 = model2.objects.get(my_url=url_var2)
return render(request, self.template_name, {'obj2':obj2})
when i request url "/first-post/my-first-post/", It checks out the url which is in my "model1" under ther header "my_url" and return the page.
But when I request url "/second-post/my-second-post/", It checks out the url in "model1" and throws an error, as the url is in "model2" under header "my_url".
I know that the urlpattern follows a squence check, and stops at the pattern which matches the first urlpattern(DetailView1), thats why It is giving me this error.
I want to know is there a way I can override this behavior of urlpattern.
I have also tried reverse, when url is not found in DetailView1:
try:
obj1 = model1.objects.get(my_url=url_var1)
except:
return reverse('app1:DetailView2')
But Its still giving me an error.
If any of you got any other suggestions for catching urlpattern from root for mare than two type of urlpattern please tell me.
I am making a product cum blog website which has two models "model1" which is a product model, and "model2" which is a blog model. Now the "model1" is for automobile having 2 main categories "car" and "bike" and "model2" is having the same as "latest in cars" & "latest in bikes". For these categories I want to pick up urls from the root which have been given as "/cars/lexus.....", "/bike/ducati....". Also, there can be further additions of subfolder url and all urls have product IDs having "." and numbers. So is there is way i can pick urls frm root for both models using the above url pattern.
Its not possible to have multiple views and single urlpattern in Django.
Take a look at your views. They are almost the same. You should put the logic handling different url parameters in single view.
My advice would be also to carefully review your model design, it looks like you have two models that are essentially the same. I feel that this is the root of your problem.
Additionally I assume that you are trying to create some kind of blog.
Django had its beginning as framework powering news site. And it has some helpful tools. For example take a look at SlugField This may provide you with functionality you are looking for. Without over complicating the urlpatterns.
According to django docs:
class MyModelAdmin(admin.ModelAdmin):
def get_urls(self):
urls = super(MyModelAdmin, self).get_urls()
my_urls = [
url(r'^my_view/$', self.my_view),
]
return my_urls + urls
def my_view(self, request):
# ...
context = dict(
# Include common variables for rendering the admin template.
self.admin_site.each_context(request),
# Anything else you want in the context...
key=value,
)
return TemplateResponse(request, "sometemplate.html", context)
If I am not wrong, we can do the same thing by adding url in urls.py and the views in views.py as it is normally done then, what is the use of introducing this way? I am a newbie to django and I may be missing something here.
Can you please provide an example where we cannot do it in views.py and we must use the above method?
Any guidance/help would be appreciated.
I think I figured out, both of them can be used to do the same thing but the key difference is that the views which you write using above method will belong to admin app while the general views in views.py belongs to the particular app in you have written.
Hence, the url in ModelAdmin need to be called using name admin:url_name since the url goes as admin/my_views/ in given example.
When defining URL patterns, I am supposed to use a regular expression to acquire a PK from the URL.
What if I want a URL that has no PK, and if it's not provided, it will use the currently logged in user? Examples:
visiting /user will get a DetailView of the currently logged in user
/user/edit will show an UpdateView for the currently logged in user
I tried hard-coding the pk= in the Detail.as_view() call but it reports invalid keyword.
How do I specify that in the URL conf?
My sample code that shows PK required error when visiting /user URL:
urlpatterns = patterns('',
url(r'user/$',
DetailView.as_view(
model=Account,
template_name='user/detail.html')),
)`
An alternative approach would be overriding the get_object method of the DetailView subclass, something along the line of:
class CurrentUserDetailView(UserDetailView):
def get_object(self):
return self.request.user
Much cleaner, simpler and more in the spirit of the class-based views than the mixin approach.
EDIT: To clarify, I believe that two different URL patterns (i.e. one with a pk and the other without) should be defined separately in the urlconf. Therefore they could be served by two different views as well, especially as this makes the code cleaner. In this case the urlconf might look something like:
urlpatterns = patterns('',
url(r"^users/(?P<pk>\d+)/$", UserDetailView.as_view(), name="user_detail"),
url(r"^users/current/$", CurrentUserDetailView.as_view(), name="current_user_detail"),
url(r"^users/$", UserListView.as_view(), name="user_list"),
)
And I've updated my example above to note that it inherits the UserDetailView, which makes it even cleaner, and makes it clear what it really is: a special case of the parent view.
As far as I know, you can't define that on the URL definition, since you don't have access to that information.
However, what you can do is create your own mixin and use it to build views that behave like you want.
Your mixin would look something like this:
class CurrentUserMixin(object):
model = Account
def get_object(self, *args, **kwargs):
try:
obj = super(CurrentUserMixin, self).get_object(*args, **kwargs)
except AttributeError:
# SingleObjectMixin throws an AttributeError when no pk or slug
# is present on the url. In those cases, we use the current user
obj = self.request.user.account
return obj
and then, make your custom views:
class UserDetailView(CurrentUserMixin, DetailView):
pass
class UserUpdateView(CurrentUserMixin, UpdateView):
pass
Generic views uses always RequestContext. And this paragraph in the Django Documentation says that when using RequestContext with auth app, the template gets passed an user variable that represents current user logged in. So, go ahead, and feel free to reference user in your templates.
You can get the details of the current user from the request object. If you'd like to see a different user's details, you can pass the url as parameter. The url would be encoded like:
url(r'user/(?P<user_id>.*)$', 'views.user_details', name='user-details'),
views.user_details 2nd parameter would be user_id which is a string (you can change the regex in the url to restrict integer values, but the parameter would still of type string). Here's a list of other examples for url patterns from the Django documentation.
One of the objects I am managing in my django site will only ever have one instance in the database. I therefore want to change the list view to simply redirect to the 'edit' page for this first object.
So basically when you hit /admin/my_site/widgets I want to redirect to /admin/my_site/widget/1. I have tried a custom view, a custom template, etc, but I can't find an easy way of doing this (or any way of doing this for that matter).
It's almost like I want to do something like this (doesn't work because I can't figure out how to change the list view):
class WidgetAdmin(admin.ModelAdmin):
def list_view(self, request):
widget = Widget.objects.all()[0]
return HttpResponseRedirect('/admin/my_site/widget/%s' % widget.id)
I've also tried change the url's to match the list request and do a redirect there, but I can't seem to match the list request with anything other than a complete blanket regex, i.e. (r/^.*$/) which means I just get an infinite loop redirect.
I needed the same thing. I solved it slighty different using the changelist_view from ModelAdmin. Using your example it would look somthing like:
class MySingleEditAdmin(admin.ModelAdmin):
def changelist_view(self, request, extra_context=None):
object, created = self.get_my_object()
url = reverse('admin:%s_%s_change' %(object._meta.app_label, object._meta.module_name), args=[object.id] )
return HttpResponseRedirect(url)
class WidgetAdminAdmin(MySingleEditAdmin):
def get_my_object(self):
return Widget.objects.get_or_create(pk=1, ...default_data...)
Ok this is how I sorted it out.
class WidgetAdmin(admin.ModelAdmin):
def list_view(self, request):
widget = Widget.objects.all()[0]
return HttpResponseRedirect('/admin/my_site/widget/%s' % widget.id)
def get_urls(self):
from django.conf.urls.defaults import *
urls = super(WidgetAdmin, self).get_urls()
my_urls = patterns('',
(r'^$', admin.site.admin_view(self.list_view))
)
return my_urls + urls