forking django-oscar views shows an error - django

I forked customer app , to add a tab in http://oscar/accounts/...(example products)
to edit/show catalogue Views (Dashboard>Catalogue)
Error that I get to use that view is
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
I used views with the same method for payment checkout, but this one runs into errors.
# yourappsfolder.customer.apps.py
import oscar.apps.customer.apps as apps
from oscar.apps.dashboard.catalogue import apps as dapps
from django.views import generic
from django.conf.urls import url
from oscar.core.loading import get_class
from .views import ProductListView
class CustomerConfig(apps.CustomerConfig):
name = 'yourappsfolder.customer'
def ready(self):
super().ready()
self.extra_view =ProductListView
def get_urls(self):
urls = super().get_urls()
urls += [
url(r'products/',self.extra_view.as_view(),name='Products'),
]
return self.post_process_urls(urls)
This is the view I copied from oscar.apps.dashboard.catalogue
# yourappsfolder.customer.views
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
from django.views import generic
from oscar.apps.dashboard.catalogue.views import ProductListView as UserProductListView
class ProductListView(UserProductListView):
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['form'] = self.form
ctx['productclass_form'] = self.productclass_form_class()
return ctx
def get_description(self, form):
if form.is_valid() and any(form.cleaned_data.values()):
return _('Product search results')
return _('Products')
def get_table(self, **kwargs):
if 'recently_edited' in self.request.GET:
kwargs.update(dict(orderable=False))
table = super().get_table(**kwargs)
table.caption = self.get_description(self.form)
return table
def get_table_pagination(self, table):
return dict(per_page=20)
def filter_queryset(self, queryset):
"""
Apply any filters to restrict the products that appear on the list
"""
return filter_products(queryset, self.request.user)
def get_queryset(self):
"""
Build the queryset for this list
"""
queryset = Product.objects.browsable_dashboard().base_queryset()
queryset = self.filter_queryset(queryset)
queryset = self.apply_search(queryset)
return queryset
def apply_search(self, queryset):
"""
Search through the filtered queryset.
We must make sure that we don't return search results that the user is not allowed
to see (see filter_queryset).
"""
self.form = self.form_class(self.request.GET)
if not self.form.is_valid():
return queryset
data = self.form.cleaned_data
if data.get('upc'):
# Filter the queryset by upc
# For usability reasons, we first look at exact matches and only return
# them if there are any. Otherwise we return all results
# that contain the UPC.
# Look up all matches (child products, products not allowed to access) ...
matches_upc = Product.objects.filter(upc__iexact=data['upc'])
# ... and use that to pick all standalone or parent products that the user is
# allowed to access.
qs_match = queryset.filter(
Q(id__in=matches_upc.values('id')) | Q(id__in=matches_upc.values('parent_id')))
if qs_match.exists():
# If there's a direct UPC match, return just that.
queryset = qs_match
else:
# No direct UPC match. Let's try the same with an icontains search.
matches_upc = Product.objects.filter(upc__icontains=data['upc'])
queryset = queryset.filter(
Q(id__in=matches_upc.values('id')) | Q(id__in=matches_upc.values('parent_id')))
if data.get('title'):
queryset = queryset.filter(title__icontains=data['title'])
return queryset

You have a circular import - move the import of the list view into the ready() method of the app config:
class CustomerConfig(apps.CustomerConfig):
name = 'yourappsfolder.customer'
def ready(self):
super().ready()
from .views import ProductListView
self.extra_view =ProductListView

Related

permission_required for user who only users who are part of a group ,in view based class

Based on a tutorial,i have a view with a restriction on the display of data, based on a permission of the form "book.can_view" in class BookDetailView
This works, but the probleme are every user not have access to the view I'd like to do the same thing but using the group name. . I would like only users who are part of a group named "premium" to have access to this page
my views.py
from django.shortcuts import render
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.http import HttpResponse
from catalog.models import Book, Author, BookInstance, Genre
from accounts.models import CustomUser
from django.views.generic import ListView, DetailView
class BookListView(ListView):
model = Book
paginate_by = 10
#permission_required = 'catalog.view_book'
def index(request):
# Generate counts of some of the main objects
num_books = Book.objects.all().count()
num_instances = BookInstance.objects.all().count()
# Available books (status = 'a')
num_instances_available = BookInstance.objects.filter(
status__exact='a').count()
# The 'all()' is implied by default.
num_authors = Author.objects.count()
context = {
'num_books': num_books,
'num_instances': num_instances,
'num_instances_available': num_instances_available,
'num_authors': num_authors,
}
# Render the HTML template index.html with the data in the context variable
return render(request, 'index.html', context=context)
class BookDetailView(PermissionRequiredMixin, DetailView):
"""Generic class-based detail view for a book."""
model = Book
template_name = "catalog/permission_required.html"
permission_required = 'book.can_view'# change this line ?
class AuthorListView(ListView):
"""Generic class-based list view for a list of authors."""
model = Author
paginate_by = 10
class AuthorDetailView(DetailView):
"""Generic class-based detail view for an author."""
model = Author
thank for help
I see it more or less like this.
from django.contrib.auth.mixins import UserPassesTestMixin
from django.contrib.auth.models import Group
class BookDetailView(UserPassesTestMixin, LoginRequiredMixin, DetailView):
model = Book
template_name = "catalog/permission_required.html"
def test_func(self):
premium_group = Group.objects.filter(name = "premium") # or get
if self.request.user in premium_group:
return True
else:
return False
Thank you ttt, the code you told me
def test_func(self):
premium_group = Group.objects.filter(name = "premium") # or get
if self.request.user in premium_group:
return True
else:
return False
restricts access to all users, and i have page 403 , even the one who has the right to the "premium" group and even the admin, this sends you to the error page.

