I've read in a book that you should avoid doing this:
from .views import *
What I am currently doing is the following:
from . import views
My first question is, if this is the same thing just written differently?
My second question is if I should import it this way above or should I import every view separately?
from .views import (DetailView, EditView, DeleteView,
ListView, AnotherView, OneMoreView)
I mean it is bad practice because you import everything, even if you do not use it. If you have helper functions in your views, it imports those as well. If you go with the second option you must use the prefix views. before any view function/class. This can be a nuisance, therefore you should just import each view you would like to use, then you can just call the view.
Related
I know my question is very similar to what is "request" in Django view but I can't make sense of the answers provided. I have also read the documentation that is related to my question, but still don't understand. I would greatly appreciate any elaboration to the other answers in addition to anything I ask that isn't covered in that question.
In views.py, we can have something like this:
from django.shortcuts import render
from django.http import HttpResponse
def home(request):
return HttpResponse("Hello, World")
And in urls.py we have something like this:
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='hello-world-home'),
]
My question involves views.home being passed in as a parameter to path. Based on one of the answers to a similar question, views.home is passing the "function object" as a parameter to path. If it's not calling the function, don't we need pass it like this: views.home()? How does it eventually get called by path?
If there is some documentation about being able to pass in a reference to a function in Python, I would appreciate it if you could link it.
Is being able to pass in a reference to a function exclusive to Python, or can it be replicated in a compiled language (i.e. C++)?
to understand it properly how the path function is working in Django you need to read the path method
Here is the link to go over Path definition.
https://github.com/django/django/blob/main/django/urls/conf.py#L57
Hope that will solve your confusion.
In django, to display models on admin page, we have to first register all the models in admin.py.
If there are so many models to register, we have to write admin.site.register(model_name) so many times.
Its kind of a boring task.
So I was wondering if there is any way in python to import all the classes in module as list.
for instance, admin.py,
from django.contrib import admin
from .models import * as list_name #like this is there any way we can get all things inside * in list ?
for i in list_name:
admin.site.register(i) #so that this way I have to write only one line of code to register all classes.
Is there any way to save writing lot of lines here ?
I think that the dir function will be useful here. Something like:
from django.contrib import admin
from django.db.models import Model
import models
for i in dir(models):
m = getattr(models, i)
if isinstance(m, Model):
admin.site.register(m)
First of all, site.register allow you to pass a model or iterable of models (docs) - so you can simply pass a list of models you want to register. To accomplish this automatically - without ever needing to edit the admin.py module - I suggest to reimport your models in an __init__.py file.
from my_app import models
site.register(map(models.__dict__.get, models.__all__))
Content of my_app.models.__init__.py:
from .cat import Cat
from .dog import Dog
__all__ = ["Cat", "Dog"]
I have something like this in one of my apps's models.py :
class Account(AbstractBaseUser):
email = models.EmailField(unique=True)
I want to import a class from another app's views.py as below:
from anotherapp.views import MyClass
The problem is in the first lines of anotherapp.views file, I imported the Account class. So when I want to import MyClass into my models.py file, this error raises :
ImportError: cannot import name Account
That is circular import error you are encountering. While it is bad practice to import from views to models in Django, if you still want to, you can follow methods in this question to resolve it.
Here are few alternative ways that can be considered as good practice:
You can consider importing other low-level modules exist within anotherapp instead of MyClass (not depending on views.py)
You can use Django's signals to catch anotherapp's events project wide and act according to.
You can create a third file, say utils.py in anotherapp, move MyClass there and let anotherapp/views.py and your app's models.py import from anotherapp.utils
Dilemma
My views.py gets pretty unwieldy, so I want to separate it into a separate views module inside of my app. However, I'm not sure this is a good idea, for two reasons:
If my views file is the same name as the app name, I cannot import the model without using django.db.get_model, therefore I am worried my approach may be flawed. I have heard it is best practice to avoid name collision within modules; should I rename my view files?
I'm not sure if creating a views module is considered good practice within the Django community in general.
Example
For example, for an app named blogs, with a Blog model and a Post model:
blogs/
__init__.py
models.py
urls.py
views/
__init__.py
blogs.py
posts.py
Here is my blogs.views.blogs:
# project/blogs/views/blogs.py
from django.db.models import get_model
from django.shortcuts import get_object_or_404
from django.views.generic import ListView, DetailView
# Cannot import model directly, results in `ImportError: No module named models`.
# This can be resolved if I resolve the name collision between this file and
# the app itself.
#
# from blogs.models import Blog
class BlogListView(ListView):
model = get_model('blogs', 'Blog')
def get_queryset(self):
return self.model.objects.all()
class BlogDetailView(DetailView):
model = get_model('blogs', 'Blog')
def get_object(self):
blog_pk = self.kwargs.get('blog_pk')
return get_object_or_404(self.model.objects, pk=blog_pk)
Question
My question is twofold:
Should I be separating my views in the first place?
If so, is using get_model a good idea, or is there a way I can import my model directly without using this method? Or should I change my view file names, for example by adding the suffix _views (e.g.: blogs.views.blogs_views.py) in order to avoid the problem altogether?
I cannot import the model without using django.db.get_model
You can: from project_name.app_name.models import MyModel And it's preferable way, 'relative imports for intra-package imports are highly discouraged', - as said in PEP-8.
There shouldn't be any problems with names, views.py has no special meaning in Django, it's just a convention.
You can keep your views in any file in any module under any name you want. So there is no special rules here, if you think that separating the module into submodules will be good, do it.
As DrTyrsa points out, views has no special meaning. So as an alternative to creating a subpackage, you could just create several files at the same level as the existing views.py - blog_views.py, posts_views.py, etc. As long as you use the correct reference in urls.py, this works fine.
So, Generic views are pretty cool, but what I'm interested in is something that's a generic template.
so for example, I can give it an object and it'll just tostring it for me.
or if I give it a list, it'll just iterate over the objects and tostring them as a ul (or tr, or whatever else it deems necessary).
for most uses you wouldn't need this. I just threw something together quickly for a friend (a bar stock app, if you must know), and I don't feel like writing templates.
If there's a django model for it, you can just stick to django.contrib.admin or django.contrib.databrowse. If not, then you might manage by skipping the django template altogether. example:
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)
But of course you wanted to avoid even writing that much, so instead of doing html, we can use plain text and the pprint module:
from django.http import HttpResponse
import datetime
from pprint import pformat
def current_datetime(request):
now = datetime.datetime.now()
return HttpResponse(pformat(now), mimetype="text/plain")
edit: Hmm... this seems like something a view decorator should handle:
from django.http import HttpResponse
import datetime
import pprint
def prettyprint(fun):
return lambda request:HttpResponse(
pprint.pformat(fun(request)), mimetype="text/plain")
#prettyprint
def current_datetime(request):
return datetime.datetime.now()
I don't see you getting away from writing templates, especially if you would want to format it, even slightly.
However you can re-use basic templates, for e.g, create a generic object_list.html and object_detail.html
that will basically contain the information to loop over the object list and present it, and show the object detail. You could use these "Generic" templates across the entire app if need be.