I have a custom configuration for logs in views.py as below:
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# Handlers
log_handlers = {
"terminal": logging.StreamHandler(),
"file_debug": logging.FileHandler("/var/log/eshot-api/{name}-{level}.log".format(name=__name__, level="DEBUG"), mode="w"),
"file_error": logging.FileHandler("/var/log/eshot-api/{name}-{level}.log".format(name=__name__, level="ERROR"), mode="w")
}
log_handlers["terminal"].setLevel(logging.INFO)
log_handlers["file_debug"].setLevel(logging.DEBUG)
log_handlers["file_error"].setLevel(logging.ERROR)
# Formatters
log_formatters = {
"terminal": logging.Formatter("[%(name)s]::[%(levelname)s]#[%(asctime)s]: %(message)s"),
"file_debug": logging.Formatter("[%(levelname)s]#[%(asctime)s]: %(message)s"),
"file_error": logging.Formatter("[%(asctime)s]: %(message)s")
}
for k, v in log_formatters.items():
log_handlers[k].setFormatter(v)
I have created a directory as /var/log/eshot-api and given permission as chmod 777 to that directory so that there will be no problem for writing.
I've also created a function as below:
def initial_log(request, method):
logger.debug("{ip} requested {path} with {kwargs} in {method} method".format(ip=ipaddr(request), path=request.get_full_path(), kwargs=str(dict(request.GET)), method=method))
method argument is a string to pass "GET" or "POST" to this function.
And I've put this at the beginning to my all get function of ClassBasedView. However, when I run and refresh a page a couple of time in order to generate some logs and look into my log files, they are empty.
And, I want to mention that this is a development server in my own computer.
Environment
django 1.9.6
ubuntu 14.04
python 3.5.1
Check your settings.py for a LOGGING = {...} setting and make sure that it has disable_existing_loggers set to False:
LOGGING = {
...
'disable_existing_loggers': False,
..
}
Or remove the LOGGING setting completely. And add handlers to the logger:
logger.addHandler(log_handlers["file_debug"])
Also i'de like to advise you to configure LOGGING in your settings.py.
Fully working example
urls.py:
from django.conf.urls import url
from .views import IndexView
urlpatterns = [
url(r'^$', IndexView.as_view()),
]
views.py:
import logging
from django.http import HttpResponse
from django.views.generic import View
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# Handlers
log_handlers = {
"terminal": logging.StreamHandler(),
"file_debug": logging.FileHandler("/var/log/eshot-api/{name}-{level}.log".format(name=__name__, level="DEBUG"), mode="w"),
"file_error": logging.FileHandler("/var/log/eshot-api/{name}-{level}.log".format(name=__name__, level="ERROR"), mode="w")
}
log_handlers["terminal"].setLevel(logging.INFO)
log_handlers["file_debug"].setLevel(logging.DEBUG)
log_handlers["file_error"].setLevel(logging.ERROR)
# Formatters
log_formatters = {
"terminal": logging.Formatter("[%(name)s]::[%(levelname)s]#[%(asctime)s]: %(message)s"),
"file_debug": logging.Formatter("[%(levelname)s]#[%(asctime)s]: %(message)s"),
"file_error": logging.Formatter("[%(asctime)s]: %(message)s")
}
for k, v in log_formatters.items():
log_handlers[k].setFormatter(v)
logger.addHandler(log_handlers['file_debug'])
class IndexView(View):
def get(self, request):
logger.debug("requested {path} with {kwargs} in method".format(path=request.get_full_path(), kwargs=str(dict(request.GET))))
return HttpResponse('app:index')
settings.py
LOGGING = {
'disable_existing_loggers': False,
}
Related
I have been trying to import a model in a middleware process function but I am getting the error:
Value: Model class x doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS
I am guessing the problem is that the application setup is not complete, however, all my attempts to solve this have hit a wall.
middleware.py function
from notifications.models import Notification
...
class CheckNotificationMiddleware(object):
"""
Checks clicked notification to mark it as read
"""
def process_request(self, request):
if request.user.is_authenticated():
notification_id = request.GET.get('notification_id')
if notification_id:
AppConfig.get_model('Notification')
try:
notification = Notification.objects.get(
pk=notification_id, status=0, recipient=request.user)
notification.status = 1
notification.save()
except ObjectDoesNotExist:
pass
settings.py
INSTALLED_APPS = (
...
'notifications',
...
)
I have tried a couple of things including...
from django.apps import AppConfig
AppConfig.get_model('Notification')
I am using Django version 1.11 and python 2.7
you have to include notifications under the
INSTALLED_APPS = [
'notifications',
]
in the settings file
I am trying to implement logging in my Django project (django 1.11, Python 3.6). I'm using default django logger.
To get the username in log, I have used django-requestlogging 1.0.1.
As of now, I don't have any user other than admin superuser.
When I'm trying a GET request on front-end side, an error occurs that says 'LogSetupMiddleware' is not callable.
What is the reason for this error? How do I make the logging work?
How do I get AnonymousUser in the logs?
File settings.py snippet:
INSTALLED_APPS= [
...
'django_requestlogging',
]
MIDDLEWARE = [
...
'django_requestlogging.middleware.LogSetupMiddleware',
...
]
LOGGING = {
'version': 1,
'formatters': {
'standard' : {
'format': '%(asctime)s %(username)s %(request_method)s',
},
},
}
As I can see here middleware class is really not callable. To fix it you have to override that class like this:
some/middlware/path.py
from django.utils.deprecation import MiddlewareMixin
from django_requestlogging.middleware import LogSetupMiddleware as Original
class LogSetupMiddleware(MiddlewareMixin, Original):
pass
And replace middleware path in settings.py by new one:
some.middleware.path.LogSetupMiddleware
I have Django project that has two apps App1 and App2)
each app has only 1 view.
. My project connected to openldap using django-auth-ldap.
I have two groups(Group1, Group2).
I Added decorators before my views in app1 and app2 (#login_required) and the result as expected that all users from group1 and group2 will be able to login to both apps.
I want to be able to just allow group1 to access app1 only and group2 access app2 only.
I tried many codes but no one work with me.
Here is my code:
app1.views.py
from django.shortcuts import render
from django.template import loader
from django.http import HttpResponse
from django.contrib.auth.decorators import login_required
from django.contrib.auth import views as auth_views
#login_required(login_url='/accounts/login/')
def index(request):
#getting our template
template = loader.get_template('main/index.html')
#rendering the template in HttpResponse
return HttpResponse(template.render())
Here is my ldap settings from settings.py:
#Generated by 'django-admin startproject' using Django 1.11.
import os
import django
AUTHENTICATION_BACKENDS = ('django_auth_ldap.backend.LDAPBackend',)
import ldap
from django_auth_ldap.config import LDAPSearch, GroupOfNamesType
AUTH_LDAP_SERVER_URI = "ldap://mydomain.com"
AUTH_LDAP_BIND_DN = "cn=admin,dc=mydomain,dc=com"
AUTH_LDAP_BIND_PASSWORD = "mypass"
AUTH_LDAP_USER_SEARCH = LDAPSearch("ou=ou_org_unit,dc=mydomain,dc=com",
ldap.SCOPE_SUBTREE, "(uid=%(user)s)")
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("ou=ou_org_unit,cn=group1,cn=group2,dc=mydomain,dc=com",
ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)"
)
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType()
AUTH_LDAP_USER_ATTR_MAP = {
"first_name": "givenName",
"last_name": "sn",
"email": "mail"
}
AUTH_LDAP_FIND_GROUP_PERMS = True
AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600
First I would map a property to the user object that specifies which group the user is in:
AUTH_LDAP_USER_ATTR_MAP = {
"first_name": "givenName",
"last_name": "sn",
"email": "mail",
"ldap_group": "cn" # not 100% sure if this is what's required, just guessing
}
Then make a decorator with user_passes_test:
from django.contrib.auth.decorators import user_passes_test
def ldap_group_required(group_name):
"""
Checks if a user is in the specified LDAP group.
"""
return user_passes_test(
lambda u: hasattr(u, 'ldap_group') and u.ldap_group == group_name,
login_url='/accounts/login/'
)
Use it on a view like so:
#ldap_group_required('group1')
def index(request):
#getting our template
template = loader.get_template('main/index.html')
#rendering the template in HttpResponse
return HttpResponse(template.render())
If you check out the source code, this is effectively how login_required works.
I would personally recommend a slightly different approach to this, using Django's built-in permissions.
What you can do is create custom permissions, for example, can_access_app1 and can_access_app2. Then, since django-auth-ldap will automatically copy all of your groups into the Django database for you, you can then assign those permissions to the appropriate groups.
Now that your groups and their respective permissions are set up, you would then decorate your views appropriately. For example:
# app1/views.py
from django.contrib.auth.decorators import permission_required
from django.http import HttpResponse
from django.shortcuts import render
from django.template import loader
#permission_required('app1.can_access_app1')
def index(request):
#getting our template
template = loader.get_template('main/index.html')
#rendering the template in HttpResponse
return HttpResponse(template.render())
This approach would be well-documented, not introduce any special trickery having to manipulate your user objects, and would also have the added advantage that you can assign these permissions to individuals as well if you want to give special access. In addition, any superuser account will automatically have both permissions for no extra effort!
According to the documentation this should be fairly simple: I just need to define handler404. Currently I am doing, in my top urls.py:
urlpatterns = [
...
]
handler404 = 'myapp.views.handle_page_not_found'
The application is installed. The corresponding view is just (for the time being I just want to redirect to the homepage in case of 404):
def handle_page_not_found(request):
return redirect('homepage')
But this has no effect: the standard (debug) 404 page is shown.
The documentation is a bit ambiguous:
where should handler404 be defined? The documentation says in the URLconf but, where exactly? I have several applications, each with a different urls.py. Can I put it in any of them? In the top URLconf? Why? Where is this documented?
what will be catched by this handler? Will it catch django.http.Http404, django.http.HttpResponseNotFound, django.http.HttpResponse (with status=404)?
As we discussed, your setup is correct, but in settings.py you should make DEBUG=False. It's more of a production feature and won't work in development environment(unless you have DEBUG=False in dev machine of course).
All the other answers were not up to date. Here's what worked for me in Django 3.1:
urls.py
from django.conf.urls import handler404, handler500, handler403, handler400
from your_app_name import views
handler404 = views.error_404
handler500 = views.error_500
views.py
def error_404(request, exception):
context = {}
return render(request,'admin/404.html', context)
def error_500(request):
context = {}
return render(request,'admin/500.html', context)
Note, you will have to edit this code to reflect your app name in the import statement in urls.py and the path to your html templates in views.py.
Debug should be False and add to view *args and **kwargs. Add to urls.py handler404 = 'view_404'
def view_404(request, *args, **kwargs):
return redirect('https://your-site/404')
If I didn't add args and kwargs server get 500.
To render 404 Error responses on a custom page, do the following:
In your project directory open settings.py and modify DEBUG as follows:
DEBUG = False
In the same directory create a file and name it views.py, insert the following code:
from django.shortcuts import render
def handler404(request, exception):
return render(request, 'shop/shop.html')
Finally open urls.py file which is in the same project directory and add the following code:
from django.contrib import admin
from . import views
handler404 = views.handler404
urlpatterns = [
path('admin/', admin.site.urls),
]
I have some interesting task - write custom logger for Django, that stores request (INFO level) and show data (DEBUG level) in file.
I cannot use standard Django logger.
Can you point me in right direction?
Should I use middleware?
Thanks. I appreciate your time.
So far i figure out something like:
import os
import logging
from django.conf import settings
# logging config
logging.basicConfig(filename=os.path.join(settings.BASE_DIR, 'debug.log'),
level=logging.DEBUG)
logger = logging.getLogger(__name__)
class FileLoggerMiddleware(object):
def process_response(self, request, response):
request_log = 'Path: {}, GET: {}, POST: {}'.format(
request.path, request.GET, request.POST)
logger.info(request_log)
# We have queries logging out of box
# But here what i wood wrote:
# from django.db import connection
# for q in connection.queries:
# query_log = "({}) QUERY ".format(q.time, q.sql ) //and more info
# logger.debug(query_log)
return response