Giter Site home page Giter Site logo

makinacorpus / django-safedelete Goto Github PK

View Code? Open in Web Editor NEW
677.0 31.0 122.0 377 KB

Mask your objects instead of deleting them from your database.

Home Page: https://django-safedelete.readthedocs.io/

License: BSD 3-Clause "New" or "Revised" License

Python 98.51% CSS 0.08% HTML 1.42%
django python

django-safedelete's Introduction

Django safedelete

https://coveralls.io/repos/makinacorpus/django-safedelete/badge.png

What is it ?

For various reasons, you may want to avoid deleting objects from your database.

This Django application provides an abstract model, that allows you to transparently retrieve or delete your objects, without having them deleted from your database.

You can choose what happens when you delete an object :
  • it can be masked from your database (SOFT_DELETE, the default behavior)
  • it can be masked from your database and mask any dependent models. (SOFT_DELETE_CASCADE)
  • it can be normally deleted (HARD_DELETE)
  • it can be hard-deleted, but if its deletion would delete other objects, it will only be masked (HARD_DELETE_NOCASCADE)
  • it can be never deleted or masked from your database (NO_DELETE, use with caution)

Example

# imports
from safedelete.models import SafeDeleteModel
from safedelete.models import HARD_DELETE_NOCASCADE

# Models

# We create a new model, with the given policy : Objects will be hard-deleted, or soft deleted if other objects would have been deleted too.
class Article(SafeDeleteModel):
    _safedelete_policy = HARD_DELETE_NOCASCADE

    name = models.CharField(max_length=100)

class Order(SafeDeleteModel):
    _safedelete_policy = HARD_DELETE_NOCASCADE

    name = models.CharField(max_length=100)
    articles = models.ManyToManyField(Article)


# Example of use

>>> article1 = Article(name='article1')
>>> article1.save()

>>> article2 = Article(name='article2')
>>> article2.save()

>>> order = Order(name='order')
>>> order.save()
>>> order.articles.add(article1)

# This article will be masked, but not deleted from the database as it is still referenced in an order.
>>> article1.delete()

# This article will be deleted from the database.
>>> article2.delete()

Compatibilities

  • Branch 0.2.x is compatible with django >= 1.2
  • Branch 0.3.x is compatible with django >= 1.4
  • Branch 0.4.x is compatible with django >= 1.8
  • Branch 0.5.x is compatible with django >= 1.11
  • Branch 1.0.x, 1.1.x and 1.2.x are compatible with django >= 2.2
  • Branch 1.3.x is compatible with django >= 3.2 and Python >= 3.7

Current branch (1.3.x) is tested with :

  • Django 3.2 using python 3.7 to 3.10.
  • Django 4.0 using python 3.8 to 3.10.
  • Django 4.1 using python 3.8 to 3.10.
  • Django 4.2 using python 3.8 to 3.11.

Installation

Installing from pypi (using pip).

pip install django-safedelete

Installing from github.

pip install -e git://github.com/makinacorpus/django-safedelete.git#egg=django-safedelete

Add safedelete in your INSTALLED_APPS:

INSTALLED_APPS = [
    'safedelete',
    [...]
]

The application doesn't have any special requirement.

Configuration

In the main django settings you can activate the boolean variable SAFE_DELETE_INTERPRET_UNDELETED_OBJECTS_AS_CREATED. If you do this the update_or_create() function from django's standard manager class will return True for the created variable if the object was soft-deleted and is now "revived".

By default, the field that indicates a database entry is soft-deleted is deleted, however, you can override the field name using the SAFE_DELETE_FIELD_NAME setting.

Documentation

The documentation is available here. Generate your own documentation using:

tox -e docs

Licensing

Please see the LICENSE file.

Contacts

Please see the AUTHORS file.

https://drupal.org/files/imagecache/grid-3/Logo_slogan_300dpi.png

django-safedelete's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-safedelete's Issues

