Django: How to create a user action log/trace with vizualization - django

I am looking for a tool to track user actions like:
user logged in
user changed password
user got bill via email
user logged
user uploaded image
user send message
...
which I can include into my Django project. Afterwards I want to build queries and ask the system stuff like:
how often did a user a message within a month
how often did a user login within a month
does the user uploaded any images
and I would like to have some kind of interface. (Like google analytics)
Any idea? I am pretty sure that this is a common task, but I could not find anything like this.

There are many ways to achieve that. Try reading this link first. Also, you can use LogEntry for tracking the creation, deletion, or changes of the models you have. Also, it shows you the information you need in the admin panel, or also you can use some other third-party packages.
Or you may want to create your own Model to create logs for your application and this link may help you, but do not reinvent the wheel and analyze your situation.
from django.contrib.admin.models import LogEntry, ADDITION
LogEntry.objects.log_action(
user_id=request.user.pk,
content_type_id=get_content_type_for_model(object).pk,
object_id=object.pk,
object_repr=force_text(object),
action_flag=ADDITION
)

Create a model to store the user actions. OP will want the Action model to have at least two fields - user (FK to the user model) and action (user action).
from django.db import models
class Action(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
action = models.CharField(max_length=255)
Create a way to store the user actions.
def store_user_action(user, action):
action = Action(user=user, action=action)
action.save()
Then if one wants to store when the user changed password, one will go to the view that deals with the change password and call our method store_user_action(request.user, 'changed password') when successful.
To then visualise the user actions, OP can see the records in the Django Admin, create views and templates, ... There are different possibilities.

Related

Different model field requirements for superuser vs normal user? django

Example(not true example):
I want the superusers to have to save on register their username and email.
and the normal users to save username, email, and a number(unique=True).
I wanted to use the user models django has, but I don't see how when the number has to be unique? or rather I originally wanted it to be the primary key, but only for normal users. Do I have to manually make two different user classes along with the permissions, authentication etc.? or is there separate user models for admin/user in django?
I tried(as a complete amateur, new to oop and django)... after gave up on using it as primary key, bc AbstractUser is fly.
Tried with onetoonefield, but couldn't make a combined form with UserCreationForm, bc "too many fields error". Also weird to have an important part of the user table be in a different table (or is it?).
something like (not 100% accurate):
#in models.py
class AdminUser(AbstractUser):
username
email
class NormalUser():
ontoonefield(AdminUser)
number(unique=True)
#in forms.py
class NormalUserForm(UserCreationForm):
class meta:
fields
class onetoonefieldForm(NormalUserForm):
class meta:
add_field += (number)
tried playing with required_fields, but again... number is unique
tried making two abstractUsers... permissions errors
thought about just making it non-unique and just checking on db insert that it's unique, but that seemed like a risk to the database, when it's vital it's unique.
Thank you for listening:)
Have a great day
Do I have to manually make two different user classes along with the permissions, authentication etc.? or is there separate user models for admin/user in django?
Django uses one built in User model and distinguishes three types of users using the attributes is_staff and is_superuser.
Normal user: is_staff=False, is_superuser=False
Staff user (can access the admin interface): is_staff=True
Super user (can do everything): is_superuser=True
If the default user model does not work for you, you can extend it or replace it.
Having the user decide their primary key, is not the intended default. The primary key is usually decided by the database, which also handles the uniqueness. If you would like to assign a unique number to each user, such as a customer number, I suppose it is easiest to extend the user model with a user profile.

Custom Django Authentication

