django: modifying/extending 3rd party apps - django

a newbie django question
I want to use 3rd party app, but I need to make some mods to it (in this case, the app is django-registration, and I need to change things such as allowing registration without confirmation email)
Initially, I simply installed the app in the general site-packages folder, and changed the code there. Now that I put my code on bitbucket I need a way to be able to keep my mods in the repository in a usable way, and uploading the full python code doesn't sound like a good idea.
I guess the best way would be to keep the 3rd party app in site-packages, and create an app in my project to keep my changes. In my case, I'd create my-django-registration in my project, and then import this when I need it in my code, rather than django-registration.
I also read about virtualenv, but I think that's mostly used for being able to use multiple environments in the same machine (in fact, somewhere it advises against changing the modules installed in the virtualenv), and doesn't help me with keeping my changes in a repository.
Any comments welcome!
Thanks

In general, you should reuse and override the behavior in 3rd party apps and not modify their sources.
What you'll most often encounter is that apps ship models that may not necessarily cover your needs, but do most of the work; you'll have forms that are almost perfect, but need that little something; you'll have views that would be perfect if you can just change one thing; you'll have URLs that are sane, but you need something more from them.
In most cases, that would just require that you create a custom app and rewire everything. Ship your own URLs that map to views that you've extended and overrode methods for custom behavior; supply it with a model form who's Meta is using the new model that you've extended from the original; so forth...
That's just the tip of the iceberg of what you can do, there's more ways when your creative. I can give you an example of how I've used the RegistrationProfile model, but shipped my own URL patterns and a custom class-based view that handled the registration process.
Now, where virtualenv comes into play is that you'll most likely be using pip to specify and supply your required dependencies in the requirements file format. That's when you want to say: "I've extended the django-registration app, but it won't work cleanly with just any version. It has to be of release X", or , "a checkout from the repository of commit Y".

This blog post that adresses this issue is extremely helpful. For convenience I copy-paste it here:
You don’t touch external app code
You are not supposed to edit the code from an external app. Unless you fork it first on github.
So, how to override without forking:
Overriding a template
If you want to override templates/userena/activate_fail.html, then all you have to do is create your own templates/userena directory and make your own activate_fail.html in it.
Overriding a url
Probably the first thing you should check in an external app is its urls.py. Views that are properly coded should support plenty of arguments. For example, userena has a signup view with such a signature (at the time of writing):
def signup(request, signup_form=SignupForm,
template_name='userena/signup_form.html', success_url=None,
extra_context=None):
This means that you can replace the form used by the signup view. To do so, open your urls.py, add what we are going to need at the top:
from userena import views as userena_views
from yourforms import YourSignupForm
Then, find the include the external app’s urls, something like:
url(r'^userena/', include('userena.urls')),
Before that, add your url override:
url(r'^userena/signup/$', userena_views.signup, {'signup_form': YourSignupForm}, name='userena_signup'),
url(r'^userena/', include('userena.urls')),
Now, your custom url definition will be the first to be hit when a visitor hits /userena/signup/. Which means that /userena/signup/ will use YourSignupForm instead of userena’s signup form.
This trick works with any view argument. The ones you should see the most often are:
template_name: lets you change the template name
extra_context: lets you add a dict that will be added to the
context
Almost every view should have these arguments.
Overriding a view
Overriding a view requires to override the url of the view you want to replace. If you want your own signup view to be used, then just override the url:
import yourviews
# ...
url(r'^userena/signup/$', yourviews.yoursignup, name='userena_signup'),
url(r'^userena/', include('userena.urls')),
Decorating a view
Decorating a view is like overriding a view, but reuses the external app’s view. Basically, it’s the same than overriding a view (see above), but your view will look like this
from userena import views as userena_views
def yoursignup(request):
# do stuff before userena signup view is called
# call the original view
response = userena_views.signup(request)
# do stuff after userena signup view is done
# return the response
return response
Forking an app
If you are not familiar with pip and virtualenv first, please read the post about using pip and virtualenv first.
For example:
You installed django-userena as such: pip install django-userena
First you should uninstall it: pip uninstall django-userena
Then go on the app’s github page
Click on the fork button
This will make you a repository with a copy of django-userena
Install it as such: pip install -e
git+git#github.com:your-username/django-userena.git#egg=django-userena
Then you can edit the code in yourenv/src/django-userena
Push your commits
Credits to the post writer!

