The first thing I did was of course customizing forms, views and templates in site-packages. And then I learned that everything will be reset to default after upgrading the package.
So now I decided to create a new application "accounts" and make customizations there.
My question is which approach is better (haven't tried any, sorry)
First approach:
Set INCLUDE_REGISTER_URL = False
in accounts.views import RegistrationView and create MyRegistrationView (same thing with forms)
in accounts.urls include registration.backends.default.urls and create my own urlpattern for MyRegistrationView
create custom templates in templates/registration
put registration above django.contrib.admin in INSTALLED_APPS
Second approach:
in accounts.views import RegistrationView and create MyRegistrationView (same thing with forms)
Create complete replica of registration.backends.default.urls in accounts.urls with my new custom template names
put custom templates inside my accounts app
Or are there any better approaches? (probably are)
First of all, if you want to override almost every part of redux, wont it be better to use built-in django authentication and to extend it as you wish?
Yes, you are on the right way. You need to override those things you do not like by coping them to your project and then by changing the copy. Though it's will be a cleaner code if you place templates in templates/registration, views in views.py and etc, actually you can do in some other way you wish.
Related
I have a view inheriting from LoginRequiredMixin, TemplateView, which renders some data using the admin/base_site.html template as the base. I treat it as a part of the admin interface, so it requires an administrator login. I'd like to make this view a little bit more a part of the Django admin interface by enabling the standard sidebar navigation on the left-hand side.
Note that I don't have a custom ModelAdmin definition anywhere, I simply render the template at some predefined URL. There are no models used in the interface either, it parses and displays data from database-unrelated sources.
Currently, I just build the required context data manually, e.g.:
data = super().get_context_data(**kwargs)
data.update(**{
"is_popup": False,
"site_header": None,
"is_nav_sidebar_enabled": True,
"has_permission": True,
"title": "My title",
"subtitle": None,
"site_url": None,
"available_apps": []
})
The sidebar is visible, but displays an error message:
Adding an app to available_apps ("available_apps": ["my_app"]) doesn't help either:
So my question is - how do I do that? Is there a class I can inherit from to achieve this behaviour? Or a method I can call to get all required context data for base_site.html? Or perhaps I should insert some information in my template? Perhaps I need an AdminSite object, or can somehow call methods of the default one?
By accident I noticed there is a DefaultAdminSite object in django.contrib.admin.sites, and it's instantiated as site. Therefore, in my case, simply using site is sufficient.
from django.contrib.admin import AdminSite
from django.contrib.admin.sites import site
admin_site: AdminSite = site
data.update(**admin_site.each_context(self.request))
Furthermore, turns out I can just use the apps in case importing site would be an issue, just like DefaultAdminSite does it:
AdminSiteClass = import_string(apps.get_app_config("admin").default_site)
self._wrapped = AdminSiteClass()
The app_list.html template which is included in your base template requires a context variable available_apps with a structure as described here.
As you probably won't be able to make this include work properly with your app you could also override the {% block nav-sidebar %} in your base template and provide some HTML that fits your use-case.
But after all it's probably not such a good idea to reuse templates which are made for a different app (admin) with your app because it's difficult to predict how they will behave, what their requirements are and beyond this maintainance in the long term will also be a problem as they might change with future Django versions.
You have to include django admin's default context variables used in the template. This can be done by calling each_context function:
data.update(self.admin_site.each_context(request))
I also have custom admin views and templates in my projects and this works well for me.
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.
I have a question regarding Django. I created a site and everything works as it is indented to work. The only problem I have is that first of all my urls.py and views.py files are getting quite bloated (I have one method for every page I have) and that i have for every site one template. I use {% extend basetemplate.html %} for making it at least a bit generic. However I find this attempt not really nice. Creating a method inside the urls.py and views.py in addition to create a template html file seems the wrong attempt.
I already thought about building a big controller and did some googleing but i could not find what i was looking for.
Is there something like a best practice to achieve that? How do you guys handle the amount of templates?
Any advice would be more than welcome :)
One solution is to refactor your one application into multiple applications inside your project. Each would have its own urls.py & views.py.
If all your view does is render a template, then you can use TemplateView directly in your urls.py, and you don't need to define a view for each url.
from django.conf.urls import url
from django.views.generic import TemplateView
urlpatterns = [
url(r'^about/', TemplateView.as_view(template_name="about.html"), name="about"),
url(r'^contact/', TemplateView.as_view(template_name="contact.html"), name="contact"),
]
Other generic class based views might be useful as well. If there was a way to map the urls to the template names programatically (e.g. the template name was <slug>.html, you might not even need a url for each template. However, as I said in the comments above, I can't make any specific suggestions without seeing more of your code.
Create a directory called views with the following structure.
.../project/views/
.../project/views/__init__.py
.../project/views/feature_one.py
.../project/views/feature_two.py
.../project/views/feature_three.py
# in .../project/views/__init__.py import the others
from .feature_one import *
from .feature_tow import *
from .feature_threee import *
Now you can go on and import like before from your views. You can do the same thing for admin, models, form ..etc.
For templates, break them up, use inclusion tag to include the smaller partial files. Group them and create a nice directory structure.
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.
Django tutorial suggests to organize templates like this:
Within the templates directory you have just created, create another directory called polls, and within that create a file called index.html. In other words, your template should be at polls/templates/polls/index.html. Because of how the app_directories template loader works as described above, you can refer to this template within Django simply as polls/index.html.
Tutorial also tells what happens if I just put index.html in polls/templates:
Now we might be able to get away with putting our templates directly in polls/templates (rather than creating another polls subdirectory), but it would actually be a bad idea. Django will choose the first template it finds whose name matches, and if you had a template with the same name in a different application, Django would be unable to distinguish between them. We need to be able to point Django at the right one, and the easiest way to ensure this is by namespacing them. That is, by putting those templates inside another directory named for the application itself.
My assumption was that as long as I'm creating an isolated application, it's templates are also isolated from other apps without any subfolder magic.
Is there another way to namespace, so I can refer to template as index.html without creating duplicated folders?
The way templates are organised in a Django project is very flexible. So there's nothing to stop you ordering the template files however you want, as long as you specify the correct template name in the view. For example, you could use a Class Based View for the list of Polls, specifying the template_name as whatever you like:
# polls/views.py
from django.views.generic import ListView
from .models import Poll
class PollList(ListView):
model = Poll
template_name = 'any/path/you/choose/any_name.html'
Having said that, it's good to create a consistent template structure to keep the code maintainable. I'd recommend at the very least keeping your page-level templates (things which are used to return the whole html page) structured in folders with their relevant app name, and anything you include (snippets included with the {% include %} tag) within includes subfolders, like so:
templates
- base.html
polls
- poll_list.html
includes
- poll_votes.html
Edit:
If you still need namespaces despite this, you could use URL namespaces.