Using Django Views and Forms without a Models based Database - python

I am kind of new to Django (been writing Python for a while now) and I was wondering if it is at all possible to use the Views and Forms framework in Django without having the need for a database or the use of Models.
The content is dynamic, and gets populated into a dictionary each time the user launches the website. So I would like to leverage the Django Views and Forms but passing through the details from the dictionary and not from a Model Class (Database)
I hope I have explained myself correctly.
So to add onto this then.
If you had the following for a Models based class:
class TestClass(models.Models):
var1 = models.CharField(....)
class DetailView(generic.DetailedView):
model = TestClass
How could I use the DetailView class (Or any other django based View framework with a class based dictionary like this:
class TestObj(object):
def __init__(self):
self.var1 = []
testdict = defaultdict(TestObj)
testdict['test'].var1 = ['blah']
Do I just use the dictionary in the model field under the DetailView class ?
please excuse me if I have anything typed incorrectly.
Thanks

It is totally possible.
However, if you decide not to have a database you will lose a chance to use many contrib features (like accounts, backend). From the "empty" project (made with django-admin startproject) you will need to remove most of INSTALLED_APPS, MIDDLEWARE, context_processors in TEMPLATE, set DATABASES to an empty dict() (see the comment from #spectras), maybe some other settings tinkering on top.
Upd: (Since you modified your question significantly, here are more details)
Using django.db.models doesn't make much sense without a database (pay attention on db in the path to models package). Some generic views (like DetailView) are made to spare your time when working with models, so using them will not make much sense neither.
If you don't need to save any of TestClass instances and their lifetime is limited to generating a response to a single user request, you should be fine without using django models at all. Using TemplateView will be sufficient.
class TestClass(object):
def __init__(foo, bar):
self.foo, self.bar = foo, bar
class MyView(TemplateView):
template_name = 'my_template.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['my_object'] = TestClass(foo="hello", bar="world")
return context
In my_template.html:
{{ my_object.foo }} {{ my_object.bar }}

Related

Python, bad practice to have same name on classes

I have multiple files like this in a django app.
django-app
----views
-------app_one.py
-------app_two.py
-------app_three.py
Inside app_one.py i have code similar to this
class AppOne:
... some methods ...
class Data(AppOne, APIView):
def post(request):
class History(AppOne, APIView):
def get(request):
In app_two.py I would like to name my classes like this (Note the sub_classes have the same names as in app_one):
class AppTwo:
... some methods ...
class Data(AppTwo, APIView):
def post(request):
class History(AppTwo, APIView):
def get(request):
So, my question is this: This works fine, I can run the server etc. But is this a bad practice? Could I run into unexpected results because of this?
The reason I want these specific names is because I use them inside Django admin for a permissions thing.
Views don't matter in the admin at all, so that's beside the point.
No, you shouldn't bump into any trouble; after all Django doesn't really care about your view classes' naming, it just cares about how they're hooked up in your urls (or if you're using DRF, based on APIView, your API router).
There's also nothing stopping you from inheriting things cross-app (after all, apps are just Python packages that are registered with Django) if that leads to less code and/or makes sense for you.

How to use base classes in Django

I'm trying to alter an app I've created so that it is reusable. It's based around a single model which sites using the app will subclass. As it stands, my non-reusable version has the following kind of structure:
# models.py
class Document(models.Model):
contents = models.TextField()
date = models.DateTimeField()
# views.py
from .models import SiteModel
# ...
class MyView(ListView):
def some_method(self, list_of_pks):
model_vals = Document.objects.filter(pk__in = list_of_pks).values()
def perform_action(request):
obj_pk = request.POST.get('obj_pk')
obj = Document.objects.filter(pk = obj_pk)
MySignal.send(sender=Document, instance = obj)
#etc, etc
This works well enough. But my use case calls for different types of Document, one per site, that will have additional fields that aren't known in advance. Based on reading the documentation on abstract base classes, I thought the a reasonable solution would look like:
# models.py for the app
class BaseDocument(models.Model):
contents = models.TextField()
class Meta:
abstract = True
# models.py for a hypothetical site using the app
class SiteDocument(myapp.BaseDocument):
date = models.DateTimeField()
# other site-specific fields
What I don't understand is how to then reference the model in the app's views.py, forms.py, etc. I know BaseDocument.objects.all(), for example, won't return anything since it isn't connected to a database. Conversely, I can't have Document.objects.all() because Document hasn't been created yet and is specific to each site. Is an abstract base class not the correct solution, and if so, what is?
Edit:
It looks like using a OneToOneField may be best suited to my use case, although it looks like that precludes inheriting methods from the superclass and that BaseDocument.objects.all() won't list out all its children.
Alternatively, I was wondering if I could just add a get_document_model() method to my abstract base class, in the style of get_user_model()?
You can't query your abstract classes directly like that since they won't have managers, only the inherited classes. If you really must do inheritance, you can use a concrete base model and inherit from that at the cost of a join on every query.
Think long and hard about whether this is truly necessary, or if you can represent your data in a more generic way. Models make inheritance seem easy, but they're not magic. There are very real performance and complexity considerations.
It might be as easy as adding a type field to your model
class Document(models.Model):
DOCUMENT_TYPES = ['site', 'another', 'whatever']
document_type = models.CharField(choices=DOCUMENT_TYPES)
...
For more information about abstract vs concrete classes and querying, visit How to query abstract-class-based objects in Django?
I ended up going with a solution mentioned in my edit, namely creating a get_document_model() method inspired by get_user_model(). This gives me exactly the desired behavior.
# models.py in app1
from django.db import models
from django.apps import apps as django_apps
class BaseDocument(models.Model):
contents = models.TextField()
class Meta:
abstract = True
def get_document_model():
# exception handling removed for concision's sake
return django_apps.get_model(settings.DOCUMENT_MODEL)
# models.py in app2
from django.db import models
from app1.models import BaseDocument
class SiteDocument(BaseDocument):
date = models.DateTimeField()
Throughout views.py and elsewhere, I changed things that would have been of the form Document.objects.all() to BaseDocument().get_document_model().objects.all().

create custom methods in django class base views

I want to use generic class base views using django 1.9
What i am trying to understand that
from django.views.generic import CreateView
from braces.views import LoginRequiredMixin
from .models import Invoice
class InvoiceCreateView(LoginRequiredMixin,CreateView):
model = Invoice
def generate_invoice(self):
...
return invoice
now i want to bind this custom method to url. How can i achive this?
I know using function base view its simple but i want to do this using class base views.
Help will be appreciated.
Yes, this is the main issue to grasp in CBV: when things run, what is the order of execution (see http://lukeplant.me.uk/blog/posts/djangos-cbvs-were-a-mistake/).
In a nutshell, every class based view has an order of running things, each with it's own method.
CBV have a dedicated method for each step of execution.
You would call your custom method from the method that runs the step where you want to call your custom method from. If you, say, want to run your method after the view found that the form is valid, you do something like this:
Class InvoiceCreateView(LoginRequiredMixin,CreateView):
model = Invoice
def generate_invoice(self):
... do something with self.object
return invoice
def form_valid(self,form):
self.object = form.save()
self.generate_invoice()
return super(InvoiceCreateView,self).form_valid(form)
So you have to decide where your custom method should run, and define your own method on top of the view generic method for this step.
How do you know what generic method is used for each step of executing the view? That the method the view calls when it gets the initial data for the form is def get_initial? From the django docs, and https://ccbv.co.uk/.
It looks complex, but you actually have to write very few methods, just where you need to add your own behaviour.

Should I be using controllers.py or #staticmethod in Django?

The person on our team who initially taught us django (and has subsequently left) utilized a controllers.py file for helper functions. A lot of these functions are directly related to classes. I prefer to use #staticmethod to house these helpers with the classes they're related to. For example, rather than doing this:
# controllers.py
def process_entry():
# do some exciting stuff that might not have to do with an instance
Called like this:
from myapp.controllers import process_entry
process_entry()
I'd prefer this:
# models.py
class Entry(models.Model):
name = CharField...
# some other fields
#staticmethod
def process_entry():
# do some exciting stuff that might not have to do with an instance
Called like so:
from myapp.models import Entry
Entry.process_entry()
Is there a preferred, standard way to deal with situations like this or is it just personal preference? Does anyone else utilize a controllers.py file? What goes in there?
Thanks.
EDIT:
Possibly a better example, commissions.
# models.py
class Commission(models.Model):
check = ForeignKey
payment = ForeignKey
# other fields
class Check(models.Model):
# fields
class Payment(models.Model):
# fields
Any time a Check or Payment instance is modified an adjustment as to be made to any related Commission instances or any time someone wants to manually run commissions, they can do so. So where should run_commissions() go? I prefer this, but apparently this shouldn't be encapsulated in a data-related model?
# models.py
class Commission(models.Model):
check = ForeignKey
payment = ForeignKey
# other fields
#staticmethod
def run_commissions():
# do stuff
Static methods are used for grouping related functions in one class (mostly for factory methods), beside that, there is no difference between static method and function.
BUT. In your example you are assigning behavior to DATABASE model. DATABASE models are not LOGIC models, and you should separate them from your app logic. Anyway, controllers is also a bad name in that matter.
I'm not sure what process_entry does, but if it's only changing one Entry entity, then it can be named: Entry.process(), but NOT Entry as DB model! just another Entry class. However if that function does more than just changing Entry, then it shouldn't be assigned to Entry entity, but made as a service function.

extra_context function for simple generic view in django

I have my page where I have my posts list, and I also want to have sidebar with suggestions. I used generic ListView for my posts, and needed to pass suggestions somehow so I used extra_context which should(?) work like that according to few examples I've read, but in template there is no 'suggestions' object.
class PostList(generic.ListView):
model = models.Post
paginate_by = 10
context_object_name = 'mj'
def get_queryset(self):
return models.Post.objects.filter(user = self.request.user)
def extra_context(self):
return {'suggestions':models.Pla.objects}
I don't have experience in django so maybe there is better way to pass suggestions for sidebar. Maybe it's possible to do this with wrapping view function since I want to have suggestions..
Class-based views don't use extra_context the way the older function-based generic views did. Instead, the usual way to do this is with a custom get_context_data call as shown in the docs:
https://docs.djangoproject.com/en/dev/topics/class-based-views/generic-display/#adding-extra-context
The example in the docs is almost exactly what you're trying to do. You may want to follow its example further and pass in a queryset (models.Pla.objects.all()) rather than the manager object (models.Pla.objects).

Categories