Git Product home page Git Product logo

django-drip's Introduction

Django Drip

Build Status

Drip campaigns are pre-written sets of emails sent to customers or prospects over time. Django Drips lets you use the admin to manage drip campaign emails using querysets on Django's User model.

We wrote this specifically to scratch an itch at our startup Zapier. It currently runs all of our drip campaigns.

Read the docs or check out a demo.

Installing:

We highly recommend using pip to install django-drip, the packages are regularly updated with stable releases:

pip install django-drip

Next, you'll want to add drip to your INSTALLED_APPS in settings.py.

INSTALLED_APPS = (
    'django.contrib.contenttypes',
    'django.contrib.comments',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.admin',

    # Your favorite apps

    'drip',
)

Don't forget to add DRIP_FROM_EMAIL to settings.py, or else we will fall back to EMAIL_HOST_USER.

Finally, be sure to run python manage.py syncdb or python manage.py migrate drip to set up the necessary database tables.

python manage.py syncdb
# or...
python manage.py migrate drip

what the admin looks like what the admin looks like for the timeline

django-drip's People

Contributors

akoumjian avatar brad avatar bryanhelmig avatar budlight avatar guanlisheng avatar hwkns avatar jacebrowning avatar jarcoal avatar jsocol avatar jtrain avatar kmtracey avatar roycehaynes avatar sayar avatar syphar avatar timgates42 avatar

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  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

django-drip's Issues

Several test fail since AUTH_PROFILE_MODULE (deprecated) is not set.

AUTH_PROFILE_MODULE is not set in my project since it's deprecated since 1.5. As a result, many Drip tests calling it fail this way:

"SiteProfileNotAvailable: You need to set AUTH_PROFILE_MODULE in your project settings"

The list of affected test is:

ERROR: test_backwards_drip_class (drip.tests.DripsTestCase)
ERROR: test_custom_date_range_walk (drip.tests.DripsTestCase)
ERROR: test_custom_drip (drip.tests.DripsTestCase)
ERROR: test_custom_drip_static_datetime (drip.tests.DripsTestCase)
ERROR: test_custom_drip_static_now_datetime (drip.tests.DripsTestCase)
ERROR: test_custom_drip_with_count (drip.tests.DripsTestCase)
ERROR: test_custom_short_term_drip (drip.tests.DripsTestCase)
ERROR: test_day_fourteen_users_active (drip.tests.DripsTestCase)
ERROR: test_day_fourteen_users_inactive (drip.tests.DripsTestCase)
ERROR: test_day_seven_users_active (drip.tests.DripsTestCase)
ERROR: test_day_seven_users_inactive (drip.tests.DripsTestCase)
ERROR: test_day_two_users_active (drip.tests.DripsTestCase)
ERROR: test_day_two_users_inactive (drip.tests.DripsTestCase)
ERROR: test_day_zero_users (drip.tests.DripsTestCase)
ERROR: test_get_simple_fields (drip.tests.DripsTestCase)
ERROR: test_users_exists (drip.tests.DripsTestCase)

Any plans to return django-drip back to live?

Hi, django-drip contributors!