AssertionError: No templates used to render the response

I solved the problem while writing this question but I wanted to post it so maybe someone needs this answer
Hello my friends.
i am new to django testing.
while i'm testing my views i faced this error in some views.
This is my views.py:
def all_programs(request):
programs = Program.objects.all()
return render(request, 'orders/all_programs.html', {'programs': programs})
def checkout(request, slug):
if request.method == 'POST':
# get data from form and save it
program = get_object_or_404(Program, slug=slug)
dates = ProgramDate.objects.filter(program=program)
return render(request, 'orders/checkout.html', {'program': program, 'dates': dates})
This is urls.py:
from django.urls import path
from django.views.generic import RedirectView
from .views import *
app_name = 'orders'
urlpatterns = [
path('', RedirectView.as_view(url='https://www.another-website.net')),
path('tests/', all_programs, name='all_programs'),
path('checkout/<str:slug>/', checkout, name='checkout'),
path('checkout/return_page/', ReturnPage.as_view(), name='return_page'),
]
And this is test_views.py:
from django.test import TestCase
from django.shortcuts import reverse
class TestViews(TestCase):
def test_all_programs(self):
response = self.client.get(reverse('orders:all_programs'))
self.assertTemplateUsed(response, 'orders/all_programs.html')
def test_checkout(self): # error id here
response = self.client.get(reverse('orders:all_programs', kwargs={'slug': 'test'})) # I tried this
# response = self.client.get('http://127.0.0.1:8000/checkout/test/') #and this
self.assertTemplateUsed(response, 'orders/checkout.html')
The solution in this case is:
The test in Django does not use the default database but rather creates its own database that does not have any records (I completely forgot that), so you must create records before you start tests that relate to the database.
in this case i must create new program before test:
class TestViews(TestCase):
_program = {
'name': 'test_program',
'price': 1000,
'abbreviation': 'test',
'description': 'test_program',
'slug': 'test_program',
'id_from_zoho': 1000,
}
def test_checkout(self):
program = Program(**self._program)
program.save()
response = self.client.get(reverse('orders:checkout', kwargs={'slug': program.slug}))
self.assertTemplateUsed(response, 'orders/checkout.html')

flask-admin "AdminIndexView" not working to restrict the /admin page

