lorinkoz / django-pgschemas Goto Github PK
View Code? Open in Web Editor NEWDjango multi-tenancy through Postgres schemas
Home Page: https://django-pgschemas.readthedocs.io/
License: MIT License
Django multi-tenancy through Postgres schemas
Home Page: https://django-pgschemas.readthedocs.io/
License: MIT License
After some extensive use, maybe passing -s :static:
or -s :dynamic:
is not better than -ss
or -sd
.
Hi,
I post this as an issue because, as a newbie, I really think there is an issue to choose the right library for postgres multitenant schemas in Django. Django-tenant-schemas, Django-tenants, django-pgschemas... What to choose and why?
I love the features of django-pgschemas, it would be so cool to see them as options in django-tenants ( or as part of f.ex. a django-tenants 2.0 )
It is really amazing that people like you (@lorinkoz) , @tomturner and all contributors are sharing their work with the world. Big thanks for that! Yet, it could be so much more powerful if forces would be joined to create one project in stead of forks of forks, etc.
I just wanted to share, I know there is probably a reason for everything so, no offence.
Keep up the good work!
I created a template schema with createrefschema
. I then created a new tenant off that. When I attempted to make a new migration for my project and migrate, it fails when it gets to the new tenant with
django.db.utils.IntegrityError: duplicate key value violates unique constraint "django_migrations_pkey" DETAIL: Key (id)=(1) already exists.
Investigating it I can see that the column defaults aren't carried over in Postgres.
I was able to get django_pgschemas working nicely with no issues. However I noticed that since incorporating django-pgschemas into my project my post_save and post_delete signals no longer work. Are signals supported with django-pgschemas?
Here is my signals.py file:
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from fin.fin_helpers import adjust_account_tran_balance
from fin.models import AccountTran, InvestAccount
@receiver(post_save, sender=AccountTran)
def save_account_tran(instance, **kwargs):
print('--------------- in signal post_save ---------------')
adjust_account_tran_balance(instance.account_id, instance.odate)
As a newcomer to multitenancy in general and django-pgschemas in particular, is there any harm in including ALL of my INSTALLED_APPS in both/ either of the public or default tenants? I can see potential performance issues with having every table replicated inside all schemas, but I think this would only affect dynamic tenants? Put another way, how do I decide which apps should be "tenantized" ?
edit: also, how do I decide which apps go in public, and which in default?
Investigate, it works good with whowill
but for some reason it's not working with migrate?
Sometimes you want to run a command on all dynamic schemas, and for some reason the command halts before finishing. You don't want to start over again, how to "resume execution" and only run it on the missing schemas?
Is there any standard for storing execution plans? Any standard for the arguments one must use to play along with an execution plan?
I've been playing around with this for a while and what I want to accomplish is multitenancy where each tenant can access their own admin. I've gotten as far as actually getting /admin to work but I can't create an admin user for the tenant. How is this done?
Also, what is the best way to set up the main application where I can manage the customers / tenants?
Here is my settings.py configuration:
TENANTS = {
# ...
"www": {
"APPS": [
"django.contrib.auth",
"django.contrib.sessions",
"django.contrib.admin",
'django.contrib.messages',
"django.contrib.staticfiles",
# ...
"website",
],
"DOMAINS": ["localhost"],
"URLCONF": "website.urls",
},
# ...
"public": {
"APPS": [
"django.contrib.contenttypes",
"django.contrib.staticfiles",
# ...
"django_pgschemas",
"customers",
# ...
],
},
# ...
"default": {
"TENANT_MODEL": "customers.Client",
"DOMAIN_MODEL": "customers.Domain",
"APPS": [
"django.contrib.auth",
"django.contrib.sessions",
"django.contrib.admin",
'django.contrib.messages',
'django.contrib.staticfiles',
# ...
"frontend",
"accounts",
# ...
],
"URLCONF": "frontend.urls",
}
}
Whenever I try to createsuper on for the base, I get this:
django.db.utils.ProgrammingError: relation "auth_user" does not exist LINE 1: ...user"."is_active", "auth_user"."date_joined" FROM "auth_user...
I'm in dev and just experimenting so if I have to start over, I'm fine with it.
I'm using a single domain with tenant folders. Ex. app.domain.com/tenant1, app.domain.com/tenant2, etc.
I use this https://docs.djangoproject.com/en/2.2/ref/urls/#handler404 to have a different 404 view.
After setting up django-pgschemas, I've noticed that handler404 works when I visit app.domain.com/asdadas, but if I get a 404 response with tenant folder, the handler404 view is not used. For example, when I visit app.domain.com/tenant1/asdasdas, it shows the default page not found error.
Please advice.
When the tenant/domain model themselves have pending migrations, the query for them performed inside management commands is exploding. One variant is to run the migrations in the public schema explicitly first, but I think we can catch this exception and provide a helpful message to the user.
Hi! In the process of moving some of my apps over to django 4, and it appears the latest version supported by pgschemas is 3.3. Any chance of a release which supports django 4 any time soon?
Being able to define a custom header and using it for tenancy routing would make it a straightforward experience when django is used exclusively as a api backend.
Review and incorporate these:
The Django admin customizations are still out of the scope here.
The modification of the TenantClient.login
feels out of scope, since this comes from a Django decision itself, it seems that this customization would be more appropriate to be carried out as part of test mocking.
Refactor
asgiref.Local
routing
module.TENANTS
settings.TenantModel.routing
pytest
!!more to come...
I'm getting this error when running createrefschema. The error message doesn't make any sense to me. What names are clashing?
`(venv) C:\code\fin2>manage.py createrefschema
SystemCheckError: System check identified some issues:
CRITICALS:
?: (pgschemas.W004) Name clash found between static and dynamic tenants: {'public'}`
My settings looks like this...
`TENANTS = {
"public": { # always treated as a shared schema. Cannot be routed directly.
"APPS": [
"django.contrib.contenttypes",
"django.contrib.staticfiles",
"django_pgschemas",
'customers',
],
},
"default": { # represents all dynamic tenants
"TENANT_MODEL": "customers.Client",
"DOMAIN_MODEL": "customers.Domain",
"APPS": [
"django.contrib.auth",
"django.contrib.sessions",
"fin.apps.FinConfig",
"users.apps.UsersConfig",
'django_plotly_dash',
'constance.backends.database',
'constance',
'django.contrib.admin',
'django.contrib.messages',
'django.contrib.staticfiles',
'fontawesomefree',
'bootstrap_modal_forms',
'widget_tweaks',
'crispy_forms',
'flatpickr',
'bootstrap4',
'django_extensions',
'rest_framework',
],
"URLCONF": "mysite.urls",
"CLONE_REFERENCE": "refschema",
},
}
INSTALLED_APPS = []
for schema in TENANTS:
INSTALLED_APPS += [app for app in TENANTS[schema]["APPS"] if app not in INSTALLED_APPS]
ROOT_URLCONF = TENANTS["default"]["URLCONF"]`
Check whether it's possible to have django.contrib.auth
only in default
and not in public
. Got report of errors.
This condition will always skip adding the search path if PGSCHEMAS_LIMIT_SET_CALLS is True.
Not sure how to add a test for that. Also I see there are some refactors planned for the tests
Bumping to Django 4.1 is currently not possible as
django-pgschemas 0.9.0 depends on django<4.1 and >=3.1
Apologies if this is answered elsewhere but I've scoured the django-tenants issues list as well as here and stack overflow and turned up nothing.
What I want is to have a public admin user that has permissions only to modify tenants and domains, and then each tenant will have their own admin user for modifying their own data. I've been able to mostly solve this via a 'root' static tenant, but that inherits from default, meaning it gets all the apps/ models that are defined there.
TENANTS = {
'public': {
'APPS': [
'django.contrib.contenttypes',
'django.contrib.staticfiles',
'django.contrib.auth',
'django.contrib.admin',
'django.contrib.sessions',
#...
'django_pgschemas',
#...
'myproj.accounts',
'myproj.patrons',
],
'TENANT_MODEL': 'patrons.Patron',
'DOMAIN_MODEL': 'patrons.Domain',
},
'default': {
'APPS': [
'django.contrib.auth',
'django.contrib.admin',
'django.contrib.sessions',
'django.contrib.staticfiles',
'django.contrib.messages',
'rest_framework.authtoken',
'myproj.accounts',
'myproj.coolstuff', # These should be available to all dynamic tenants
'myproj.awesomethings', # and editable in a tenant admin
],
'URLCONF': ROOT_URLCONF,
},
'root': {
'APPS': [
'django.contrib.auth',
'django.contrib.admin',
'django.contrib.sessions',
'django.contrib.staticfiles',
'django.contrib.messages',
'rest_framework.authtoken',
'myproj.patrons', # I only want the models here available to the root tenant; however coolstuff and awesomethings show up as well
],
'DOMAINS': ['localhost'],
'URLCONF': ROOT_URLCONF,
}
}
This is working, but exposes the default apps to the root user, which I don't want, since only tenants will use coolstuff and awesomethings. It's almost like I need a dynamic default and a static default. Is there any way to achieve what I want (without resorting to a lot of custom admin code) ?
running ...
"...makamigrations" and "./manage.py migrate -s public" runs successfully, but
"./manage.py migrate" produces the following:
"django.db.utils.ProgrammingError: permission denied for database webdb"
partial Traceback (most recent call last):
File "/var/www/vhosts/website/.pyenv/versions/3.9.1/lib/python3.9/site-packages/django/db/backends/utils.py", line 82, in _execute
return self.cursor.execute(sql)
psycopg2.errors.InsufficientPrivilege: permission denied for database webdb
Also, I don't see the additional static schemas, just 'public'
thanks in advance
I'm still digging into this, but it looks like when I use LoginRequiredMixin, the reverse for the login url returns incorrect value under certain circumstances. Here's the background:
settings.py
LOGIN_URL = "user_login" # or whatever your login url name might be
urls.py (simplified)
/home/ goes to a simple TemplateView
/about/ goes to the same TemplateView, with LoginRequiredMixin
/accounts/ goes to the accounts app urls
accounts/urls.py
/login/ goes to the login authentication view, url name: "user_login"
I have set up two tenants.
Client1
domain: app.mydomain.com
folder: client1
schema_name: client1
Client2
domain: app.mydomain.com
folder: client2
schema_name: client2
If I start the server and go any view for Client1 (app.mydomain.com/client1/home/ or app.mydomain.com/client1/about/), all works well.
Now, if I go to home for Client2 (app.mydomain.com/client2/home/), no problem.
But as soon as I go to a view with LoginRequiredMixin (app.mydomain.com/client2/about/), I get problems. Instead of going to app.mydomain.com/client2/accounts/login/ I'm getting redirects to app.mydomain.com/client1/accounts/login/
This same thing happens in reverse if I start the server, go to a Client2 url, and then try to go to a Client1 url that uses LoginRequiredMixin. (goes to app.mydomain.com/client2/accounts/login/ rather than the expected app.mydomain.com/client1/accounts/login/)
I verified by copying LoginRequiredMixin to my own project and doing something like this within the get_login_url method (I know, debugging by print statement is evil, but it's easy to replicate):
def get_login_url(self):
"""
Override this method to override the login_url attribute.
"""
login_url = self.login_url or settings.LOGIN_URL
print("get_login_url login_url: ", str(login_url))
print("get_login_url reverse(login_url): ", reverse(str(login_url)))
print("get_login_url schema_name: ", connection.schema.schema_name)
if not login_url:
raise ImproperlyConfigured(
"{0} is missing the login_url attribute. Define {0}.login_url, settings.LOGIN_URL, or override "
"{0}.get_login_url().".format(self.__class__.__name__)
)
return str(login_url)
Result (after going to a url for the second client from the initial example above):
get_login_url login_url: user_login
get_login_url reverse(login_url): /client1/accounts/login/
get_login_url schema_name: client2
Any recommendations? Anyone else experiencing this?
In some contexts where querying database would mean additional time cost (management commands,) we're using raw schema descriptors to describe dynamic tenants. This breaks the contract and is currently failing silently. Let's protect this variable and raise an exception when accessed unsafely.
You are not supposed to create a dynamic tenant whose schema_name
is the clone reference. If the clone reference was added as an afterthought, and there is already a dynamic tenant with that name, we'll let that explode, I guess?
What if you don't need dynamic tenants at all, or just want to start with a couple of static tenants?
A db with two schemas:
Setup the following migration script
from django.db import migrations
from django.db.migrations import RunPython
create = """
DROP FUNCTION IF EXISTS reproduce_error();
CREATE OR REPLACE FUNCTION reproduce_error()
RETURNS TEXT AS
$func$
BEGIN
RETURN (select version());
END
$func$ LANGUAGE plpgsql;
"""
delete = "DROP FUNCTION IF EXISTS reproduce_error();"
def forwards_func(_, schema_editor):
schema_editor.execute(create, params=None)
def reverse_func(_, schema_editor):
schema_editor.execute(delete, params=None)
class Migration(migrations.Migration):
dependencies = [
("business", <former_script>),
]
operations = [RunPython(forwards_func, reverse_func)]
python manage.py migrate business --schema public
The reproduce_error
function is in the public schema.
python manage.py migrate business --schema reference_tenant
The reproduce_error
function:
The reproduce_error
function:
By removing DROP FUNCTION IF EXISTS reproduce_error();
in the create
above, the issue is not reproduced.
(In case further interactive discussions will be necessary, the problem was written at https://gitter.im/django-pgschemas/community too)
I'm in a use case where I'm looking for django-tenant's schema_context decorator to execute code from outside of schema.
I couldn't find anything by myself. Can anyone give me a clue for how to do that? Thanks!
I have a number of celery tasks that (will) operate on individual tenants. I can write a wrapper to loop over these tasks, or use a request object to obtain the current tenant, but I'm curious about a general method for obtaining the contextually current tenant. This is especially useful for running such tasks from a management command - something like
./manage.py runschema my_command -s schema1 # starts, e.g., tasks.my_task.delay() to run within the celery process
my_command
will fire off a task, but the task will of course run in a different process than the management command; so passing the tenant ID or schema name to the task will be required. How do I obtain the current tenant within my_command? I thought it would be on the connection but doesn't seem to be available there. I'm looking for something like this:
SELECT current_schema();
(from https://www.postgresqltutorial.com/postgresql-schema/)
django-pgschemas/pyproject.toml
Line 21 in 02506a6
Maybe could be better to reference excluding next minor version and not for exclude all patch for actual minor:
django = ">=4.0,<4.3"
instead of
django = ">=4.0,<=4.2"
this way i can upgrade for 4.2.1, 4.2.2, etc
Following the docs, and implemented the TENANTS
dict which i later on applied the python manage.py migrateschema -s public
and python manage.py migrateschema
respectively but the apps i created do not show in either schemas including the shared app which hinders me from creating a client with the django shell.
` TENANTS = {
"www": {
"APPS": [
'django.contrib.admin',
"django.contrib.auth",
"django.contrib.sessions",
"rae_profile",
],
"DOMAINS": ["raedarr.com"],
"URLCONF": "rae_profile.urls",
},
"public": {
"APPS": [
'django.contrib.admin',
"django.contrib.auth",
'django.contrib.sessions',
"django.contrib.contenttypes",
"django.contrib.staticfiles",
"django_pgschemas",
"pwa",
"shared_app"
],
"TENANT_MODEL": "shared_app.Client",
"DOMAIN_MODEL": "shared_app.Domain",
},
"default": {
"APPS": [
'django.contrib.admin',
"django.contrib.auth",
"django.contrib.sessions",
'django.contrib.sites',
"post_office",
'hr.apps.HrConfig',
"chat.apps.ChatConfig",
'crm',
'payroll.apps.PayrollConfig',
'invoice.apps.InvoiceConfig',
'benefits.apps.BenefitsConfig',
'transport.apps.TransportConfig',
'leave.apps.LeaveConfig',
'estate.apps.EstateConfig',
'attendance.apps.AttendanceConfig',
'revenue.apps.RevenueConfig',
# 'allauth',
# 'allauth.account',
# 'allauth.socialaccount',
# 'allauth.socialaccount.providers.asana',
# 'allauth.socialaccount.providers.google',
# 'allauth.socialaccount.providers.linkedin',
# 'allauth.socialaccount.providers.linkedin_oauth2',
# ...
],
"URLCONF": "rae_profile.urls",
}
}`
Thanks
When in need of running tests in a specific static tenant, a test case for this should exist.
In real world projects, the executor-centered strategy is not completely future-proof, so I don't expect a lot of activity in this front. Let's change the --executor [sequential|parallel]
into just --parallel
for convenience.
Hi there!
I am in the process of lifting a py3.7/ django 3.2/ pgschemas 0.4.3 project up to py3.10/ django 4.1/ pgschemas 0.10.0 .
In the process, django wanted to create a bunch of new migrations for each app to update ID fields. No problem, I thought, except I'm now receiving the following error:
bash-5.1# ./manage.py migrate -s public
[sequential:public] Operations to perform:
[sequential:public] Apply all migrations: accounts, admin, auth, authtoken, foo, contenttypes, django_celery_beat, bar, baz, boz, sessions, frob
[sequential:public] Running migrations:
[sequential:public] Applying accounts.0003_auto_20220822_1143...Traceback (most recent call last):
File "/usr/local/lib/python3.10/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
psycopg2.errors.UndefinedTable: relation "authtoken_token" does not exist
This is odd because the app that defines that model is not included in the public
schema:
TENANTS = {
'public': {
'APPS': [
'django.contrib.contenttypes',
'django.contrib.staticfiles',
'django.contrib.gis',
'django.contrib.auth',
'django.contrib.admin',
'django.contrib.sessions',
...,
'rest_framework',
'rest_framework_gis',
# 'rest_framework.authtoken', see I am commented out
...
],
'TENANT_MODEL': 'patrons.Patron',
'DOMAIN_MODEL': 'patrons.Domain',
},
If I run manage.py migrate -s <my-tenant>
everything works ok. Another odd part of all this is that authtoken_token isn't even mentioned in any accounts
migrations, but evidently it defined its own ID-update migration which is where the error originates. So I'm not sure why it is getting reported by my migration.
Any ideas what I might be doing wrong? I am considering creating an interim release which includes rest_framework.authtoken as a separate migration step, but before going down that path I'm wondering if there's a better, cleaner approach.
Thanks in advance!
Add function to both DomainMixin
and TenantMixin
to prepend the main domain and folder to a given url.
I can get the subdomain approach to work but am having issues with the subfolder approach.
Using subdomain approach...
When I go to client1.localhost:8000 it takes me to the login screen for my app... http://client1.localhost:8000/accounts/login/?next=/
This works as expected.
Using subfolder approach...
When I go to clients.localhost:8000/client1/ it takes me to... http://clients.localhost:8000/accounts/login/?next=/client1/
This takes me to the "page not found error" and this message... No tenant for hostname 'clients.localhost'
How can I get the subfolder approach to work?
In cerrtains Macs building the psycopg2 package throws errors and it is easier to manage with the binary
It'd be great if we could choose between psycopg2 or psycopg2-binary at the project level or at least choose to ignore the psycopg2 dependency. (poetry does not seem to have any docs on sub-dependency override)
django==3.2.11
django-pgschemas==0.8.0
PGSCHEMAS_ORIGINAL_BACKEND=django.contrib.gis.db.backends.postgis
Observed:
./manage.py
Traceback (most recent call last):
File "/opt/app/./manage.py", line 21, in <module>
main()
File "/opt/app/./manage.py", line 17, in main
execute_from_command_line(sys.argv)
File "/usr/lib/python3.9/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
utility.execute()
File "/usr/lib/python3.9/site-packages/django/core/management/__init__.py", line 395, in execute
django.setup()
File "/usr/lib/python3.9/site-packages/django/__init__.py", line 24, in setup
apps.populate(settings.INSTALLED_APPS)
File "/usr/lib/python3.9/site-packages/django/apps/registry.py", line 114, in populate
app_config.import_models()
File "/usr/lib/python3.9/site-packages/django/apps/config.py", line 301, in import_models
self.models_module = import_module(models_module_name)
File "/usr/lib/python3.9/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 850, in exec_module
File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
File "/usr/lib/python3.9/site-packages/django/contrib/auth/models.py", line 3, in <module>
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
File "/usr/lib/python3.9/site-packages/django/contrib/auth/base_user.py", line 48, in <module>
class AbstractBaseUser(models.Model):
File "/usr/lib/python3.9/site-packages/django/db/models/base.py", line 122, in __new__
new_class.add_to_class('_meta', Options(meta, app_label))
File "/usr/lib/python3.9/site-packages/django/db/models/base.py", line 326, in add_to_class
value.contribute_to_class(cls, name)
File "/usr/lib/python3.9/site-packages/django/db/models/options.py", line 207, in contribute_to_class
self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())
File "/usr/lib/python3.9/site-packages/django/utils/connection.py", line 15, in __getattr__
return getattr(self._connections[self._alias], item)
File "/usr/lib/python3.9/site-packages/django/utils/connection.py", line 62, in __getitem__
conn = self.create_connection(alias)
File "/usr/lib/python3.9/site-packages/django/db/utils.py", line 204, in create_connection
backend = load_backend(db['ENGINE'])
File "/usr/lib/python3.9/site-packages/django/db/utils.py", line 111, in load_backend
return import_module('%s.base' % backend_name)
File "/usr/lib/python3.9/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "/usr/lib/python3.9/site-packages/django_pgschemas/postgresql_backend/base.py", line 7, in <module>
from .introspection import DatabaseSchemaIntrospection
File "/usr/lib/python3.9/site-packages/django_pgschemas/postgresql_backend/introspection.py", line 8, in <module>
class DatabaseSchemaIntrospection(original_backend.DatabaseIntrospection): # pragma: no cover
AttributeError: module 'django.contrib.gis.db.backends.postgis.base' has no attribute 'DatabaseIntrospection'
Expected:
manage.py commands (and django in general) function correctly.
It's useful to run a command on all tenant-like schemas.
Investigate, it works good with whowill
but for some reason it's not working with migrate?
I have a bunch of scheduled and periodic tasks that currently run under celery. No problem for a single-tenant architecture, but how do I tell celery to run these tasks when it only knows about the public schema? Couple of thoughts:
To summarize: I want celery beat and other tasks to look at their tables within each pg schema, not just public.
Anything I'm missing? It looks like django-tenants has a "schema_context" context processor but I don't see that in django-pgschemas.
I'm finally getting around to putting some Django tests. I am successfully using a REFERENCE_SCHEMA
in my project but I am not seeing it clone when it running with manage.py test --keepdb
. My expectation is that the test
schema/tenant would be using my clone schema. It runs the regular migrations route instead. I visited the docs but I couldn't find anything to help resolve this. Could this be a misconfiguration on my part?
Hi, @lorinkoz . I was testing the new release but I get an infinite recursion when I swap out psycopg2 for psycopg3. Should psycopg3 be supported and working? For visibility, I'm installing the requirement psycopg[binary,pool]==3.1.9
in place of psycopg2-binary==2.9.6
.
The _get_schemas_from_options
function is using a set to store the possible tenants that will be affected by the command but it doesn't preserve the ordering when they are fetched from the database
Is it possible to control schemas in more than one database with a smart routing?
Current challenges:
CLONE_REFERENCE
must always be on every database)Django runs migrations on apps in INSTALLED_APPS. Does runschema
select the apps from config and run migrations or does it just run all migrations and fake the non-associated apps?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.