I have some functions like:
has_delete_permission,
has_add_permission,
get_actions,
formfield_for_foreignkey
get_queryset
Etc are the built-in ModelAdmin functions which I am using in almost all the ModelsAdmin's in my project.
How to create a common/reusable class which include these functions and reuse in the other ModelAdmin classes?
How to pass the reference of the Model or the ModelAdmin class to the common class?
What should be the file structure to be maintained, in case this has to be used for many apps in a project.
Some direction will be great help.
Thanks.
I'd recommend using Python's class's multiple inheritance to achieve this. It would look something like this:
from django.contrib import admin
from .models import Banana
class MyAdminMixin:
def has_delete_permission(self, obj):
# Your code goes here
def has_add_permission(self, obj):
# Your code goes here
class BananaModelAdmin(MyAdminMixin, admin.ModelAdmin):
# Now your admin has access to the methods in MyAdminMixin
model = Banana
For some more information on using mixins with class-based views, take a look at the Django docs on the subject. Hope this helps!
Related
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.
My colleague and I are discussing whether it is correct to have model methods which are not directly related to the model data. For example, methods that generate links for the admin pages.
Should these methods be in the model or it can be a separate function which accepts app_name as an argument?
class Resource(models.Model):
...
#classmethod
def __admin_list_url(cls):
return reverse(f'admin:{cls._meta.db_table}_changelist')
#classmethod
def get_admin_list_url(cls, caption='', query_string=''):
if not caption:
return '-'
return mark_safe(f'{caption}')
It is not inherently incorrect, but I'd say it should go in your admin.py, either as a separate function or custom admin class/mixin.
Also a heads up that you probably want to use f'admin:{cls._meta.model_name}_changelist'.
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 }}
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.
So the background detail, Post is a model, and I am basically trying to create a blog, the same blog as the one shown in this video.
Here is the code:
from django.views.generic import ListView, DetailView
from models import Post
class PublishedPostsMixin(object):
def get_queryset(self):
queryset = super(PublishedPostsMixin, self).get_queryset()
return queryset.filter(published=True)
class PostListView(PublishedPostsMixin, ListView):
# PostListView takes default template name as `post_list.html`,
# as list was the name it was assigned.
model = Post
template_name = 'blog/post_list.html'
class PostDetailView(PublishedPostsMixin, DetailView):
model = Post
template_name = 'blog/post_detail.html'
So, if you can see, PublishedPostsMixin is inheriting from object, so how is it that the super() is working. If you can understand what is going on, could you please explain step by step, I'm a little confused.
The trick is in what super does. It's a dynamic call: it refers to the next class up in the MRO (method resolution order). Because (as Adrián says in the comments) the mixin is only supposed to be used in conjunction with other classes, there will always be something in between PublishedPostsMixin and object in the MRO.
For more details on super, you should read Raymond Hettinger's article Super considered super (note that it's written with Python 3 syntax in mind, but the principles are the same).