I have an model named Customers(username,password ..etc) and also an model named User(username,password...etc).
I want to create two different APIs with different authentication.
One should authenticate with the User username,password
and the second should authenticate using the Customers username,password.
Any idea on how can I do this?
Thank you!
I suggest the following options:
1.
I am assuming User model is the "real" user of your app. If this is true use the django's default User model class. It will work out of the box.
For the Customer model, make it inherit from AbstractBaseUser, this will give you password functionality out of the box and you can add other fields as per your need.
Now you can create 2 different urls for login. 1 url for user which checks in the User model and the other for the customer model. This avoids any confusion for everyone.
If you prefer a single url, you have to mention the model class along with username and password to know in which table to verify them.
2.
Create two profile models: UserProfile and CustomerProfile
Each will have a one to one relationship with the django's default User model.
Basically a User can have the profile of a "real" user or of a customer.
In this case when you are creating any User you have check if you want to attach a UserProfile or a CustomerProfile.
In this case it makes sense to just use a single login url. From the user's login information you can first fetch the user from the User table and then check if it is a customer or not by running a query in the CustomerProfile table.
I recommend you to use the django.contrib.auth.user class for your classical authentication. You can either inherit from that class or add a OneToOne relation to your own model as follows
from django.contrib.auth.models import User
class YourUser(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
For the rest of your question you should add some more details and even some pieces of your code.

How to save two different users in a django model?

My case is related to a purchase, the customer who buys something and the seller who sold it.
Models.py
from django.contrib.auth.models import User
class buy(models.Model):
customer = models.ForeignKey(User)
seller = models.ForeignKey(User)
I am aware that the above code is wrong, I write it that way so the question is understood.
I take the django.contrib authentication system, to avoid having to make another authentication system for clients and one for sellers, I want django code reuse.
A solution had thought of creating another data model to sellers or customers, but in my view and in the login I'm using django.contrib, then I would still use this system authentication would like to know if there is any way or if I ultimately that create another authentication system?
I'm just guessing, if you have a Product model that has a user field in which case he's the actual seller, why don't you use seller = models.ForeignKey(Product, to_field='user')

How to use anafero to create a referral system in django?

I want to create a two-sided benefit referral system, with different types of referrals in django using the anafero app.
I looked at this article and looked at the documentation for anafero and I cannot make sense of it. Can someone please give an simple example of:
What database changes need to be made, i.e. which models need to
be created and how the user object needs to be changed
Which view needs to be created
How to display the referral url in the template
Anafero is outdated. Instead of it you can use pinax_referrals
Install the package as it described in documentation, add middleware etc, synchronize database.
Depending on what do you use for signing up hack the view. In my case I have reimplemented SignUp view and added following lines inside:
profile = user.userprofile
referral = Referral.create(
user= user,
redirect_to= "/"
)
profile.ref = referral
profile.save()
You see that when User signs up the Refferal object is created and saved into User profile. It means that you have to change the model for UserProfile and add additional field:
Import:
from pinax.referrals.models import Referral
Inside model:
ref = models.OneToOneField(
Referral,
null=True,
on_delete=models.CASCADE,
)
Make migrations, migrate, check in the admin if new fields are added, try to sign up and see whether the new Referral object is created and saved.

Anyone think django's user model is too tightly coupled with auth?

I'm trying to learn Django and I would like feedback from anyone who has any MVC/MTV/PHP/Ruby framework experience. Does anyone find that the user model is too tightly coupled with auth?
Background: When you first implement authentication for Django, you include the module django.contrib.auth
This will bring in several models like User, Group, Message etc. Let's focus on the User model as this is the one of the most important tables in any website.
In short the User table has these fields
User
username max_length 30, unique, [letters, digits, underscores]
password max_length 75
email max_length 75
...and about 8 other useful fields like first_name, last_name, etc.
Goal:
I want to remove username and use email as the login for every user. It's a pretty simple request that many websites use these days.
I don't want to monkey patch the core code since this will make upgrading more difficult later on. This means modifying the User model is out of the question. I only want to do a few simple and basic things I expect a few frameworks to do so let me address how Django does it.
Adding new fields to the User model
Django docs says to use create another table and insert the fields there. You will have a one to one relationship between the User table and the Profile table.
eg.
If You want to add an image field to each user you add it to the profile table. A join query is made every single time. They've even specified a constant to tell the framework what table to use:
AUTH_PROFILE_MODULE = 'accounts.UserProfile'
I don't think it's the best practice to have to do a join query every time I want a field that should belong to the user table.
Another option is to use the function add_to_class.
The django community has stated it's not good to define new fields outside of the main class because other developers who add methods won't know all the data members.
Editing old fields
The auth module does a check against two fields username and the hashed password. Looking at the above table I would need to change the username model to accept these properties. Length of 75 with all the valid characters of the email. The django suggests I check against the email field.
Two problems arise if I use the email field to auth against:
I need to write a new class to be used in a constant AUTHENTICATION_BACKEND, so it checks against the email field and I have an unused field called username.
Adding new methods
In MVC/MTV a design principle is to use fat models skinny controllers. Since the model is declared in auth, I'm not sure how one is supposed to add methods that act on the user model's fields. Since django suggests using a Profile model, I suppose they will have to go there.
Extending the User class
A small annoyance would be that I can't use the name 'User' and instead must use 'Users' or 'Accounts'. A bigger one is I don't think the auth would recognize this new module. Meaning I would have to rewrite a bunch functionality that is is present. This one doesn't bother me as it's something I expect to do in other frameworks.
Any comments are appreciated. I wouldn't ask all these questions and look for solutions if I wasn't truly interested in using django.
I agree that django's incessant clinginess to the auth models is absurd. My job requires me to create ultra scalable and very high load sites which sometimes require user authentication and djano's auth model + permissions does not fit with that.
Fortunately, it's not difficult to replace.
First, create a custom User model.
class User(models.Model):
...fields...
#Define some interface methods to be compatible.
def get_and_delete_messages(self):
def is_active(self):
def is_anonymous(self):
def is_authenticated(self):
def is_staff(self):
def has_perm(self, perm_list):
Second, create your own authentication back-end.
class LocalAccount(object):
"""
This checks our local user DB for authentication
"""
def authenticate(self, username=None, password=None):
try:
user = User.objects.get(alias=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.select_related().get(pk=user_id)
except User.DoesNotExist:
return None
#settings.py
AUTHENTICATION_BACKENDS = (
'helpers.auth.LocalAccount',
)
That should solve most of your issues, I don't even think all of the methods you would find on django.contrib.auth.User are necessary, I recommend trying it out.
The one gotcha here is that the admin may start to bitch, fortunately that's really easy to patch using simple python inheritance as well. That's another question though :)
At the end of the day your project's auth backend needs some sort of store for auth credentials. That the default auth backend is tightly coupled to the User model is not strange in this respect. It's easy enough to substitute your own definition for the user model if you write your own auth backend, as I have in the past.
I created my Profile model and use AUTH_PROFILE_MODULE, so I have complete control over my model, I can modify fields, add methods, etc. Now I'm thinking about using cache and writing middleware that will get profile from cache if possible.
To login using email you could write very simple auth backend:
from django.contrib.auth.models import User
from django.contrib.auth.backends import ModelBackend
class EmailModelBackend(ModelBackend):
def authenticate(self, username=None, password=None):
try:
user = User.objects.get(email=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None