Reusing a Django app within a single project - python

In trying to save as much time as possible in my development and make as many of my apps as reusable as possible, I have run into a bit of a roadblock. In one site I have a blog app and a news app, which are largely identical, and obviously it would be easier if I could make a single app and extend it where necessary, and then have it function as two separate apps with separate databases, etc.
To clarify, consider the following: hypothetically speaking, I would like to have a single, generic news_content app, containing all the relevant models, views, url structure and templatetags, which I could then include and extend where necessary as many times as I like into a single project.
It breaks down as follows:
news_content/
templatetags/
__init__.py
news_content.py
__init__.py
models.py (defines generic models - news_item, category, etc.)
views.py (generic views for news, archiving, etc.)
urls.py
admin.py
Is there a way to include this app multiple times in a project under various names? I feel like it should be obvious and I'm just not thinking clearly about it. Does anybody have any experience with this?
I'd appreciate any advice people can give. Thank you.

What's the actual difference between blogs and news? Perhaps that difference ought to be part of the blog/news app and you include it just once.
If you have a blog page with blog entries and a news page with news entries and the only difference is a field in the database (kind_of_item = "blog" vs. kind_of_item = "news") then perhaps have you have this.
urls.py
(r'^/(?P<kind>blog)/$', 'view.stuff'),
(r'^/(?P<kind>news)/$', 'view.stuff'),
views.py
def stuff( request, kind ):
content= news_blog.objects.filter( kind=kind )
return render_to_response( kind+"_page", { 'content': content } )
Perhaps you don't need the same app twice, but need to extend the app to handle both use cases.

In this case you could create the common piece of code as a Python module instead of a whole new application.
Then for each instance you would like to use it, create an app and import the bits from that module.

I'm not 100% sure I understand your question, so I'm going to list my understanding, and let me know if it is different from yours.
You want to have a "news" and a "blog" section of your website with identical functionality.
You want to have "news" and "blog" entries stored separately in the database so they don't end up intermingling.
If this is the case, I'd suggest making an API to your views. Something like this:
views.py:
def view_article(request, article_slug,
template_name='view_article.html',
form_class=CommentForm,
model_class=NewsArticle,
success_url=None,
):
urls.py:
(r'^news/(?P<article_slug>[-\w]+)/$', 'view_article', {}, "view_news_article"),
(r'^blog/(?P<article_slug>[-\w]+)/$', 'view_article', {'model_class': BlogArticle}, "view_blog_article"),
This makes your app highly reusable by offering the ability to override the template, form, model, and success_url straight from urls.py.

Related

Django: How structure/use project with multiple apps

I've already read the official Django tutorial and many other questions here on stackoverflow.com, but it seems like there is no real answer to my question or I just don't get it. Unfortunately, I could not find an appropriate tutorial with more than one app.
My problem:
A Django project usually consists of multiple apps. What I don't get is how those apps can work together.
Example:
Let's say we build a news website and this news website has blog posts, polls and a comments area etc. So I think it would make sense to create an app called polls, another app called blog and the app comments.
So, when you browse to url.com/news/5 for example, you'll see the blog post with the id 5. Or when you browse to url.com/polls/2 you'll see the poll with the id 2. Everything ok.
Now, however, I don't want it to be separated. What I don't get is when I want to have those parts of a website on a single webpage (like in most of the websites). That means if I browse to url.com/news/5 it should not only display the news but also the poll (because the poll belongs to this news page thematically) and at the bottom of the page the comments to that article.
How do I structure it and "glue" it together?
Normally, when I browse to url.com/news/5 the defined view function within the blog app is run and provides the HttpResponse. With this solution, however, I cannot have the poll and comments at the same page. I hope it's clear to you what my problem is.
What is "best practice" to display different apps on a single webpage? Or is it done completely different?
I am also very happy if you can give me a link to a real-world example or nice tutorial that covers this issue.
Using Class-based generic views and providing extra context. Here is a link from the documentation:
https://docs.djangoproject.com/en/1.11/topics/class-based-views/generic-display/#adding-extra-context
and here is the example code:
from django.views.generic import DetailView
from books.models import Publisher, Book
class PublisherDetail(DetailView):
model = Publisher
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(PublisherDetail, self).get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['book_list'] = Book.objects.all()
return context
As you can see the main model is Publisher and with get_context_data you can add another context: context['book_list'] = Book.objects.all() that retrieves also all books from the database. You can combine multiple models with this.