I've found your project recently and that's what I need for the newsletter in my Django project.
But your project doesn't work with custom User model and I see no activity since last year.
I see 59 forks (that's a lot!) of django-drip but I can't find any that works with custom User model.

Could you tell me if you're going to return your project back to live and to support (at least) Django 1.5 with custom Users? Or maybe you could advise some alternative to django-drip?

Cannot Run Tests with Django 1.8.4

I'm running Django 1.8.4 and cannot run tests. I also needed to install a forked version of django drip just to get it to run - see issue #51. I've looked through the app to try to figure out where this might be but it's beyond me.

Trying to to run tests produces:

Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
    utility.execute()
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 330, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 30, in run_from_argv
    super(Command, self).run_from_argv(argv)
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/base.py", line 393, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 74, in execute
    super(Command, self).execute(*args, **options)
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/base.py", line 444, in execute
    output = self.handle(*args, **options)
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/commands/test.py", line 90, in handle
    failures = test_runner.run_tests(test_labels)
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/test/runner.py", line 210, in run_tests
    old_config = self.setup_databases()
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/test/runner.py", line 166, in setup_databases
    **kwargs
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/test/runner.py", line 370, in setup_databases
    serialize=connection.settings_dict.get("TEST", {}).get("SERIALIZE", True),
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/db/backends/base/creation.py", line 368, in create_test_db
    test_flush=not keepdb,
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 120, in call_command
    return command.execute(*args, **defaults)
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/base.py", line 444, in execute
    output = self.handle(*args, **options)
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/commands/migrate.py", line 179, in handle
    created_models = self.sync_apps(connection, executor.loader.unmigrated_apps)
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/core/management/commands/migrate.py", line 318, in sync_apps
    cursor.execute(statement)
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/db/utils.py", line 97, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/home/vagrant/Envs/gitjobs/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 62, in execute
    return self.cursor.execute(sql)
django.db.utils.ProgrammingError: relation "auth_user" does not exist

Exception when viewing the email in Admin

I think this must have broken with the changes in #18, because the build_email method was removed there.

AttributeError at /orcas/admin/drip/drip/2/timeline/4/7/911/

'DripBase' object has no attribute 'build_email'

Request Method: GET
Request URL: http://127.0.0.1:8000/orcas/admin/drip/drip/2/timeline/4/7/911/
Django Version: 1.4.2
Exception Type: AttributeError
Exception Value:

'DripBase' object has no attribute 'build_email'

Exception Location: /home/bpitcher/.virtualenvs/jauntly/src/django-drip/drip/admin.py in view_drip_email, line 56

Error running manage.py migrate

I am on South 1.0 and Django 1.6.5, and added drip as per instructions, but get an error when I do migrate

Running migrations for drip:
 - Migrating forwards to 0003_auto__add_field_drip_message_class.
 > drip:0001_initial
FATAL ERROR - The following SQL query failed: ALTER TABLE "drip_sentdrip" ADD CONSTRAINT "user_id_refs_id_ca2f99a1" FOREIGN KEY ("user_id") REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED;
The error was: relation "auth_user" does not exist

Error in migration: drip:0001_initial
Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/django/core/management/__init__.py", line 399, in execute_from_command_line
    utility.execute()
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/django/core/management/__init__.py", line 392, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/django/core/management/base.py", line 242, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/django/core/management/base.py", line 285, in execute
    output = self.handle(*args, **options)
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/south/management/commands/migrate.py", line 111, in handle
    ignore_ghosts = ignore_ghosts,
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/south/migration/__init__.py", line 220, in migrate_app
    success = migrator.migrate_many(target, workplan, database)
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/south/migration/migrators.py", line 256, in migrate_many
    result = migrator.__class__.migrate_many(migrator, target, migrations, database)
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/south/migration/migrators.py", line 331, in migrate_many
    result = self.migrate(migration, database)
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/south/migration/migrators.py", line 133, in migrate
    result = self.run(migration, database)
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/south/migration/migrators.py", line 114, in run
    return self.run_migration(migration, database)
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/south/migration/migrators.py", line 85, in run_migration
    south.db.db.execute_deferred_sql()
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/south/db/generic.py", line 318, in execute_deferred_sql
    self.execute(sql)
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/south/db/generic.py", line 282, in execute
    cursor.execute(sql, params)
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/django/db/backends/util.py", line 69, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/django/db/backends/util.py", line 53, in execute
    return self.cursor.execute(sql, params)
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/django/db/utils.py", line 99, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/Users/somghosh/.virtualenvs/earthmiles/lib/python2.7/site-packages/django/db/backends/util.py", line 53, in execute
    return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "auth_user" does not exist

My User is defined in accounts/models.py as :

class User(AbstractUser):

and in settings, I have AUTH_USER_MODEL = 'accounts.User'

Exclude users, i.e. support for unsubscribing

I lack the ability to unsubscribe from the emails sent by drip. We're about to start using it for our customers, but anticipate that certain users will want to unsubscribe.

Is this something that could be integrated with Drip, or handled separately? How do others do it?

Timeline shows same user multiple times

The admin timeline is useful, but doesn't accurately reflect the ability of django-drip to weed out users that have been emailed in the past.

A user won't be sent the same campaign twice.

The timeline should only show the first time a user will be emailed.

Django signal triggers.

Might be cool to trigger off of any registered Django signal like User created, updated, deleted, etc...

namespace conflict with mock

This isn't a problem with django-drip==0.1.3, only with the latest source.
Steps to reproduce:

$ mkvirtualenv testpip
$ pip install mock -e \
git+https://github.com/zapier/django-drip.git#egg=django-drip
$ python
>>> from mock import patch
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: cannot import name patch

ManyToManyRel' object has no attribute 'parent_model

In utils.py at following line its hard to understand its like "tuple + tuple + list".
fields = Model._meta.fields + Model._meta.many_to_many + Model._meta.get_all_related_objects()
This is caused me error so I converted it to tuple(Model._meta.get_all_related_objects()).
However now I am getting error with following traceback:

File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\core\handlers\base.py" in get_response
  132.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\contrib\admin\options.py" in wrapper
  616.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\utils\decorators.py" in _wrapped_view
  110.                     response = view_func(request, *args, **kwargs)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\views\decorators\cache.py" in _wrapped_view_func
  57.         response = view_func(request, *args, **kwargs)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\contrib\admin\sites.py" in inner
  233.             return view(request, *args, **kwargs)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\drip\admin.py" in add_view
  83.             request, extra_context=self.build_extra_context(extra_context))
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\drip\admin.py" in build_extra_context
  78.         extra_context['field_data'] = json.dumps(get_simple_fields(User))
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\drip\utils.py" in get_simple_fields
  121.     return [[f[0], f[3].__name__] for f in get_fields(Model, **kwargs)]
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\drip\utils.py" in get_fields
  98.                 RelModel = field.related.parent_model