Undelete does nothing when using DELETED_INVISIBLE

This is actually a pre-existing one I've been running into on Django 1.7/1.8.

When attempting to undelete (save) a deleted model, the _base_manager is used by Django to create the "base_qs" to perform the update from:

base_qs = cls._base_manager.using(using)
...
updated = self._do_update(base_qs, using, pk_val, values, update_fields, forced_update)

Because the _base_manager is the SafeDeleteManager, only model instances where deleted__isnull=True are considered. This returns and empty set of course because we're attempting to save an instance where deleted is not null.

As a result, _do_update returns False, since no records were updated, and django then attempts to insert a new record, which defeats the purpose of undeleting.

So far, the only workaround I've found is to set _base_manager = models.Manager(), but this has some other negative side-effects, such as causing reverse managers from instances with ForeignKeys to the SafeDelete model to not filter out deleted models.

handle related managers for custom through models

I used a SOFT_DELETE policy on a "through" model for a ManyToManyField. When i delete the relationship, the related object is still appearing via the related manager.

# models.py
from django.db import models
from safedelete.models import SoftDeleteMixin
from safedelete.models import SOFT_DELETE

class Foo(models.Model):
    bars = models.ManyToManyField('Bar', through='FooBar')

class Bar(models.Model):
    pass

class FooBar(SafeDeleteMixin):
    _safedelete_policy = SOFT_DELETE
    foo = models.ForeignKey(Foo)
    bar = models.ForeignKey(Bar)

Let's create one instance of each, plus a relation:

> foo = Foo.objects.create()
> bar = Bar.objects.create()
> foobar = FooBar.objects.create(foo=foo, bar=bar)
> FooBar.objects.count()
1
> foo.bars.count()
1

Now, let's delete the relation:

> foobar.delete()
> FooBar.objects.count()
0
> foo.bars.count()
1

Note that foo still thinks it is related to bar. Of course, a relation exists in the database, but it's supposed to be "deleted". i'm thinking that foo.bars.count() should return 0 in that case. We would have to override the related manager for that ManyToManyField.

using 0.3.2

Separate tests

Tests like SimpleTest.test_hard_delete_nocascade only rely on 2 models of which 1 had a ForeignKey to the other. Because there are other models in the mix, that can mess up the tests which caused bug #56. Tests should be put in a subfolder and multiple files that each test a specific policy for example. It would weed out some perhaps future bugs that come with too tightly coupled tests.

Trying to get ValuesListQuerySet throws "TypeError: _clone() takes exactly 1 argument (2 given)"

I defined an extremely simple SafeDeleteModel and when I try to get a ValuesListQuerySet, the following error is thrown. Any idea why this is happening? Willing to contribute a fix, but could use some guidance.

TypeError: _clone() takes exactly 1 argument (2 given)

My model:

class DumbModel(SafeDeleteModel):
    is_thing = models.BooleanField(default=False)

My code:

In [1]: from app.models import DumbModel
In [2]: DumbModel.objects.all().values_list()
Out[2]: <repr(<django.db.models.query.ValuesListQuerySet at 0x106df54d0>) failed: TypeError: _clone() takes exactly 1 argument (2 given)>

In [3]: DumbModel.objects.all().values_list()[0]
Out [3]: TypeError: _clone() takes exactly 1 argument (2 given)

Django version: 1.8.14
django-safedelete version: 0.4.4

Deletion of object is immediately reversed by save() method

Using, for example, the SOFT_DELETE policy, I'm finding that an object is correctly set with self.deleted = timezone.now()(https://github.com/makinacorpus/django-safedelete/blob/master/safedelete/models.py#L137). But then in the save() function, it is immediately undeleted. This is because keep_deleted is defaulted to False, which results in the deleted field being set to None. The object is then saved as if the soft delete never occurred. For extra info, if I momentarily set the arg keep_deleted to True in the package save method, everything works.

