Django: Get base URL for sending links in email - python

I have a django app myapp, which registers a menu-command foo to be called via ./manage.py foo.
The command should send a reminder email to all users. The mail contains a link in it, to a specific view, lets say bar. bar has the this entry in the urls.py:
url(r'^(?P<id>\d+)/$', views.bar, name='bar'),
How do I correctly determine the absolute url in this context?
The relative url would be reverse('myapp:bar'). But how do I get the base to that?
I could just hardcode it in settings.py of my project, but that would go against the philosophy of django, wouldn't it?

Related

Changing Site Name in Django 1.9

I am currently following a tutorial which introduces a custom Bootstrap 3 template and builds a Django site using it. In the tutorial they suggest that one changes the following template snippet:
<a class="navbar-brand" href="index.html">Start Bootstrap</a>
to the following snippet.
<a class="navbar-brand" href="/">{{ request.site.name }}</a>
However, when I make this change, no site name shows. I am wondering where I should be setting this name. If it helps, I am using Django CMS and there is only one site called example.compopulated in the Sites section of the Administration.
Had the same problem, found this in the documentation.
If you often use this pattern:
from django.contrib.sites.models import Site
def my_view(request):
site = Site.objects.get_current()
... there is simple way to avoid repetitions. Add django.contrib.sites.middleware.CurrentSiteMiddleware to MIDDLEWARE_CLASSES. The middleware sets the site attribute on every request object, so you can use request.site to get the current site.
You can add site name or change existing site called example.com in the Sites section of the Administration.
To access Site object you need to provide SITE_ID in your settings.py
If you are changing example.com then use SITE_ID = 1 in settings
To render site name in django templates, get value from site model using
from django.contrib.sites.models import Site
current_domain = Site.objects.get_current().domain
then pass current_domain to template
It seems that you have to enable the sites framework, refer to doc.
first yo have to understand that in the setting you have a site_id set to 1 and in database migrations an example site with domain name example.com is created. So, you have two options:
You can change this default from django site models like this: python manage.py shell -c "from django.contrib.sites.models import Site; Site.objects.filter(domain='example.com').update(name='My Site', domain='mysite.tld')" then you restart the server.
You can insert a new row in the site models like this: python manage.py shell -c "from django.contrib.sites.models import Site; mysite,_=Site.objects.get_or_create(id=101, name='mysite.tld', domain='mysite.tld'); print(mysite.id, mysite.name)" Then change the site_id in the settings to the new site_id which should be 2 since it is the second new row.
You can take a look at this Github trend for more clearity.

Continue url match if request is not resolved - Django

I'm not sure if it's very specific but I think what I am going to ask is being used in various places in different contexts. My problem is mainly related to URL patterns that I've created for my Django application. I need a profile URL for all application users, so I am creating a URL pattern as below.
urlpatterns = patterns('apps.user_profile.views',
url(r"^(?P<username>\w+)/$", 'user_profile', name="user_profile_page"),
url(r"^app/$", 'app', name="app_page"),
)
As is very clear, I am mapping URLs with user names in the path to fetch user data dynamically. This is working fine, but the problem comes when the system gets a request for app page. In this case, the request goes to user profile, since it accepts all kinds of words and is ordered before app view in urls.py.
Question :
Is there any way to specify, where a request is not resolved in user_profile view, to continue looking at other URLs in the urls.py of app?
Patterns are matched in the order they are written, so simply moving your app pattern before your username pattern will solve your problem:
urlpatterns = patterns('apps.user_profile.views',
url(r"^app/$", 'app', name="app_page"),
url(r"^(?P<username>\w+)/$", 'user_profile', name="user_profile_page"),
)
Now, only if a url doesn't match app/ it will be sent to your user profile view.
Of course, you will have an issue the day a user signs up with the username of app.

Connect user login views, form with pre-exist user which is created by Django admin

