Am trying to implement Firebase Realtime Database with my Django Web Application. After properly setting up the configuration with Firebase, I got confused about how data will write into my Firebase Database from my Django website instead of using Sqlite, or Postgres.
Under settings.py, do I need to set my engine to Firebase? Am totally confused here. I do not want to use the normal ORM such as Sqlite, Postgres etc. I want my app to use Firebase.
Is there something else I need to understand about Firebase?
settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
pyrebase_settings file
import pyrebase
config = {
"apiKey": "my_api_key_is_here",
"authDomain": "my_auth_domain_is_here",
"databaseURL": "my_firebase_database_url_is_here",
"projectId": "my_firebase_project_id_is_here",
"storageBucket": "my_firebase_storageBucket_is_here",
"serviceAccount": "my_serviceAccount.json_file_path_is_here",
"messagingSenderId": "messagingSenderId_is_here"
}
# initialize app with config
firebase = pyrebase.initialize_app(config)
# authenticate a user
auth = firebase.auth()
user = auth.sign_in_with_email_and_password("email#usedforauthentication.com", "FstrongPasswordHere")
db = firebase.database()
take a look at the database section of the doc. It details how you would interact with the database API. Typically you would use these in your views where you need to save or retrieve something from the database.
e.g say you want a view that gets users, you could have something like this:
#views.py
from pyrebase_settings import db, auth
from django.shortcuts import render
def get_users(request):
users = db.child("users").get()
return render(request, 'users.html', {'users': users.val()})
The documentation for retrieving data can be seen here
also say you want a view to save(signup) users, you could have something like so:
#views.py
from pyrebase_settings import db, auth
def signup(request):
form = SignupForm(request.POST)
if form.is_valid():
email = form.cleaned_data('email')
password = form.cleaned_data('password')
auth.create_user_with_email_and_password(email, password)
# the rest of your code goes here
the create_user_with_email_and_password method is documented here
PS. I have never made use of the pyrebase library so I write only based on what is specified in its docs. Also I am only writing these django snippets off the top of my head so forgive me if there are any syntax errors or typos :)
Hope this helps :)
Is there something else I need to understand about Firebase?
No, there is something you need to understand about Django -- it is designed to use a relational database engine as its primary data store. Firebase is not relational.
Sorry to be the bearer of bad news.
Many answers on this question are missing this point, and suggesting code or libraries that let you access Firebase from Python. Sure, that's possible. But that doesn't make it work as a primary data store for Django. Django's ORM features and contrib apps all presume a relational database.
In order for this to work you'd need something along the lines of django-nonrel that supported Firebase. As far as I know that doesn't exist.
consider having a look at the fcm-django library here https://github.com/xtrinch/fcm-django
My solution for getting multiple files from html and upload that files in firebase storage in web django
index.html
<div id="fine-uploader-manual-trigger">
<input class="custom-file" type="file" name="imgname" id="productImgUpload" accept=".xlsx,.xls,image/*,.doc,audio/*,.docx,video/*,.ppt,.pptx,.txt,.pdf" multiple>
</div>
views.py
from firebase import Firebase
def storeimg(request):
config = {
"apiKey": "",
"authDomain": "",
"databaseURL": "",
"storageBucket": ""
}
firebase = Firebase(config)
storage = firebase.storage()
finalimglist = []
imglist = []
for i in range(len(filepath)):
storage.child("Product/"+cname+"/"+str(filepath[i])).put(filepath[i])
imgurl = storage.child("Product/"+cname+"/"+str(filepath[i])).get_url(token='null')
imglist.append(imgurl)
finalimglist.append(imglist)
Pyrebase is a wrapper around the Firebase for python. I don't recommend using Pyrebase because it lags support for Firestore and FCM. When everything in Django is done on Serverside, why not use the Firebase Admin SDK on the Django server. You can also manage users with it. I mean there is good documentation for adding the Firebase to our server. Also, they have docs in Python, NodeJS etc., for the server. I know its kind of going towards API stuff. But I feel its the right way to do in Django since Django is a server application. Check out this link
Related
I am trying to use Flask-appbuilder in an IoT project. So, FAB is used for rapid application buildup and we need dedicated RESTful API for Mobile App and 3rd party service suppliers.
In FAB, there is an implementation for RESTful API, as subclass of BaseCURDView. Most URL is defined as
http://host//api/list
If the mobile app acts as an user agent like browser, it collect username/password, login and access FAB's RESTful API, then permissions, url is not a big deal, everything can follow B/S programming. AKA, all security model is based upon cookie and session. Most of the request information are inside the flask.g.user/flask.request.*.
If the webapp has to support more standard style RESTful API, as described in flask books by miguel. The external webapp has to embed the api key/secret to specified url to exchange token, then use token in header or http parameters to access resources for CRUD operations.
http://host/api/v1/get_token
header:api_key:balabalabala
header:api_secret:abcdefxyz
return {'token':'1234567890'}
http://host/api/v1/resource
header:token:1234567890
return {'resource':'abcdefghijk'}
I have successfully merged them together in FAB's views.py.
from flask import render_template
from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask_appbuilder import ModelView, BaseView, expose
from app import appbuilder, db
from flask import Flask, jsonify
from flask import abort
from flask import make_response
from flask import request
from flask import url_for
tasks = [
{
'id': 1,
'title': u'Buy groceries',
'description': u'Milk, Cheese, Pizza, Fruit, Tylenol',
'done': False
},
{
'id': 2,
'title': u'Learn Python',
'description': u'Need to find a good python tutorial',
'done': False
}
]
def make_public_task(task):
new_task = {}
for field in task:
if field == 'id':
new_task['uri'] = url_for('get_task', task_id=task['id'], _external=True)
else:
new_task[field] = task[field]
return new_task
class ApiView(BaseView):
route_base = "/api/v1"
default_view = "index"
#expose("/index")
def index(self):
#return jsonify({'tasks': map(make_public_task, tasks)})
print repr(request.args)
print repr(request.method)
print repr(request.headers)
return jsonify(tasks)
#expose("/get_token")
def get_token(self):
print repr(request.headers)
return jsonify({'res': True})
#expose("/get_resource")
def get_resource(self):
return jsonify({'res': False})
#expose("/del_resource")
def del_resource(self):
return jsonify({'res': False})
"""
Application wide 404 error handler
"""
#appbuilder.app.errorhandler(404)
def page_not_found(e):
return render_template('404.html', base_template=appbuilder.base_template, appbuilder=appbuilder), 404
db.create_all()
appbuilder.add_view_no_menu(ApiView())
Yes, I can implement standard RESTful API just I did in another flask project with http headers and custom queries with sqlalchemy. But I am not sure if it is the proper way to do that. Since most of the data are requested directly from sqlalchemy raw queries, they are quite different programming experiences.
Open for any suggestions, before moving forward.
Actually FAB's REST API is designed for AJAX, so for mobile app and 3rd party applications, we need a seperate RESTful API, which can follow flask megatutorial and best practice and resue REST-auth library from Miguel.
FAB can work with both anyway.
I'm trying to build a super simple dashboard to show to users their Google Analytics data well formatted.
I'm using oAuth2Client and Django 1.10.4 and Python 3.5.
I've followed the example within the documentation and now I have a very simple app, the landing page will ask you to login, you click on a link to authorise, the Google page loads and asks you if you want to share your GA data and if you accept you are redirect to a page you can see only if you are logged in. All good so far.
However I can't manage to actually get users data, what's the best way to get for example the list of properties in a user's account or even better the number of page views a property had in the last week?
This is my code so far:
/pools/models.py
from django import http
from oauth2client.contrib.django_util import decorators
from django.views.generic import ListView
# from polls.models import GoogleAnalytic
from django.http import HttpResponse
# Google Analytics
from apiclient.discovery import build
# def index(request):
# return http.HttpResponse("Hello and Welcome! </br> </br> Click <a href='/profile_enabled'> here</a> to login")
#decorators.oauth_required
def get_profile_required(request):
resp, content = request.oauth.http.request(
'https://www.googleapis.com/plus/v1/people/me')
return http.HttpResponse(content)
#decorators.oauth_enabled
def get_profile_optional(request):
if request.oauth.has_credentials():
# this could be passed into a view
# request.oauth.http is also initialized
return http.HttpResponse('You are signed in.</br> </br>'+'User email: {}'.format(
request.oauth.credentials.id_token['email']) + "</br></br>Click <a href='/ga'> here </a> to view your metrics")
else:
return http.HttpResponse(
'Hello And Welcome!</br></br>'
'You need to sign in to view your data. </br></br>' +
'Here is an OAuth Authorize link:Authorize'
.format(request.oauth.get_authorize_redirect()))
########## MY CODE! ###############
#decorators.oauth_required
def google_analytics(object):
return HttpResponse('These are your results for last week:')
urls.py
from django.conf import urls
from polls import views
import oauth2client.contrib.django_util.site as django_util_site
urlpatterns = [
urls.url(r'^$', views.get_profile_optional),
urls.url(r'^profile_required$', views.get_profile_required),
# urls.url(r'^profile_enabled$', views.get_profile_optional),
urls.url(r'^oauth2/', urls.include(django_util_site.urls)),
urls.url(r'^ga/$', views.google_analytics)
]
settings.py
[...]
GOOGLE_OAUTH2_CLIENT_ID = 'XXX.apps.googleusercontent.com'
GOOGLE_OAUTH2_CLIENT_SECRET = 'XXX'
GOOGLE_OAUTH2_SCOPES = ('email','https://www.googleapis.com/auth/analytics')
So my problem is I don't really understand where Django saves the token to access the data of that particular user, I know it works because it prints out the email address correctly etc, but I can't figure out what I should add to def google_analytics(object): to actually get specific Google API methods.
If anyone has experience on these kind of things I would really appreciate some help! Thanks!
If you want to fetch Google Analytics configuration details e.g. Accounts, Web properties, Profiles, Filters, Goals, etc you can do that using Google Analytics Management API V3
If you want to fetch data of certain dimension and metrics from a Google Analytics view (aka profile), you can do that using either Core Reporting API V3 or Analytics Reporting API V4.
I think you will find the python api examples in their respective Guides.
All is in my title. I would like to get the current user information because i need it in my view to display action (delete/edit) depending of the user's rights.
I use the basic authentification make by Django (/login /logout), i didn't change anything. Is there a way to listen to this login/logout action and retrieve this information in the Angular context?
Pretty new in angular, i'm searching some informations that would help me to go in one or other direction.
Actually i don't have a REST API for authenticated my users.
I find some interesting article Best place/way to store 'global' data such as 'current logged in user' / How do I store a current user context in Angular? but for now as i said i don't have AuthService just the basic login/logout from Django.
I used Django Rest framework for some action on my project (like post/delete/read/update for some of my models) and it works fine with angularjs. But i'm happy with the basic authentification provided by Django, so i don't want to rewrite it. But i don't know how to listen on it and if it's possible.
I know that is a broad question and for now i dont't have code to show because afters hours of research i don't know where i need to begin.
If it's to broad i will remove it.
Thanks,
OK, you can do something like that
Example (someUrl is url to your function in view.py):
In angular controller add $http
$http({method: 'POST', url: '/someUrl'}).
success(function(data){
//process aswer
});
In djnago view.py:
from django.shortcuts import HttpResponse
import json
def check_login(request):
if request.user.is_authenticated():
return HttpResponse(json.dumps({'result': {'logged': True}, 'user': request.user.username}),
content_type="application/json")
else:
return HttpResponse(json.dumps({'result': {'logged': False}}),
content_type="application/json")
I've been asked to provide a "Login with Facebook" functionality to an iOS app I am creating.
The app connects to a REST api created with Piston, the web application is created with Django and uses social_auth. The application also has a Facebook login.
My thought was to create a service 'FBLogin' providing just the Facebook profile UID (separate FB login procedure on iPhone to get the ID). Using the SocialAuth models I can query the DB with uid and provider to fetch the user... but how can i use the authentication mechanism to get this user instance authenticated?
Any ideas on getting this right?
This just doesn't feel good ... getting the user instance authenticated is a pain...
The username password authentication is already implemented ... without a problem.
Btw, don't have django experience ... do have a lot of other development experience so understanding python and django isn't that hard :)
Tx
Y
It doesn't really seem to be documented anywhere, but you can do this in your REST handler:
from social_auth.backends.pipeline.social import associate_user
from social_auth.backends.facebook import FacebookBackend
from social_auth.models import UserSocialAuth
myextra_data = {
'access_token' : 'jfkdlfsdgeyejfghfdsjdfpoweipuo',
'id' : 123456789,
}
usa, created = UserSocialAuth.objects.get_or_create(provider = 'facebook',
uid=123456789)
usa.user = user
usa.extra_data = myextra_data
usa.save()
if created:
associate_user(backend=FacebookBackend, user=user, uid=usa.uid)
These get pretty vendor-specific in terms of how data gets formatted in extra_data so YMMV
I'm overhauling a site I'd originally made using Joomla to Django, and I was wondering if I can import the user records directly from Joomla (my main concern is the user passwords as they are encrypted).
Yes, you can, but you'll have to do some work. Joomla keeps users in some specific DB table structure, so you'll have to pull them out and insert them into a users table you create in your Django application. As for encryption, if the algorithm is known, it's probably the hash value that's kept in the DB, and you can just transfer it as-is as long as you implement the same hashing algorithm in your Django application.
Remember: Django is a more general 'concept' than Joomla - it's a framework for writing web application, hence in theory you can even re-implement Joomla completely with it.
Joomla users in Django (Django auth backend, that populates users from Joomla)
Once I was in need to use our existing Joomla users in my new API, written in Django.
Problem is that I could not just copy Joomla users into a Django database, because:
Joomla password hashing system differs from Django one.
J-users and D-users had different set of fields (this is easy to fix, but still)
So instead I made a custom auth backend for Django, and now I can confidently say that
Django can authenticate users against the Joomla database, without need to decrypt password hashes or to copy all users from Joomla DB at once.
Algorithm:
connect the Joomla database to the Django project
create JoomlaUser model, to populate users from the Joomla DB
implement check_joomla_password() function, that validates user passwords the same way as Joomla
add custom "Joomla Auth Backend" that copies each user from Joomla to Django at the first login
Implementation:
To understand what's going on, you should have some experience with Django.
The code have to be modified accordingly to your django project.
However the code is taken from the working project with minimum changes,
and it should be easy to set up for your needs.
1. connect to Joomla DB:
Read https://docs.djangoproject.com/en/dev/topics/db/multi-db/
Add to /project_name/settings.py:
DATABASES = {
'default': {"your default DB settings"},
'joomla_db': {
'ENGINE': 'django.db.backends.mysql',
'OPTIONS': {},
'NAME': 'joomla_database_name',
# Don't store passwords in the code, instead use env vars:
'USER': os.environ['joomla_db_user'],
'PASSWORD': os.environ['joomla_db_pass'],
'HOST': 'joomla_db_host, can be localhost or remote IP',
'PORT': '3306',
}
}
# add logging to see DB requests:
LOGGING = {
'version': 1,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'level': 'DEBUG',
'handlers': ['console'],
},
},
}
2. create Joomla user model
Read https://docs.djangoproject.com/en/2.1/howto/legacy-databases/
Think where to keep new "Joomla user" model.
In my project I've created 'users' app, where my custom user models live,
and the custom Joomla backend will be placed.
inspect how the user is stored in the existing Joomla DB:
python manage.py inspectdb --database="joomla_db"
Find and carefully examine the users table.
Add to users/models.py:
class JoomlaUser(models.Model):
""" Represents our customer from the legacy Joomla database. """
username = models.CharField(max_length=150, primary_key=True)
email = models.CharField(max_length=100)
password = models.CharField(max_length=100)
# you can copy more fields from `inspectdb` output,
# but it's enough for the example
class Meta:
# joomla db user table. WARNING, your case can differs.
db_table = 'live_users'
# readonly
managed = False
# tip for the database router
app_label = "joomla_users"
To ensure, that JoomlaUser model will use right DB, add a database router:
Create file "db_routers.py" in the project folder, where the "settings.py" file is stored:
# project_name/db_routers.py
class DbRouter:
"""this router makes sure that django uses legacy 'Joomla' database for models, that are stored there (JoomlaUser)"""
def db_for_read(self, model, **kwargs):
if model._meta.app_label == 'joomla_users':
return 'joomla_db'
return None
def db_for_write(self, model, **kwargs):
if model._meta.app_label == 'joomla_users':
return 'joomla_db'
return None
register new router, for that, add in settings.py:
# ensure that Joomla users are populated from the right database:
DATABASE_ROUTERS = ['project_name.db_routers.DbRouter']
Now go to django shell ./manage.py shell and try to populate some users, e.g.
>>> from users.models import JoomlaUser
>>> print(JoomlaUser.objects.get(username='someuser'))
JoomlaUser object (someuser)
>>>
If everything works - move on to the next step. Otherwise look into errors, fix settings, etc
3. Check Joomla user passwords
Joomla does not store user password, but the password hash, e.g.
$2y$10$aoZ4/bA7pe.QvjTU0R5.IeFGYrGag/THGvgKpoTk6bTz6XNkY0F2e
Starting from Joomla v3.2, user passwords are hashed using BLOWFISH algorithm.
So I've downloaded a python blowfish implementation:
pip install bcrypt
echo bcrypt >> requirements.txt
And created Joomla password check function in the users/backend.py:
def check_joomla_password(password, hashed):
"""
Check if password matches the hashed password,
using same hashing method (Blowfish) as Joomla >= 3.2
If you get wrong results with this function, check that
the Hash starts from prefix "$2y", otherwise it is
probably not a blowfish hash from Joomla.
:return: True/False
"""
import bcrypt
if password is None:
return False
# bcrypt requires byte strings
password = password.encode('utf-8')
hashed = hashed.encode('utf-8')
return hashed == bcrypt.hashpw(password, hashed)
Old versions Warning! Joomla < 3.2 uses different hashing method (md5+salt),
so this function won't work.
In this case read joomla password encryption
and implement a hash checker in python, which probably will look something like:
# WARNING - THIS FUNCTION NOT TESTED WITH REAL JOOMLA USERS
# and definitely has some errors
def check_old_joomla_password(password, hashed):
from hashlib import md5
password = password.encode('utf-8')
hashed = hashed.encode('utf-8')
if password is None:
return False
# check carefully this part:
hash, salt = hashed.split(':')
return hash == md5(password+salt).hexdigest()
Unfortunately I have no old Joomla instance running, thus I couldn't test this function for you.
4. Joomla Authentication Backend
Now you are ready to create a Joomla authentication backend for Django.
read how to modify django auth backends: https://docs.djangoproject.com/en/dev/topics/auth/customizing/
Register Jango (not yet existing) backend in the project/settings.py:
AUTHENTICATION_BACKENDS = [
# Check if user already in the local DB
# by using default django users backend
'django.contrib.auth.backends.ModelBackend',
# If user was not found among django users,
# use Joomla backend, which:
# - search for user in Joomla DB
# - check joomla user password
# - copy joomla user into Django user.
'users.backend.JoomlaBackend',
]
Create Joomla authentication Backend in users/backend.py:
from django.contrib.auth.models import User
from .models import JoomlaUser
""" check password function we wrote before """
def check_joomla_password(password, hashed):
...
class JoomlaBackend:
def authenticate(self, request, username=None, password=None):
"""
IF joomla user exists AND password is correct:
create django user
return user object
ELSE:
return None
"""
try:
joomla_user = JoomlaUser.objects.get(username=username)
except JoomlaUser.DoesNotExist:
return None
if check_joomla_password(password, joomla_user.password):
# Password is correct, let's create identical Django user:
return User.objects.create_user(
username=username,
email=joomla_user.email,
password=password,
# any additional fields from the Joomla user:
...
)
# this method is required to match Django Auth Backend interface
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
Test & documentation
Congratulations - now your customers from old Joomla site can use their credentials on the new Django site or rest api, etc
Now, add proper tests and documentation to cover this new code.
It's logic is quite tricky, so if you won't make tests&docs (lazy dude) - maintaining the project will be a pain in your (or somebody's else) ass.
Kind regards,
# Dmytro Gierman
Update 11.04.2019 - errors fixed.
I think there is 3 ways to approach this problem:
1) You can read about how joomla and django make hash of passwords and make the migration with a script
2) You can make your own authentication backend
3) You can use a ETL tool
Joomla (PHP) is a CMS while Django (Python) is a web framework.
I wonder whether this is really possible. What i can conclude at this point of time is that it is not possible. However someone may have any idea about this.
Thanks :)