Any clues as to what I'm getting wrong here would be much appreciated :)

How to use no-delete?

As advertised in the docs:

You can choose what happens when you delete an object :

  1. it can be masked from your database (soft delete)
  2. it can be normally deleted (hard delete)
  3. it can be hard-deleted, but if its deletion would delete other objects, it will only be masked
  4. it can be never deleted or masked from your database (no delete, use with caution)

I could not find option 4. Could you please clarify, how to implement no-delete with django-safedelete?

Thanks!

QuerySet first() method gives Cannot filter a query once a slice has been taken.

Hey guys!

It seems that this code change gave me an issue, as following:

User.objects.filter(email="[email protected]").first()

Gives me:

File "/Users/pauloostenrijk/webprojects/app/app/users/import_export/resources.py", line 57, in before_import
user = User.objects.all().filter(email=row['email']).first()
File "/Users/pauloostenrijk/.virtualenvs/app/lib/python2.7/site-packages/django/db/models/query.py", line 550, in first
objects = list((self if self.ordered else self.order_by('pk'))[:1])
File "/Users/pauloostenrijk/.virtualenvs/app/lib/python2.7/site-packages/django/db/models/query.py", line 258, in __iter__
self._fetch_all()
File "/Users/pauloostenrijk/.virtualenvs/app/lib/python2.7/site-packages/safedelete/queryset.py", line 121, in decorator
self._filter_visibility()
File "/Users/pauloostenrijk/.virtualenvs/app/lib/python2.7/site-packages/safedelete/queryset.py", line 98, in _filter_visibility
"Cannot filter a query once a slice has been taken."
AssertionError: Cannot filter a query once a slice has been taken.

Here are some implementation details:

from safedelete.managers import SafeDeleteManager

class UserManager(BaseUserManager, SafeDeleteManager):
@python_2_unicode_compatible
class User(SafeDeleteModel, AbstractBaseUser, TimeStampedUUIDModel, PermissionsMixin):
    objects = UserManager()

Version: 0.4.1

allow_tags deprecated in Django 2.0

Warning below appears in Django 1.9+

RemovedInDjango20Warning: Deprecated allow_tags attribute used on field <function highlight_deleted at 0x7f32cd9ef9d8>. Use django.utils.html.format_html(), format_html_join(), or django.utils.safestring.mark_safe() instead.

I think you just need to wrap the html here with format_html() instead

SafeDeleteMixin is not a mixin

The name SafeDeleteMixin seems to say that the class is a Mixin when it's not because it inherits from django.db.models. Wouldn't SafeDeleteModelbe a better name in this case? It clears up some confusion regarding inheritance.

Please update Pypi Package

In light of recent changes (especially moving version information into setup.py) could you please update the pypi-Package?

How to create custom mangers for models inheriting SafeDeleteModel?

Per the docs it seems that it should be possible to add additional custom managers to a model, if the SafeDeleteModel is initializing objects property, but this doesn't seem to be the case. If I add a custom manager to a model, model._default_manager will be that manager.

Shouldn't SafeDeleteModel define a default_manager_name?

safedelete fails to cascade properly with inheritance

Somewhat related to #55