Exception Type: AttributeError at /admin/drip/drip/add/
Exception Value: 'ManyToManyRel' object has no attribute 'parent_model'

I am using djagno 1.8.5. Please advise.

Use AUTH_USER_MODEL in models.

Having updated to Django 1.5 and migrated my profile information onto an extended User model, drip does not allow my app to start:

django.core.management.base.CommandError: One or more models did not validate:
drip.sentdrip: 'user' defines a relation with the model 'auth.User', which has been swapped out. Update the relation to point at `settings.AUTH_USER_MODEL`.

May I suggest the following, in models.py:

try:
  from settings import AUTH_USER_MODEL
except:
  AUTH_USER_MODEL = 'auth.User'

...

user = models.ForeignKey(AUTH_USER_MODEL, related_name='sent_drips')

"Past" emails from db

Since we store these as SentDrips, it would be wise to list those instead of generated emails from the walk method.

PyPI package doesn't include templates

If you install django-drip from PyPI using pip install django-drip, the templates directory isn't included. Therefore, the view timeline and preview email functionality isn't included out of the box.

Decoupling email templates from drip

What do you guys think about allowing third party email content compilers to be used?

We currently use https://github.com/bradwhittington/django-templated-email for sending emails which is great (basically, you define the email in a django template file which can extend other templates, and send the email by referencing the template's filename).

The issue is it would make the easiest case harder probably, unless optional subject_template and body_html_template fields are left in the Drip model.

Other, less wasteful (no optional TextFields) options:

  1. I could be to make a OneToOneField from a new model DripEmailTemplate to Drip and add it as an Inline to the Drip admin in addition to an optional "template_name" field to send to django-templated-email.
  2. It may also be harder for the easiest case, but DripEmailTemplate could be referenced from a optional ForeignKey in Drip which would allow you to have multiple Drips use the same DripEmailTemplate

I'd be willing to take on this project but wanted to see if I could get it to work for more than just us.

strip_tags nuking <a> hrefs.

Since we turn HTML -> text via strip tags, we end up with borked links, IE:

<a href="http://example.com/">my example</a>

...turns into...

my example

...but should probably be...

my example (http://example.com/)

Also, this same sort of bug might exist for line breaks and such.

Rationale behind DRIP_FROM_EMAIL in settings.py?

Hello Zapier,

Great fan of your work! I am just curious as to the thought process behind the DRIP_FROM_EMAIL setting. Is there a reason why the from email is static? I figured you would want to be able to change the from email depending on the drip campaign unless I am missing a key point? Forgive me if there is something blatantly obvious.

P.S. As per usual for github users, I would be happy to contribute code if there is interest in a non-static from email and if it abides by the wishes of the project maintainers.

Drip breaks with Django 1.8

Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/Users/simon/src/uklo/venv/lib/python3.4/site-packages/django/core/management/__init__.py", line 338, in execute_from_command_line
    utility.execute()
  File "/Users/simon/src/uklo/venv/lib/python3.4/site-packages/django/core/management/__init__.py", line 312, in execute
    django.setup()
  File "/Users/simon/src/uklo/venv/lib/python3.4/site-packages/django/__init__.py", line 18, in setup
    apps.populate(settings.INSTALLED_APPS)
  File "/Users/simon/src/uklo/venv/lib/python3.4/site-packages/django/apps/registry.py", line 108, in populate
    app_config.import_models(all_models)
  File "/Users/simon/src/uklo/venv/lib/python3.4/site-packages/django/apps/config.py", line 198, in import_models
    self.models_module = import_module(models_module_name)
  File "/Users/simon/src/uklo/venv/lib/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 "/Users/simon/src/uklo/venv/lib/python3.4/site-packages/drip/models.py", line 7, in <module>
    from drip.utils import get_user_model
  File "/Users/simon/src/uklo/venv/lib/python3.4/site-packages/drip/utils.py", line 5, in <module>
    from django.db.models.related import RelatedObject
ImportError: No module named 'django.db.models.related'

From a quick search, there's some ideas as to what could be wrong here and how to fix it (but it's beyond me at the moment):

jazzband/django-simple-history#156

Bug in `drip.drips` using template source and not rendered template

I apologize if I'm mistaken, but it looks like you're using the template source and not the rendrered template for the HTML version of the email body.

See drips.drip:122

# check if there are html tags in the rendered template if len(plain) != len(body): email.attach_alternative(self.body_template, 'text/html')

It should reference the body local variable not self.body_template.

Can't install drip on django 1.11.5

[✓] pip install django-drip
[✓] Add 'drip' to your installed apps
[✓] Set DRIP_FROM_EMAIL
[✗] python manage.py migrate drip

....
....from django.db.models.related import RelatedObject
ImportError: No module named related

pip 9.0.1
Django 1.11.5
django-drip 0.7.1

Externalize QuerySet builder.

In addition, this should make the base not tied to User, but instead selectable off of something in the ContentType framework.

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.