Sort Columns in Django Templates

I know I should put up some code with what I've tried but I don't know where to start.
In Django admin I can display data so that it can be sorted by the user using:
class MyModelAdmin(admin.ModelAdmin):
list_display = ['field1', 'field2']
ordering = ['field2','field1']
Within the admin site, users will be able to click the top of the column and reorder on that column.
I want to replicate this functionality in an non-admin screen. How do I do that?
You have two approaches available:
Import and modify the admin templates to use their sortable functionality. This answer covers the basics very well., but the ModelAdmin class has a lot of functionality, which you may or may not actually need. You can start from the admin templates more generally if you want to go down that route.
Use an external library to manage in the templates.
I find the latter approach is actually easier, faster and more easily extensible. I have just implemented this in a project using datatables, which takes a couple of minutes, assuming you already have a table.

Django Class Based Views - is it bad style to put all code in urls.py?

Just working through some CBV work, and was wondering if this is bad style. Normally you have a class in your views.py and a URL in urls.py for that view. Something like:
views.py
from django.views.generic.list import ListView
from project.models import Contact
class ContactList(ListView):
model = Contact
urls.py
from django.views.generic.list import ListView
from project.views import ContactList
urlpatterns = [
url(r'contacts/$', ContactList.as_view()),
]
and then a template to show the data.
But, what about just skipping the view code entirely and doing it all like this within the urls.py file:
from django.views.generic.list import ListView
from project.models import Contact
urlpatterns = [
url(r'contacts/$', ListView.as_view(model=Contact)),
]
Is that bad style to group it all into the urls.py file? I mean, it gets rid of excess code inside views.py so isn't that good? Or is this a reduction at the expense of clarity?
It is much more better to keep view logic out of URLConfs.
At a glance url(r'contacts/$', ListView.as_view(model=Contact)) might seem okay, but actually it violates the Django design philosophies:
Loose coupling between urls, views, models has been replaced with tight one, so now you can't reuse your view.
Flexibility of URLs is destroyed. Inheritance, the main advantage of CBV is impossible using them in URLs.
Many other things, for example what if you want to add authentication? Authorization? You will need to wrap all these in decorators and your URLs will quickly become messy.
So:
Views modules should contain view logic.
URL modules should contain URL logic.
The answer is: it depends.
If you're writing a really small app that, you know, won't get bigger, then it doesn't matter, unless you can't resist code smells, you can actually write your whole app in just one file, check answers to this SO question for example How do I write a single-file Django application?
P.S: This problem is universal and is in no way Django specific.
Well, "reducing excess code in views.py" is certainly not a reason. If you're going to instanciate generic views with a couple of simple arguments, you can keep it in urls.py, as long as it works for you. When it doesn't work anymore, maybe move it to views.py or make views a module and move it to views/someview.py, it doesn't matter.

How to bind multiple reusable Django apps together?