this is my first question in stackoverflow.
i need to change flask_admin's default page but it's not working, i want to make it inaccessible for non-admin users...
admin file:
from flask import redirect, url_for
from flask_admin import AdminIndexView
from flask_admin.contrib.sqla import ModelView
from flask_login import current_user
from wtforms.fields import FileField
from wtforms.validators import DataRequired
from . import adm, db
from .models import User, Product
def configure():
adm.index_view = IndexAdmin()
adm.add_view(UserAdmin(User, db.session))
adm.add_view(ProductsAdmin(Product, db.session))
class IndexAdmin(AdminIndexView):
def is_accessible(self):
return current_user.is_authenticated and current_user.admin
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for("views.home_page"))
class UserAdmin(ModelView):
form_excluded_columns = ["created_date", "updated_date", "products", "adresses"]
column_exclude_list = ["password", "phone", "money"]
column_searchable_list = ["email"]
def is_accessible(self):
return current_user.is_authenticated and current_user.admin
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for("admin.index"))
class ProductsAdmin(ModelView):
form_excluded_columns = ["created_date", "updated_date", "user_products"]
column_exclude_list = ["image"]
column_type_formatters = {"image": FileField(label="Image", validators=[DataRequired()])}
def is_accessible(self):
return current_user.is_authenticated and current_user.admin
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for("admin.index"))
I tried to do this to put the page restrict, but this isn't working...
class IndexAdmin(AdminIndexView):
def is_accessible(self):
return current_user.is_authenticated and current_user.admin
def inaccessible_callback(self, name, **kwargs):
return redirect(url_for("views.home_page"))
I'm not certain this is the gap, but the official docs do not suggest setting this as you are with adm.index_view =. Instead https://flask-admin.readthedocs.io/en/latest/api/mod_base/#default-view suggests:
admin = Admin(index_view=MyHomeView())
So, one possibility is that the init process for Admin() does something with the index_view that doesn't happen when you set it directly.
The docs (https://flask-admin.readthedocs.io/en/latest/api/mod_base/#flask_admin.base.Admin.init_app) also indicate that you can delay this by using init_app, which is the way I've used it before. Something like:
admin.init_app(app, index_view= MyHomeView())

Is it possible to add 2nd slug to URL path in Django?

I'm using Django version 2.1.
I want to create this type of URL Path in my Project:
www.example.com/bachelor/germany/university-of-frankfurt/corporate-finance
Is it possible to do it in Django?
Yes, say for example that you have a slug for an Author, and one for a Book, you can define it as:
# app/urls.py
from django.urls import path
from app.views import book_details
urlpatterns = [
path('book/<slug:author_slug>/<slug:book_slug>/', book_details),
]
Then the view looks like:
# app/views.py
from django.http import HttpResponse
def book_details(request, author_slug, book_slug):
# ...
return HttpResponse()
The view thus takes two extra parameters author_slug (the slug for the author), and book_slug (the slug for the book).
If you thus query for /book/shakespeare/romeo-and-juliet, then author_slug will contains 'shakespeare', and book_slug will contain 'romeo-and-juliet'.
We can for example look up that specific book with:
def book_details(request, author_slug, book_slug):
my_book = Book.objects.get(author__slug=author_slug, slug=book_slug)
return HttpResponse()
Or in a DetailView, by overriding the get_object(..) method [Django-doc]:
class BookDetailView(DetailView):
model = Book
def get_object(self, queryset=None):
super(BookDetailView, self).get_object(queryset=queryset)
return qs.get(
author__slug=self.kwargs['author_slug'],
slug=self.kwargs['book_slug']
)
or for all views (including the DetailView), by overriding the get_queryset method:
class BookDetailView(DetailView):
model = Book
def get_queryset(self):
qs = super(BookDetailView, self).get_queryset()
return qs.filter(
author__slug=self.kwargs['author_slug'],
slug=self.kwargs['book_slug']
)

django generate a feed for a particular tag

I want to generate a feed of latest entries of a blog post under a particular tag. I used django-tagging. How can i do this? Here is how i defined my LatestEntriesFeed
from django.core.exceptions import ObjectDoesNotExist
from django.utils.feedgenerator import Atom1Feed
from django.contrib.sites.models import Site
from django.contrib.syndication.feeds import Feed
from articles.models import Entry
current_site = Site.objects.get_current()
class LatestEntriesFeed(Feed):
title = 'Latest Entries for %s' % current_site
link = '/feeds/latest/'
description = 'Latest entries posted.'
def items(self):
return Entry.live.all()[:100]
def item_pubdate(self, item):
return item.pub_date
def item_guid(self, item):
return "tag:%s,%s:%s" % (current_site.domain,
item.pub_date.strftime('%Y-%m-%d'),
item.get_absolute_url())
After realizing how get_object() works i finally make it work. I added some imports:
from django.core.exceptions import ObjectDoesNotExist
from tagging.models import Tag, TaggedItem
class TagFeed(LatestEntriesFeed):
def get_object(self, bits):
if len(bits) != 1:
raise ObjectDoesNotExist
return Tag.objects.get(name__exact=bits[0])
def title(self, obj):
return "%s: Latest entries under the tag '%s'" % (current_site.name, obj.name)
def description(self, obj):
return "%s: Latest entries under the tag '%s'" % (current_site.name, obj.name)
def items(self, obj):
return TaggedItem.objects.get_by_model(Entry, obj.name)
Lets say I access /feeds/tag/thetagnamehere/ then get_object will fetch tag object with name "thetagnamehere". Method items() will then fetch Entries under the tag "thetagnamehere". I also created feeds/tag_title.html and feeds/tag_description.html in my templates directory. In my project urls.py:
feeds = {
'latest': LatestEntriesFeed,
'tag': TagFeed,
}
(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
{'feed_dict': feeds}, ),
That's it. Im now able to generate a feed for a particular tag in my sidebar. I hope that helps.
Change your items method to the folowing:
from tagging.models import Tag, TaggedItem
def items(self):
tag = Tag.objects.get(name='you tag name')
return TaggedItem.objects.get_by_model(Entry, tag)