I would like to allow a User to have an admin interface to their own Video objects. I was planning on writing some views that allowed things like setting attributes like "published" or deleting objects.
I've started looking into using django's Admin site - but that seems like it might be overly complicated for what I want (just deleting/ setting the published attribute).
Is one approach better than the other? Writing something from scratch or using the Admin site?
If I were to write something from scratch - what is the correct way to achieve ModelAdmin style actions (ie. delete_selected(queryset, request))
This is exactly what the admin should be used for! How could it be too complicated? Even writing a handful of lines of HTML would take longer.
If you built this yourself, no matter how simple, you'll have to define views that list objects, validate input, check permissions, write HTML, implement some kind of multiple action system that maps to python code, ....
Assuming you don't want to do that:
You're going to want to look into making multiple admin sites and filtering admin results to only those that belong to the user via overriding the queryset method on a ModelAdmin
# pasted from docs
class MyModelAdmin(admin.ModelAdmin):
def queryset(self, request):
qs = super(MyModelAdmin, self).queryset(request)
if request.user.is_superuser:
return qs
return qs.filter(author=request.user)
Related
Can Django be used to create a website for creating custom websites depending on the user needs? There will be more than one template and each user will have a custom url for their websites.
I don't know if this can this be achieved with Django CMS.
Sure, it is possible but it requires ton of work, because you need to write bunch of templates, or/and logic that handles templates.
You could write TemplateMixin, that depending on passed domain, or kwarg in url changes the template in the View. So, for example, it could look like that:
class TemplateMixin:
template_name = None
request = None
model = None
def get_template_names(self):
"""
Return a list of template names to be used for the request.
Must return a list. May not be called if render_to_response() is overridden.
"""
db_settings = Settings.objects.get_or_create()[0]
if self.template_name is None:
raise ImproperlyConfigured(
'TemplateResponseMixin requires either a definition of '
'\"template_name\" or an implementation of \"get_template_names()\"')
template = db_settings.website_template
ready_template = '/'.join([template, self.template_name])
return [ready_template]
There are also solutions for handling multiple domains, so you could detect what current domain is via self.request in get_template_names method. The templates are handled by prefix. The kwargs also should be in self.kwargs, so you can detect which site you need to present via custom namespace url.
You can also create WebsiteSettings model that handles various templates, and is manageable via simple custom dashboard panel, and belongs to user, or user groups. The fields that it should have is 'template' with choices attribute, relation to User (or CustomUser model), and bunch of settings you want to give a user (or you could have different model('s) for that).
The solution I bring here is simple to show the idea - but it can be insufficient, to accomplish what you really want you must write the whole mixins, views etc. logic yourself.
I have a project with around 60 models so creating a unique Detail, Create, Update, Delete APIView for each would be a lot of wasted resources (or so it feels like). Would it be better performance-wise (or safe?) to simply create a generic view that could cycle between each model like so?
_CLASSES = <Dictionary of my classes>
class GenericModelView(APIView):
def get(self, request, model_name): # model_name would be a required part of the URL.
model_class = _CLASSES[model_name]
serializer_class = model_class.serializer_class # I would instantiate a serializer for each model_class
return Response(serializer_class(model_class.objects.all()).data)
I think, there should not be any concerns safety wise. However, in my experience, this approach will not last long. You will have to customize the functionality for different model according to the requirements. At that stage, you will need to create separate views. Also, it may become complicated to read and understand logs as always same function is being called. So my final recommendation would be to use different views. It should not take you more than an hour. Just copy and paste. Customize later according to your needs.
I am creating an app with a rest API that should return values for instances of objects based on the url given. Right now I have the API working using ModelViewSets of my objects for the API.
For example I have three objects, user, transactions, and goals.
As it stands I can go to /mysite/api/users and return a list of all users
I can also go to /mysite/api/users/1 to return just the user with the id '1'.
I can do something similar with transactions and goals.
What I'm looking to do is go to url /mysite/api/users/1/transaction/1/goal
to find the goal associated with the transaction for that user.
I've been scouring tutorials and am not sure what the right question is to ask in order to find something useful to learn how to do this. What is the correct way to go about setting up my rest api like this?
If I understand correctly, you want to create nested ressources.
If you are using Viewsets, then the ExtendedRouter class of the drf-extensions package will allow you to achieve this.
Drf-extensions documentation about this feature: https://chibisov.github.io/drf-extensions/docs/#nested-routes
There is also this module, who also offer the same features.
You can either use url params or query params to solve your issue. I will explain the URL params solution here,
serializers.py
#Write a Goal Serializer
urls.py
#change the URL according to your environment
url(r'^users/(?P<uid>[0-9]+)/transaction/(?P<tid>[0-9]+)/goal/$', GoalViewSet.as_view({'get': 'user_transaction_goal',}), name='user-transaction-goal'),
views.py
class GoalViewSet(viewsets.ModelViewSet):
permission_classes = [IsAuthenticated]
queryset = Goal.objects.all()
def user_transaction_goal(self, request, uid, tid):
#assuming user is FK in transaction and transaction is a FK in goal
#modify the filter rule according to your model design
goals = Goal.objects.filter(transaction=tid, transaction__user=uid)
serializer = GoalSerializer(goals, many=False)
return Response(serializer.data)
As #clement mentioned you can also use plugins to handle this situation.
I have a problems thats been bugging me for a while. I want to use dates in django admin to view entries between certain dates.
To do this I have customized my changelist.html for this model and put a form in there. When posted I override the queryset method like this
def queryset(self, request):
qs = super(ModelAdmin, self).queryset(request)
if request.POST.has_key('date1'):
return qs.filter(startdate__gte=request.POST['date1']).filter(startdate__lte=request.POST['date2'])
return qs
This works great but its only one little problem. The parameters are forgotten if I for example choose to sort the result in any way.
If I instead of this type in the url straight into the browser so it looks like this
http//localhost/admin/some/model/?startdate__gte=2010-01-01&startdate__lte=2010-12-30
I can sort however I want to afterwards because they´ll stick just like this
http//localhost/admin/some/model/?o=5&ot=asc&startdate__lte=2010-12-30&startdate__gte=2010-01-01
Do I need to use a filterspec to solve this?
Thanks heaps!
There is a change request over at the Django project asking for this functionality.
It's waiting for someone to write tests for the proposed patch before it's committed, so you could either do that or you could download the proposed patch (near the bottom of the page) and use it.
https://code.djangoproject.com/ticket/6903
I actually want to accomplish the same thing a user in
Remembering checked checkboxes across pages - what's the best way?
asked. But not for php, I want it for django. Since django is just great :-)
I`m using pagination and want to remember the checked checkbox while the user is navigating over the pages provided by pagination.
Now I'm searching for a best practice how I could accomplish this. I do not really have a good idea how i could accomplish this. My idea would include javascript, but I'm sure there is somewhere out there a solution without js.
I can't think of any way to do this with a paginator. But this is a good spot for a formwizard and dynamic forms. The general idea is to create a dynamic form for each "page" and then a formwizard to hold them all together. This allows for saving the checkboxes across multiple pages and lets you go backwards and forwards easily. The best thing is that it takes virtually no code!
Something like this should be able to deal with everything:
from django.contrib.formtools.wizard import FormWizard
from django import forms
from django.forms.extras.widgets import CheckboxSelectMultiple
from django.core.paginator import Paginator
# In your forms.py --------------
def MPageFormMaker(paginator):
"""
Create a "paginated" group of forms based on a queryset and num-per-page item.
"""
def Sform(this_q):
"""
Create this page's items
"""
class _PageForm(forms.Form):
items = forms.ModelMultipleChoiceField(queryset = this_q,
widget = forms.CheckboxSelectMultiple)
return _PageForm
for i in range(paginator.num_pages):
yield Sform(paginator.page(i).object_list)
class MpageForm(FormWizard):
def done(self, request, formlist):
#do something with the list of forms
#----- In your views.py
def MpageChecker(request):
qset = Item.objects.all()
paginator = Paginator(qset, 30)
formwizard = MPageForm(list(MPageFormMaker(paginator)))
#then deal with it like a normal formwizard
Essentially just instantiate the formwizard class and then let it take care of everything. Since it uses a paginator class to make the forms you can use any sort of personalization you'd like.
BTW: I haven't tested this code so it may have a few typos but it should be enough to get you on your way.
EDIT ... fix the ordering problem, now all ordering should be preserved correctly across pages!