While figuring out how to add a db index to help with query performance (I know it was added in #67, but only for the 0.3.x branch), I decided to subclass the SafeDeleteMixin.

# Override safedelete mixin to enable db index.
class CustomSafeDeleteModel(SafeDeleteMixin):
    deleted = models.DateTimeField(editable=False, null=True, db_index=True)

    class Meta:
        abstract = True

The culprit appears to be that it only checks the first-level of __bases__ to see if a model is a safedelete model:

def is_safedelete(related):

While my current issue can be solved in other ways, this does prevent django abstract model inheritance from working properly. It only manifests itself when setting the _safedelete_policy to safedelete.models.SOFT_DELETE_CASCADE, so it's pretty subtle.

For anyone looking for a quick short-term hack around this, you can do this so that is_safedelete works properly:

# Override safedelete mixin to enable db index.
class CustomSafeDeleteMixin(object):
    deleted = models.DateTimeField(editable=False, null=True, db_index=True)

    class Meta:
        abstract = True

class MyModel(SafeDeleteMixin, CustomSafeDeleteMixin):
   # ...

Document how to migrate project using <0.4 to >= 0.4

The change from boolean to datetime is a good one, but I think some documentation on how to handle the migration is really needed.
PostgreSQL can't simply convert booleans to datetimes (some others might convert the int 1 to timestamp 1, not sure).

The correct way to go about this would be some manually crafted migrations:

  1. Add a datetime column named new_delete
  2. Fill the new_delete column based on the delete column (False = None, True = timezone.now())
  3. Rename the deleted column to old_deleted
  4. Rename the new_deleted to deleted
  5. Also have the backwards migrations that do it the other way around.
  6. At least 2 releases/deployments later (or how ever many rollbacks you want to be able to do) add a migration to remove the old_deleted column.

By at least documenting this you give people some guide on how to handle version upgrade without automatically marking all soft delete items as deleted (deleted_isnull=True doesn't match True nor False)

queryset method union returns deleted objects

When I do the union of two querysets I get deleted objects back:
qs1.union(qs2)

Each individual query does not give the deleted object back. This is on a model set with SOFT_DELETE as safedelete_policy

Deleted instances still appear in formfields (Heisenbug?)

I have a model for which I override Django Admin's formfield_for_foreignkey() like so:

class MyCustomAdmin(CustomSafeDeleteAdmin):

    def get_queryset(self, request):
        qs = super(MyCustomAdmin, self).get_queryset(request)
        return qs.filter(user=request.user)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        user= request.user
        if db_field.name == 'foo':
            kwargs['queryset'] = Foo.objects.filter(user=user)
        return super(MyCustomAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

The Foo model inherits from SafeDeleteModel, so its default objects manager should be handled by the default SafeDeleteManager.

Problem is I am still seeing deleted Foo instances in formfield ForeignKey dropdowns, but not if I debug Foo.objects.filter(user=user) or Foo.objects.all(), and then if I step through, they don't appear in the dropdown, hence Heisenbug :(

Is this releated to the note here on ForeignKey visibility?

Django will stop me from saving the model with a deleted FK, it will give the error Select a valid choice. That choice is not one of the available choices

ATM the only way I can reliably ensure deleted instances don't appear is to append .exclude(deleted__isnull=False) to all querysets, but this is not desirable, the default manager should ensure they don't exist?

Using safedelete 0.4.1 with queryset.py from PR #77, Django 1.11.1 and Python 3.6.1 (Note issue happens with or without PR 77 patch)

For extra ref I am overiding some django admin functions so I can split safedelete access in admin between su/staff and 'lite' admin users

from safedelete.admin import SafeDeleteAdmin, highlight_deleted

class CustomSafeDeleteAdmin(SafeDeleteAdmin):
    """
    Overriding this convenience class from django-safedelete, as we want:
        - Delete to work 'as in' for non su-staff i.e. User has no idea deleted model instances still exist
        - Allow su/staff to see all instances, deleted or not, and recover them if needs be

    Notes:
        - If su/staff try deleting an already deleted instance, this is a noop
    """

    # override django-safedelete method so deleted instances are hidden from non su/staff
    def get_queryset(self, request):
        qs = super(CustomSafeDeleteAdmin, self).get_queryset(request)
        if request.user.profile.user_can_undelete():
            return qs
        else:
            # assuming the model in question inherits SafeDeleteModel, this will exclude deleted model instances (the default)
            return self.model._default_manager.all()

    def get_list_display(self, request):
        list_display = super(CustomSafeDeleteAdmin, self).get_list_display(request)
        if request.user.profile.user_can_undelete():

            # highlight_deleted overrides the default instance 'Name'
            list_display = list(list_display)
            if 'name' in list_display:
                list_display.remove('name')
            if 'Name' in list_display:
                list_display.remove('Name')
            return [highlight_deleted] + list_display
        else:
            return list_display

    # hide undelete action from admin changelist page actions if user not su/staff
    def get_actions(self, request):
        actions = super(CustomSafeDeleteAdmin, self).get_actions(request)
        if not request.user.profile.user_can_undelete():
            if 'undelete_selected' in actions:
                del actions['undelete_selected']
        return actions

    # hide deleted list_filter from admin changelist page if user not su/staff
    def get_list_filter(self, request):
        list_filter = super(CustomSafeDeleteAdmin, self).get_list_filter(request)
        if request.user.profile.user_can_undelete():
            if isinstance(list_filter, list):
                list_filter = tuple(list_filter)
            return SafeDeleteAdmin.list_filter + list_filter
        else:
            return list_filter

Can someone explain what maked in cascade means?

I'm looking at the docs and am a bit confused by the database terms used.

https://django-safedelete.readthedocs.io/en/latest/models.html

Like
This will make the objects be automatically masked (and not deleted) and all related objects, when you call the delete() method. They will be masked in cascade.

My case is that I have categories in my Forum app and if I accidentally delete or someone gains access and deletes the topic all posts in it are deleted. This scares me.

So, I want SafeDelete. Should I use safedelete.models.SOFT_DELETE_CASCADE or safedelete.models.SOFT_DELETE or safedelete.models.HARD_DELETE_NOCASCADE

test with django 1.10 and master

I was looking for a mixin that handles the edge cases I am encountering attempting to add masking to a model that I never want to be deleted. This project seems to the what I am looking for. I noticed the tests do not run on django 1.10 so I am raising this issue

Django 1.9 compatibility

models.py calls safedelete_mixin_factory(SOFT_DELETE) at import time. This breaks against the current Django master branch, so it will likely be broken on Django 1.9.

I don't fully understand the issue yet. Can we move that call somewhere else, so it is executed after the app registry is ready?

Here is an example traceback:

Traceback (most recent call last):
  File "./manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/rene/.virtualenvs/academy/lib/python3.4/site-packages/django/core/management/__init__.py", line 331, in execute_from_command_line
    utility.execute()
  File "/home/rene/.virtualenvs/academy/lib/python3.4/site-packages/django/core/management/__init__.py", line 305, in execute
    django.setup()
  File "/home/rene/.virtualenvs/academy/lib/python3.4/site-packages/django/__init__.py", line 18, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/home/rene/.virtualenvs/academy/lib/python3.4/site-packages/django/apps/registry.py", line 85, in populate
    app_config = AppConfig.create(entry)
  File "/home/rene/.virtualenvs/academy/lib/python3.4/site-packages/django/apps/config.py", line 86, in create
    module = import_module(entry)
  File "/home/rene/.virtualenvs/academy/lib64/python3.4/importlib/__init__.py", line 109, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 2254, in _gcd_import
  File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
  File "<frozen importlib._bootstrap>", line 2226, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1200, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 1129, in _exec
  File "<frozen importlib._bootstrap>", line 1471, in exec_module
  File "<frozen importlib._bootstrap>", line 321, in _call_with_frames_removed
  File "/home/rene/.virtualenvs/academy/lib/python3.4/site-packages/safedelete/__init__.py", line 5, in <module>
    from .models import safedelete_mixin_factory
  File "/home/rene/.virtualenvs/academy/lib/python3.4/site-packages/safedelete/models.py", line 127, in <module>
    SoftDeleteMixin = safedelete_mixin_factory(SOFT_DELETE)
  File "/home/rene/.virtualenvs/academy/lib/python3.4/site-packages/safedelete/models.py", line 37, in safedelete_mixin_factory
    class Model(models.Model):
  File "/home/rene/.virtualenvs/academy/lib/python3.4/site-packages/django/db/models/base.py", line 94, in __new__
    app_config = apps.get_containing_app_config(module)
  File "/home/rene/.virtualenvs/academy/lib/python3.4/site-packages/django/apps/registry.py", line 239, in get_containing_app_config
    self.check_apps_ready()
  File "/home/rene/.virtualenvs/academy/lib/python3.4/site-packages/django/apps/registry.py", line 124, in check_apps_ready
    raise AppRegistryNotReady("Apps aren't loaded yet.")
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

Remove need for factory methods?

Curious, what is the reason for the factory methods to exists?
From what I've seen the mixins could easily be provided as stand-alone classes.

Currently it's impossible to override the SafeDeleteQueryset because of the current design

just submitting bug fixes for your documentation

on this page: http://django-safedelete.readthedocs.io/en/latest/managers.html , need this import, otherwise you get NameError not defined:

from safedelete.config import *

and this line here http://django-safedelete.readthedocs.io/en/latest/admin.html needs a comma, otherwise TypeError cannot convert str to tuple object implicitly:
list_filter = ("last_name",) + SafeDeleteAdmin.list_filter

new to django, im trying to add safedelete functionality to my project and service models for my app, it is challenging, a tutorial would be nice. heres what Im working on https://dpaste.de/Gxc1 , having issues seeing my service objects - I dont have the queryset set up properly with your package Im sure. I can see them in django admin though, highlight deleted isnt showing in red though, and a NAME is in the list_display instead of Service. Got everything mostly working.

Todo before 0.4.x release

  • Doc for post_*delete signals
  • fix #41
  • take a look at #16
  • remove Django 1.4 => 1.7 support and clean code.
  • Add DELETED_VISIBLE_BY_FIELD
  • Add SOFT_DELETE_CASCADE
  • Check the doc is up to date.

Can't install via a requirements.txt file.

If being installed via pip with a requirements file with Django and safedelete, it will fail because django-safedelete's setup.py imports django, which isn't installed yet (pip will run all package's setup.py before installing anything to try resolve the dependencies).

The only way to install this package is via a 2 step pip install process

  1. pip install django
  2. pip install django-safedelete
    which means it can't be done in a requirements file. (Or am I missing something?)

Solution is to avoid importing django in the setup.py file, but I don't see a nice way to do that since the version is being retrieved from a module that imports another module that imports django. Any suggestions?

Getting rid of Django 1.3 compatibility

Hello,

What would you think of gettign rid of Django 1.3 compatibility ? I'm currently working on improving the admin part of the module (https://github.com/Gagaro/django-safedelete/tree/improve_admin), and I have to do lots of workarounds to handle it. One would be to heavily change a template because Django 1.3 is missing one of the templatetags used in it.

Django 1.3 is no longer supported and supporting it make the code heavier. Does someone really need the 1.3 support ? What do you think about removing it ?

Model.refresh_from_db raises DoesNotExist

Calling Model.refresh_from_db on a soft deleted model will raise a Model.DoesNotExist exception. Should this be the expected behaviour? I could look into this and make a PR. But from guessing I would say it might require changing the behaviour of the QuerySet set as the default by django-safedelete. I really like how django-permanent distinguishes between showing all of the objects, the non-deleted objects, and even only the deleted objects.

>>> MyModel.objects.count()
2
>>> a.delete()
>>> MyModel.objects.count()
1
>>> MyModel.deleted_objects.count()
1
>>> MyModel.all_objects.count()
2
>>> MyModel._base_manager.count()
2

Maybe this behaviour is something more desirable that we should look into? Perhaps even implement both (all_with_deleted and the custom managers like in django-permanent).

SafeDeleteMixin is not abstract

As SafeDeleteMixin is not abstract it cause problems during flush, as django wants to flush it, but there is no real table was ever created.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.