I think the neatest way to accomplish what you look for would be to fork django-registration, and in your app use the fork instead of the original project.
That being said, you can have a non-email registration in django-registration without changing the code of the app. I've done it by creating a custom registration backend that sets the users as activated upon creation. Here you can see other ways to do the same.

Related

django extending an app to allow non authenticated votes

I have been testing a few django voting apps and found qhonuskan-votes. I have managed to install it and is works great. However, I also want it allow voting rights to non authenticated users which I am not able to do. Need help with this please.
Here is the link for its models.py, views.py and compact.py files of this app.
models
views
compact
You could write a custom view which would look like def vote(request, model, object_id, value) from the external app, but without this piece of code in it:
if not request.user.is_authenticated():
return HttpResponse(status=401)
Also make sure, that you map your custom view to the correct url instead of including app's urls:
url(r'^vote/$', view='custom_vote', name='qhonuskan_vote'))
This is not the best solution, because you are simply rewriting the code from the external app and I can't think of any proper way to override the default view in a way that would suit your needs. A better solution would be to use a different app, which allows votes by unauthenticated users (if a few lines of additional code are not a problem you can use this).

django-registration view customization

I'm using django-registration (see: https://bitbucket.org/ubernostrum/django-registration ) on one of my projects. The standard setup for the django-registration is to add a the code below in the urls.py file
(r'^accounts/', include('registration.urls'))
and also customize the templates in a folder called registration.
The code above is creating links to the registration, login and password recovery which is fine. But in my project there are some other functions I usually add to my views so if I just add the include('registration.urls') it appears that I have no way of customizing the views containing those django-registration forms.
Is there a way to call the forms used by the django-registrationin a view so I can add a few more things on those views ?
The registration form is provided by the registration backend. Check out registration.backends.default.DefaultBackend.
There's a method get_form_class(request) that returns the registration.forms.RegistrationForm class. All you have to do is create a new backend, inherit from DefaultBackend and override the get_form_class() method to return a new form class.
You can pretty much do anything by providing a custom backend, except changing the base behavior of the registration app. If you need to radically customize the views in a manner that providing a custm backend doesn't make the cut, then just create a authn or users app and import any bits from django-registration you find useful. You can, say, keep the default models and managers within the registration app namespace, but hook up a custom backend to your own internals in a new app.

Installing and using django-registration

Previously I've been using some older version of django-registration which seems to be deprecated now. Because my server does not allow me to install python plugins I need to use 'registration' as separate django application. Now my question is what do I need to modify in order to get registation running as django-app ? Can I just copy 'registration' to my django project catalog, add it in settings and it should work ? Previously there was no such thing as 'backend' defined, now backend init file with function get_backend, that takes 'path' as argument. I guess this path is sent via url right ?
url(r'^activate/(?P<activation_key>\w+)/$',
activate,
{'backend': 'registration.backends.default.DefaultBackend'},
name='registration_activate'),
Inside this catalog there's also init file with DefaultBackend class, with classes activate and register.
http://paste.pocoo.org/show/225790/
They both use signals. Do I need to bother with those signals in any way ? (I still don't quite get what they're used for).
Last thing. Previously after registration it was redirecting te either given success_url or set template in this way :
return HttpResponseRedirect(success_url or reverse('registration_complete'))
Now code responsible for this looks :
if success_url is None:
to, args, kwargs = backend.post_registration_redirect(request, new_user)
return redirect(to, *args, **kwargs)
else:
return redirect(success_url)
and the post_registration_redirect :
def post_registration_redirect(self, request, user):
"""
Return the name of the URL to redirect to after successful
user registration.
"""
return ('registration_complete', (), {})
So why was this changed in this way if it still simply redirect to 'registration_complete' ? The args and kwargs are empty so why bother ?
The situation is much simpler than you're making it out to be. Django applications (like registration) are just normal Python packages and can be imported as such. What that means is that registration can live anywhere that's in your python path already. Oftentimes the simplest place for that is in your root project directory.
The backend argument there just takes a python import path. The argument was added so that people could extend Django-Registration to use custom backends if they so desire.
If you put the registration directory on your python path the existing string should work just fine.
Quote:
"Because my server does not allow me to install python plugins I need to
use 'registration' as separate django application."
Is this because you don't have root access? Have you tried using virtualenv (Link is to my own blog) to create your own (fully writeable) Python/Django install? Alternatively, creating a writeable directory in a place you do have write access, installing django-registration there and pointing your PYTHON_PATH to that location?
IMO, it seems like you gave up too quickly on the "install django-registration" option and moved to the more complicated "run it on a different server" one.