I try my best to write reusable Django apps. Now I'm puzzled how to put them all together to get the final project.
Here is an example of what I mean:
I have a picture app that stores, resizes and displays images. Also I have a weblog app that stores, edits and displays texts. Now I want to combine these two to show blog posts with images.
To do that I could put foreign key fields in the blog to point at pictures. But then the blog could not be used without the picture app. Also I could create a third app, which is responsible to connect both.
What is the 'best practice' way of doing it ?
EDIT: Thank you for your very good answers, but I'm still looking for more practical example of how to solve this problem. To complete my example: Sometimes it would be nice to use the blog app without the picture app. But if I hard code the dependency it is no longer possible. So how about 3rd app to combine both ?
Introduction talk in the bottom of the answer (more straight to the answer). I will assume that you have one app for text handling called Text and one app for picture handling called Pictures and a third app for blogging called Blog.
Big picture
You will need to study the manual about the template language for python programmers. The idea is that each thing is in its own app and that you have a third app that connects everything. The apps should then supply its models and views as you like them (just remember to keep you focus on what the app should do) and also supply a set of templatetags.
How to make inclusion tags
Make inclusion tags and it is really easy! It will remind you of writing normal views.
Create a directory templatetags in you app folder. Also create a __init__.py file in this templatetags (so the directory becomes a python package).
Then create a python file. The name is important, you will use this in {% load xyz %} in the templates that will use your app. For instance if call the file picturestags.py, you will call
{% load picturestags %} in all templates that will use it.
First in the file add some politics you need not to think much about, just include this before anything else:
from django.template import Library
register = Library()
Then add the tags by defining functions with the same name as your tag. I will call it display_picture in the example and it will take one argument url. The function should create a dictionary that you will use in a template. My example will just display the picture the url is pointing to.
#register.inclusion_tag('pictures/display_picture.html')
def display_picture(url):
return {'picture': url}
Create the path templates/pictures in your app and create the file display_picture.html inside containing:
<img src="{{ picture }}" />
As you probably understand, the #register makes this a tag, what is inside the dictionary display_picture returns are what you can use in display_picture.html. Very much like your normal view functions.
In the end you will end up with these files:
pictures/
__init__.py
models.py
views.py
tests.py
templates/
pictures/
display_picture.html
templatetags/
picturetags.py
That is all you need to add to your Picture app. To use this in your Blog app, you need to add Pictures to your INSTALLED_APPS. Then in the templates, where you need to use your own newly home baked tag first load it: {% load picturestags %} then just add the tag {% display_picture https://www.google.com/intl/sv_ALL/images/logos/images_logo_lg.gif %} like this:
{% load picturestags %}
<html>
<body>
{% display_picture https://www.google.com/intl/sv_ALL/images/logos/images_logo_lg.gif %}
</body>
</html>
Results
This is just a small example but you can see that it is very easy to expand this. Your blog could connect the Text and Pictures app by importing their models and foreign key them. There is you connection Text and Pictures for a certain blog post. Your blog_post.html-template could look like (simplified):
{% load picturestags %}
{% load texttags %}
<html>
<body>
<h1>{{ subject }}</h1>
<div class="article">{% article_to_html articleid %}</div>
<div class="article_picture">{% display_picture %}</div>
</body>
</html>
Notice that only the Blog has dependencies and it is dependencies it should have (no blog without text and pictures...but pictures can live without text). The look and placement should be and can be controlled by CSS and DIV/SPAN-tags. In this way you can take your Picture app and give it to someone who has no idea about Text app and use it, displaying pictures in different ways probably without ever touching your code!
Inclusion tags is the only thing I know of since I just learned this yesterday. I think it is a convenience provided by Django to make life simple. On the documentation page there are a whole lot more (including how to make "real" tags the hard way without "shortcuts"). So if you find this method to limited, read the documentation...it has lots of examples. It also discusses how to make filters, simple_tags, thread considerations and other advanced stuff.
Introduction
I had this exactly this problem as you and I also wanted something different than the answers I read (I don't say the answers was bad, they helped me learn a lot and gave me insights, but I wanted this I am writing now). I managed to figure something out that is not very obvious, thanks to your question and definitely thanks to Stack Overflow so this is my contribution back even to a half year old question that is probably abandoned (might help a googler or two)!
I also got a lot of inspiration from Google Tech Talk Reusable Apps. In the end (43 minutes) he mentions some good examples like django-tagging which is what he says a model for how to write reusable apps. That gave me the idea for all this, because that is the way django-tagging solves this very problem we had/have.
Now after I written all this (took an hour), I feel for the first time that I might contribute instead of just google and follow what others are doing or complaining that others are not writing how I need to do things. For the first time I am taking my responsibility of writing my view so others can google this (just had to write this paragraph :-) because it feels really great, even if it might be shredded to pieces or ignored and forgotten).
Think of it in the same way that you would use any 3rd-party app in your project. "Re-usable" doesn't mean "without dependencies". On the contrary, you'd be hard-pressed to find an app that doesn't have at least one dependency, even if it's just dependent on Django or core Python libraries. (While core Python libraries are usually thought of as "safe" dependencies, i.e. everyone will have it, things do sometimes change between versions of Python, so you're still locking your app into a specific point in time).
The goal of re-usuable is the same as that of DRY: you don't want to write the same code over and over again. As a result, it makes sense to break out functionality like a picture app, because you can then use it over and over again in other apps and projects, but your picture app will have dependencies and other packages will depend on it, as long as there are no circular dependencies, you're good (a circular dependency would mean that you haven't actually separated the functionality).
This is a good question, and something I find quite difficult to manage also. But - do you imagine these applications being released publicly, or are you only using them yourself? If you're not releasing, I wouldn't worry too much about it.
The other thing is, dependencies are fine to have. The pictures app in your example sounds like a good candidate to be a 'reusable' app. It's simple, does one thing, and can be used by other apps.
A blog app on the other hand usually needs to consume other apps like a picture app or a tagging app. I find this dependency fine to have. You could try to abstract it a little, by simply linking to a media resource that was put there by your picture app.
It's all just a little bit of common sense. Can you make your apps slim? If yes, then try to create them so they can be reused. But don't be afraid to take dependencies when they make sense. Also, try to allow extension points so you can potentially swap out dependencies for other ones. A direct foreign key isn't going to help here, but perhaps something like signals or Restful APIs can.
I am a Django newbie and I faced the same problem. It is shameful how there's so much buzz about reusable apps in the Django community, but not a single authoritative reference on how to connect them
in a project without hard coded dependencies.
I have been working on a new Django project and I wanted to set up my models to avoid hard coding as much as possible. This is the pattern that I used.
Layout
project_root/
core/
models/
mixinmodels1.py
mixinmodels2.py
...
utils.py
...
app1/
models/
__init__.py
base.py
basemixins.py
mixins.py
concrete.py
/signals
__init__.py
handlers.py
utils.py
...
app2/
...
...
App models
base.py : This module implements only the 'reason for existence' of that app in abstract classes.
Rules are:
This module usually only imports from the core app. It usually does not import anything from other apps in the same project.
An exception to the above rule is when the 'reason for existence' assumes the existence of another app. For example, a group app assumes that there is an user app somewhere. In this case, the way to link them is:
# project_root/settings.py
AUTH_USER_MODEL = 'app_label.UserModel'
# project_root/groups/models/base.py
from django.conf import settings
and then using settings.AUTH_USER_MODEL to refer to the user model
Use this pattern for all apps, not just the user app. For example, you should also do
# project_root/settings.py
GROUP_MODEL = 'app_label.GroupModel'
If using the above pattern, only assume the functionality provided by base.py of the other app
to which you are linking. Do not assume the functionality of elaborate concrete classes (I will discuss where to put concrete classes shortly)
Of course, importing from django, third party apps and python packages is allowed.
Make sure that the assumptions that you make in base.py of any app is rock solid and would not
change much in the future. A good example is django-registration by James Bennett. Its an old app, but its appeal did not wane because it made rock solid assumptions. Since good reusable apps do one thing well, it is not difficult to find that set of assumptions.
basemixins.py: This module should implements plugs to the concrete models of that app. A 'plug' to a model M is any model that contains a foreign key to the model M. For example:
# project_root/groups/models/basemixins.py
from django.conf import settings
from django.db import models
class BaseOwnedByGroup(models.Model):
"""
This is a plug to the group model. Use this
to implement ownership like relations with
the group model
"""
owner = models.ForeignKey(settings.GROUP_MODEL,
related_name = '%(app_label)s_%(class)s_owner',
verbose_name = 'owner')
# functionality and manager definitions go here.
class Meta:
abstract = True
app_label = 'groups'
BaseOwnedByGroup is a 'plug' to the group model. The rules here are the same as 'base.py`
While defining 'plugs' in basemixins.py, only assume functionality provided by base.py.
Import only from core, django, third party apps and python packages.
mixins.py : This module should be used for two purposes
To define elaborate 'plugs', which assumes the functionality of the elaborate concrete classes but not the relationships with other apps. The elaborate plugs should ideally inherit one of the 'base plugs' defined in basemixins.py.
To define mixin models (that are not 'plugs') which can be used by the concrete classes of that app.
concrete.py : This module should be used to define (you guessed it) concrete classes of that apps and to set up relationships with other apps. In short, this module assumes your project and all the
functionality you want to provide in it.
Relationships to other apps should be set up as follows:
To establish a one to one or many to one relationship with model M of app another_app, do the following:
# project_root/another_app/utils.py
def plug_to_M_factory(version_label):
"""
This is a factory method which returns
the plug to model M specified by
version_label
"""
if version_label == 'first_version':
from another_app.models.basemixins import BasePlugToM
return BasePlugToM
if version_label == 'second_version':
from another_app.models.mixins import PlugToM
return PlugToM
...
# project_root/groups/models/concrete.py
from groups.models.base import BaseGroup
from another_app.utils import plug_to_M_factory
PlugToMClass = plug_to_M_factory(version_label = 'second_version')
class ConcreteGroup(BaseGroup, PlugToMClass):
# define your concrete model
class Meta:
app_label = 'groups'
To establish a many to many relationship, the recommended way is to use a through model. Inherit the correct plug in the through model in the exact same way (as we did in the ConcreteGroup model)
signals : While setting up relationships, often we have to perform operations on a model M of app app1, when model N of app app2 changes. You can use signals to handle that. Your handlers can assume the functionality of the concrete sender, but often they don't need to. Assumption of the base version of the sender in base.py is enough. This is why it is a good idea to always use settings.ModelName to refer to a concrete model. You can extract out the model class from the settings.ModelName string by either using ContentType or using a project wide get_model_for_settings function as follows:
# project_root/project/utils.py
from django.db.models import get_model
from django.core.exceptions import ImproperlyConfigured
def get_model_from_settings(model_string):
"""
Takes a string of the form 'app_label.model' as input, returns the
appropriate model class if it can find it.
"""
try:
app_label, model_name = model_string.split('.')
except ValueError:
raise ImproperlyConfigured("function argument must be of the "
"form 'app_label.model_name', got '%s'" % model_string)
model = get_model(app_label, model_name)
if model is None:
raise ImproperlyConfigured("function argument refers to model "
"'%s' that has not been installed" % model_string)
return model
core : The core app is a special app which stores project wide mixin functions.
These mixins should not assume anything about any other app. Only exception to this rule is mixins that rely on base functionality of settings.AUTH_USER_MODEL. This is because you can safely assume that most projects will have an user model.
Of course imports from django, third party and python packages are still allowed
Remember that all base.py and basemixins.py modules are allowed to import from core.
Finally for everything to work as intended, import your models in models/__init__.py of every app.
The advantages that I find from following this scheme is:
The models are reusable. Anyone can use the abstract base models and mixins to design their own concrete model. base.py, basemixins.py and related factory methods can be bundled together with a bare bones concrete model and shipped in a reusable app.
The apps are extendable. All mixins are versioned and there is a clear inheritance scheme.
The apps are loosely coupled. External mixins are accessed via factory methods and external models are referred to using django.conf.settings.
The apps are self contained. Any changes in an app will most likely break that app and that app only. Other apps will most likely remain unscathed. Even if external apps break, the place where this
could happen is clearly marked.
I have been using this scheme to reduce coupling between my apps. I am not an experienced Django programmer, and I have a lot to learn, so any feedback is appreciated.

Shifting thinking from CakePHP to Django - a monolithic views file?

I'm trying to get started with Django, and have previously worked with CakePHP, and so my MVC background comes out of that. I'm aware of Django's slightly different MTV architecture, and am fine with the monolithic model files - multiple classes in one file I can handle just fine.
But I'm confused about how to do the views (which are roughly analagous to controllers in MVC, correct?). The examples I've seen just have one views.py that has methods like index(), view(), etc. But if I have a bunch of users that create and own widgets that they can share, for example, I want to have /users/view that runs view() for the users model, and /widgets/view that runs view() for the widgets model.
I don't see any way to separate those out, and don't know what the correct/conventional/right way is to do so. I may just be having trouble wrapping my head around Django's way of doing things, too. Should I have methods in view.py that are user_view and widget_view? That seems very clunky.
Or should I have user_view.py or even user/view.py that contains index() and view()? Could I reference those from the URL routing? How are things generally done with Django and this kind of thing?
This may ultimately be related to (or even solved by) this answer, but I'm asking more as a question of what convention and the right way to think about such things is.
Additionally, shouldn't the docs/examples be clearer on this? I've been impressed by the docs thus far, but I'm pretty sure most web apps will deal with more than one "object," and it seems to me that this would come up pretty often.
Python view files are just Python modules. The views themselves are just functions that can live anywhere you like - the module doesn't even have to be called views.py. The urlconf (in urls.py) can refer to views anywhere at all.
One obvious way of separating things out is into separate applications, which is covered well in the documentation - you can also have separate urls.py files for each app and use include in the main site-level urls.py to include all the sub-files.
But there's nothing to stop you sub-dividing the views in a single app into multiple files - eg by creating a views module, containing a (blank) __init__.py and as many other view files as you like.
Or, if you really do have views associated only with a particular model - and you'd be surprised how seldom that is the case - again, you could make your views classmethods on the model class itself. All a view has to do is to accept a request, and any other parameters, and return a response.

Categories

Resources