I have install Django admin & created some active user & group by admin page.
I need to do login form & views, which will check if user is valid or not do task in the basis of permission.
I have tried following steps.(for reference)
Copied admin login.html for testing & paste it foo_project/templates/registration/login.html
Added in urls.py
from django.contrib.auth.views import login
url(r'^login/', login),
Now by running 127.0.0.1:8080/login
When I am entering valid user-name & password its trying to open /accounts/profile/ & it's not found in urls.py. And if I am entering invalid username or password its doing nothing.
So I simple need to link a page if login successful(user created by admin) & check which type of permission & group he is.Admin created auth_user table in my db.sqlite3
I am new to Django & using version 1.6.
I read document & tried built-in login() in views.py. Got unsuccess.
Is there any built-in for above need. Please describe in depth if possible.
In settings.py create this entry:
LOGIN_REDIRECT_URL = "your_redirect_url"
The user will be redirected to this page after login. Then on the url you will create which will respond to "your_redirect_url" (and should be defined somewhere in your urls.py), you can check the permissions, or groups. For more help about checking permissions, groups, you can find it here.
The login_required decorator can be really useful on implementing your view for your "redirect_url", because you don't want anonymous users accessing to this part of the site, right?

How to allow editing of templates for email by admin user in Django?

I need to allow the admin user to make an email template in html, and the user should be able to add dynamic variables where needed. The template will be saved in the database. For example,
Dear {{user.first_name}},
Thanks for participating in our cooking class on {{cooking_class.date}}
Then, there will be a cron job which will send emails and fill the dynamic variables.
What are my options? Is there a django package for this? I am using Django 1.4.3
thanks
I implemented something similar, here's what I did:
Create an app, and registered a model to store the email
Set up a management command to process the email
Manage the cron job via django-chronograph
Rendering the email, I used render_to_string, for example
from django.template.loader import render_to_string
from myproject.myemailapp.models import EmailTpl
email_tpl = EmailTpl.objects.get(...#criteria here)
# fetch the rest of your dynamic variables
rendered_tpl = render_to_string(email_tpl.user_entered_tpl, {
"user": user,
"cooking_class": cooking_class,
# ... and so on
})
Alternatively, Django Packages has some packages you might want to look into. Would be great if you post back the route you decided.
The plugin django-dbtemplates allows you to store templates in your database, and you can expose the dbtemplate app on your Admin site to edit. You can set your middleware settings such that either the database template or the same template in other locations has priority for loading.
We are using this in a project to manage templates for different products, with the database-stored template for each product linked by ForeignKey.

Django Test framework with file based Email backend server

I have formulated test cases in Django framework.
Use Case:
I am using API that register user by sending them an Email and when they click on the link provided in the Email their account get activated.
In my settings.py I am using
EMAIL_FILE_PATH ='django.core.mail.backends.filebased.EmailBackend'
which points to the local directory.
When running PyUnit test case from eclipse everything works file. Text file gets generated for each email sent
But, When i am using
python ./manage.py test <component_name>
the files does not generate.
Any insight what is the difference when I execute test case with ./manage.py and when I use pyUnit ?
It's possible to overwrite this aspect in Django if you want to use a specific email backend.
In django.test.utils, Django will change the e-mail backend to locmem as mentioned in the Django Testing documentation when Django sets up the testing environment:
def setup_test_environment():
...
mail.original_email_backend = settings.EMAIL_BACKEND
settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
So if you want to enable sending e-mails for a test, you just need to change the setting to what you want.
from django.test.utils import override_settings
#override_settings(EMAIL_BACKEND='django.core.mail.backends.filebased.EmailBackend')
class MyTest(TestCase):
# your test case
The simple answer:
You can't do this without engineering your own email system, but that would probably be silly. I would suggest doing something else to verify that the code was successful without requiring the email to be sent. Like, run the code, assume the user clicks the link and create RequestFactory to get/post the link to run the view code associated with it.
From the Django Testing Application:
Email services
"If any of your Django views send email using Django's email functionality,
you probably don't want to send email each time you run a test using that
view. For this reason, Django's test runner automatically redirects all
Django-sent email to a dummy outbox. This lets you test every aspect of
sending email -- from the number of messages sent to the contents of each
message -- without actually sending the messages."
For somebody (like me) that need to use custom email backend for all tests, another solution would be to override TestRunner class and force settings change.
from django.conf import settings
from django.test.runner import DiscoverRunner
class CustomTestRunner(DiscoverRunner):
def setup_test_environment(self, **kwargs):
super().setup_test_environment(**kwargs)
settings.EMAIL_BACKEND = 'path.to.your.email.backend'
And after that register the test runner in settings:
TEST_RUNNER = 'path.to.CustomTestRunner'

Categories