I am working on a site currently (first one solo) and went to go make an index page. I have been attempting to follow django best practices as I go, so naturally I go search for this but couldn't a real standard in regards to this.
I have seen folks creating apps to serve this purpose named various things (main, home, misc) and have seen a views.py in the root of the project. I am really just looking for what the majority out there do for this.
The index page is not static, since I want to detect if the user is logged in and such.
Thanks.
If all of your dynamic content is handled in the template (for example, if it's just simple checking if a user is present on the request), then I recommend using a generic view, specificially the direct to template view:
urlpatterns = patterns('django.views.generic.simple',
(r'^$', 'direct_to_template', {'template': 'index.html'}),
)
If you want to add a few more bits of information to the template context, there is another argument, extra_context, that you can pass to the generic view to include it:
extra_context = {
'foo': 'bar',
# etc
}
urlpatterns = patterns('django.views.generic.simple',
(r'^$', 'direct_to_template', {'template': 'index.html', 'extra_context': extra_context }),
)
I tend to create a views.py in the root of the project where I keep the index view.
Related
I'm using django-hosts package to manage content that's supposed to be set in various different subdomains. I started by making a view in which a form is used to change something. Once the form is validated and processed, user is supposed to be redirected to some other page. Looking through documentation there's an easy way to render():
settings_url = reverse('settings', host='dashboard')
return render(request, 'dashboard/settings.html', {'settings_url': settings_url})
However, there's no mention of redirect(). So how would I go about redirecting to somewhere else, instead of the usual return redirect("dashboard:settings")
myapp/hosts.py :
host_patterns = patterns('',
host(r'www', settings.ROOT_URLCONF, name='www'),
host(r'dashboard\.myapp\.com', 'dashboard.urls', name='dashboard'),
)
dashboard/urls.py
from .views import home, websitesettings
urlpatterns = [
url(r'^$', home, name='home'),
url(r'^settings/$', websitesettings, name='settings'),
]
Basically all I want is to redirect back to the same page after form is submitted (in the render example, I'm submitting a form to change certain website settings, which is a model on it's own, and then I want to redirect back to the same page after that).
Well took couple of different and convoluted tries, only to take a night off and come up with a solution that's ironically easy. Use of dajngos native redirect with django-hosts reverse function and it works like a charm:
from django_hosts.resolvers import reverse
return redirect(reverse('home', host='dashboard'))
I am trying to forward projects/1 to the view, for purpose of getting the project based on the id.
I have tried to change the regex, and the name.
Edit: But the issue is:
The id doesn't get forwarded (Or atleast not correctly) to the views, which results in the filter failing to find the Project based on the id.
Urls related to the 'Project':
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^project/(?P<project_id>([0-9]+))$', views.project, name='project'),
]
The view for the 'Project':
def project(request, project_id=1):
template = loader.get_template("project.html")
context = {
'project': Project.objects.filter(project_id=project_id)
}
return HttpResponse(template.render(context, request))
The regex seem a little incorrect to me, especially parentheses. Try this:
url(r'^project/(?P<project_id>[0-9]+)/$', views.project, name='project'),
UPDATE:
So you want to show only one project instead of several. In that case, change Project.objects.filter to Project.objects.get in your view.
Also, try this awesome django tutorial to learn the basics
Hope it helps.
I'd like to run two apps with the same url patterns. I would like to avoid having an app-specific slug like domain.com/pages/something-here or domain.com/blog/something-there.
I tried this:
# urls.py
urlpatterns = patterns('',
url(r'^$', 'my.homepage.view'),
url(r'^admin/', include(admin.site.urls)),
url(r'^', include('pages.urls')),
url(r'^', include('blog.urls')),
)
# pages/urls.py
urlpatterns = patterns('',
url(r'^(.+)/$', views.page),
)
# blog/urls.py
urlpatterns = patterns('',
url(r'^(.+)/$', views.post),
)
My code doesn't work, whichever include comes first (here, pages.urls) works ok, other urls (for blog) throw 404.
Thanks in advance
EDIT: I did it like this: created glue.py in the same directory as settings.py. It will handle my homepage and this dispatcher view:
def dispatcher(request, slug):
try:
page = get_object_or_404(Page, slug=slug)
return render(request, 'pages/page.html', {'page': page})
except:
post = get_object_or_404(Post, slug=slug)
return render(request, 'blog/post.html', {'post': post})
I don't know if it's ok. I hope there is a better way.
Thanks for the comments.
I don't know if this is a better answer. But, if these situations are satisfied for you..
if your django app is based on django template rendering.
The url you are talking about, need not be accessed directly by typing the endpoint in the browser itself.
Then, maybe you could consider url namespaces and template redirections.
https://docs.djangoproject.com/en/1.11/topics/http/urls/#url-namespaces
This doesn't work because django urls are resolved in order, meaning that the first url that matches the regexp will be the resolved one. In your case, the the urls included from the blogs application will never be searched, as django already resolved the url on the pages includes line.
Also, the django url module is not supposed to know if a certain page or blog post exists, as i believe in your application this is determined with a database lookup.
The urls module just executes the view that is connected to the first regexp that matches.
You should change your logic, e.g. with perpending "blog/" to blog urls (what's wrong with that?)
url(r'^blog/', include('blog.urls')),
url(r'^', include('pages.urls')),
Notice that the i moved the blog url up, as most generic regxexp should always be the last to be tried by django url resolver.
Alternatively, you could code a proxy view that tries both blog posts and pages. but it doesn't seem the best way to do it to me.
How would you like this to work? They're both using the same URL (which of course is causing problems). How would a user get to a "page" rather than a "blog" or vice versa?
In general, you can't have overlapping URLs in your URL patterns (without including additional data).
EDIT:
So you want the first app to check if it has a view to match the URL and next to take over if the first doesn't? You could do something complicated like writing a "view matcher" to do want you want, but there are much more straigtforward solutions.
The easiest way would be to alter the slug generation function for one of your apps. Have one use some delimeter other than underscores, or always append the name of the app to the slug. This way you could find pages because their url would be "some-slug-page" and blogs would be "some-slug-blog", which you could then write a URL pattern for. If you don't want to add the entire URL, you can append/prepend just the first letter, or whatever you want.
Just think about a way that's acceptable to you to generate URLs for each app which, just by reading the URL, lets you know which app the page belongs to.
I need to make a very simple modification -- require that certain views only show up when a user is not authenticated -- to django-registration default views. For example, if I am logged in, I don't want users to be able to visit the /register page again.
So, I think the idea here is that I want to subclass the register view from django-registration. This is just where I'm not sure how to proceed. Is this the right direction? Should I test the user's authentication status here? Tips and advice welcomed!
Edit
I think this is the right track here: Django: Redirect logged in users from login page
Edit 2
Solution:
Create another app, for example, custom_registration, and write a view like this (mine uses a custom form as well):
from registration.views import register
from custom_registration.forms import EduRegistrationForm
def register_test(request, success_url=None,
form_class=EduRegistrationForm, profile_callback=None,
template_name='registration/registration_form.html',
extra_context=None):
if request.user.is_authenticated():
return HttpResponseRedirect('/')
else:
return register(request, success_url, form_class, profile_callback, template_name, extra_context)
I had to use the same function parameters, but otherwise just include the test, and if we pass it, continue to the main function.
Don't forget to put this in your URLConf either (again, this includes some stuff about my custom form as well):
top-level URLConf
(r'^accounts/', include('custom_registration.urls')),
(r'^accounts/', include('registration.urls')),
custom_registration.views
from django.conf.urls.defaults import *
from custom_registration.views import register_test
from custom_registration.forms import EduRegistrationForm
urlpatterns = patterns('',
url(r'^register/$', register_test, {'form_class': EduRegistrationForm}, name='registration.views.register'),
)
As far as I remember django-registration is using function-based views, so you can not really subclass them. The approach I usually follow is "overwriting" the original views (without modifying the django-registration app of course). This works like this:
Create another app (you could call it custom_registration or whatever you want)
This app need to contain another urls.py and in your case another views.py
Copy the original register view code to your new views.py and modify it, add a pattern to your urls.py to point to this view (use the same url pattern as in django-registration for this view)
Put an include to your projects urls.py of your new app urls.py before your are including the original django-registration app. This could look like this for example:
urlpatterns = patterns('',
...
url(r'^accounts/', include('custom_registration.urls')),
url(r'^accounts/', include('registration.backends.default.urls')),
...
)
This simply works since the first matching url pattern for /accounts/register will point to your new app, so it will never try to call the one from the original app.
I've building a app right now that I'm trying to keep properly decoupled from the other apps in my Django project (feel free to lecture me on keeping Django apps decoupled, I'd be happy to learn more any/all the time).
My problem is this: The get_ absolute_url() method I've written is returning a relative path based on my view. I think it's wrong to have to add a special named view in the project urls.py just so I can have absolute urls in my app, and I can't figure out what I'm doing wrong. So if someone can help me out, I'll really appreciate it (and mention you when I release this sucker!)
I have a project-level urls.py that includes another urls.py based on the URL pattern like so (the names are verbose for this example only):
project-urls.py
urlpatterns = patterns('',
('^$', direct_to_template, {'template': 'base.html'}),
(r'^app', include('project.app.urls')),
)
app-urls.py
urlpatterns = patterns('',
url(r'(?P<slug>[-\w]+)?/?$', 'app.views.home', name='app_home'),
)
Now, in my Model, I have something like this:
class AppModel(models.Model):
title = models.CharField(_('title'), max_length=100)
slug = models.SlugField(_('slug'), unique=True)
#permalink
def get_absolute_url(self):
return ('app_home', None, {'slug': self.slug})
When I call {{ AppInstance.get_ absolute_url }} in the template, I get something like this:
/slug-is-here
Which is obvs not absolute & makes sense based on my urls.py. What should I change to get a real absolute url while keeping this app clean & not couple it too deeply w/the project?
Welp,
It turns out that when I was seeing this:
/slug-is-here
I should have looked closer. What was really happening was:
/app-pathslug-is-here
I was missing a trailing slash on my app's regex in my project urls.py.
So yea. let that be a lesson to y'all.