django: modifying/extending 3rd party apps

前端 未结 3 470
被撕碎了的回忆
被撕碎了的回忆 2020-12-11 01:44

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 s

3条回答
  •  既然无缘
    2020-12-11 02:39

    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!

提交回复
热议问题