Pinax: Customize Signup and profile

I want to gather some more information when the user signs up and also display this as part of the profile information - so that the user can edit it once he creates a login.
How can I extend the sign-up and profile form and model without changing directly pinax code?
From pinax docs
Customization
As more sites are built using Pinax,
more best practices will emerge, but
for now what we recommend is:
Always work off a stable release. The most current release is 0.7.1.
Use the pinax-admin setup_project command.
Make necessary changes to the settings.py and urls.py files in your copied directory.
Change the domain and display name of the Site in the admin interface.
Develop your custom apps under your new project or anywhere on Python path.
Develop your own templates under your new project.
This thread is very relevant to your question and discusses options for overriding the default pinax apps.
It suggests looking at https://github.com/eldarion/idios, (an extensible profile app designed to replace the profiles apps in Pinax).
This blog has some comments about overriding the default pinax apps:
Overriding build-in Pinax Applications
Assuming we want to override
$PINAX_ROOT/apps/blog with
$PROJECT_ROOT/apps/blog we can do so
simply by copying the application and
make our project-local (read
individual) changes to it. Pinax will
then load $PROJECT_ROOT/apps/blog
rather than $PINAX_ROOT/apps/blog.
Those who do not care about merging in
upstream changes nor submitting
bugfixes/features upstream would just
issue cp -a $PINAX_ROOT/apps/blog
$PROJECT_ROOT/apps and be done. Those
who consider themselves good
FLOSS-country citizens however care
about contributing back as well ...
The default pinax apps you would be looking to override (if necessary), would be:
http://pinaxproject.com/docs/dev/apps/account/
http://pinaxproject.com/docs/dev/apps/profiles/
You probably want to have a go at overriding the built-in Pinax applications, which is gone over in a little detail in this article. I imagine you'd want to extend (or override) Pinax's Profile model.
This chap seems to have been in a situation that sounds like what you want, have a quick read of his chat logs to see what I mean. Sorry that this answer isn't too specific, it's more of a pointer.

Easy-to-use django captcha or registration app with captcha?

I want to implement user registration using captcha in Django.
The workflow of django-registration app is a great, but it doesn't have captcha.
What captcha would you recommend to use with it?
Are there some other variants of registration+captcha or useful links on the topic?
This should work with Django-1.1 and don't be too hard to install.
django-registration is pretty extendable. One way to extend it is to provide a custom registration form. I'd recommend to use reCaptcha, e.g. with the widget and form field from here (archived). Then it is as simple as writing a custom form class and registration backend (which is simpler than it sounds):
from registration.backends.default import DefaultBackend
from registration.forms import RegistrationForm
class RecaptchaRegistrationForm(RegistrationForm)
recaptcha = ReCaptchaField(label="I'm a human")
class RecaptchaRegistrationBackend(DefaultBackend):
def get_form_class(self, request):
return RecaptchaRegistrationForm
The last step is to tell django-registration to use your backend. That step is described in the docs (I couldn't find a HTML version of the docs, sorry)
I've just had this problem, but the solution is dead simple.
I'm using django-registration, and I want a reCAPTCHA field for user registration. In just 1 minute:
download django-recaptcha (pip install django-recaptcha)
install it on your project. That is, copy the "captcha" folder to your project, add "captcha" to INSTALLED_APPS and add your RECAPTCHA_PUBLIC_KEY and RECAPTCHA_PRIVATE_KEY keys to settings.py too (as described in the installation instructions)
open registration/forms.py and add this field inside class RegistrationForm(forms.Form):
captcha = ReCaptchaField()
you will also have to import:
from captcha.fields import ReCaptchaField
And that's it. Less than a minute.
For those like me arriving late to the thread, there are a bunch of solutions out there now, which are pretty easy to install:
http://code.google.com/p/django-simple-captcha/
http://code.google.com/p/django-captcha/
https://github.com/inueni/django-captcha-field
https://github.com/justquick/django-math-captcha
https://github.com/marconi/django-mollom which uses the third-party Mollom service (which provides captcha and spam-filtering services).
I've successfully setup Django Mollom and Django Simple Captcha, and the hardest part was yak shaving around installing PIL on my Mac. Implementing the code was as straightforward as the docs for each would suggest.