Can't get Django settings inside of my view - django

I'm trying to pull stripe settings from my cookiecutter base.py, and it's not working. I'm not sure if I have not set my view correctly, or what.
I'm testing all of this locally, and I have installed stripe via pip and added it to my installed apps (not sure if I needed to do that)
here is my urls.py for the payment view
path("payment/", TemplateView.as_view(template_name="pages/Payment.html"), name="payment")
And here is my views.py
class PaymentView(TemplateView):
template_name = 'Payment.html'
def get_context_data(self, **kwargs): # new
context = super().get_context_data(**kwargs)
context['key'] = settings.STRIPE_PUBLISHABLE_KEY
return context
I've got the following in my base.py
STRIPE_SECRET_KEY = 'sk_test_xxxx'
STRIPE_PUBLISHABLE_KEY = 'pk_test_xxxxx'
I feel my issue isn't that I have the keys in the wrong place. I may just have my view class not named correctly. Any help? Thanks!

Your url is a generic TemplateView which renders the template specified.
To use your custom view you have to specify it in the url
path("payment/", PaymentView.as_view(), ...

Related

django-rest-swagger UI doesn't have form for POST request body (function based view)

I have this function-based view with django-rest-swagger decorated. However, I can't find place in UI that allow me to post the payload (request.body).
I saw a couple solutions about doing it with class-based view, but I was wondering if there is a way to do it with function-based view.
Thank you in advance!
#renderer_classes([JSONRender])
#api_view(['POST'])
def some_method(request):
body = json.loads(request.body)
return JsonResponse({'status': 'ok'})
I am gonna answer my question since the django-rest-swagger was deprecated in June 2019 and I just found out 2 feasible solutions.
First one will change the UI globally.
In ping.views (or any other location you wish) add following class.
from rest_framework.schema import AutoSchema
class CustomSchema(AutoSchema):
def __init__(self):
super(CustomSchema, self).__init__()
def get_manual_fields(self, path, method):
extra_fields = [
coreapi.Field('command', required=True, location='form', schema=String(), description='', type='', example='',
coreapi.Field('params', required=False, location='form', schema=String(), description='', type='', example='',
]
manual_fields = super().get_manual_fields(path, method)
return manual_fields + extra_fields
Add following settings in settings.py of your Django project.
REST_FRAMEWORK = {
# Corresponding path to where you added the class
'DEFAULT_SCHEMA_CLASS': 'ping.views.CustomSchema',
}
Second solution can be applied on a per-view basis. You may check here for official guide
Use #schema from rest_framework.decorators.schema to overwrite DEFAULT_SCHEMA_CLASS.
#api_view(['POST'])
#schema(CustomSchema())
def your_view(request):
print(request.body)
return JsonResponse({'task_status': 200'})
Basically, the idea is to overwrite DEFAULT_SCHEMA_CLASS. The word schema is the term that they used to refer to swagger UI for each view in rest_framework.
When you use #api_view() to decorate your function-based view, it will assign your function an attribute schema with value APIView.schema from rest_framework.views.APIView.
rest_framework.views.APIView will in further call DefaultSchema() to load the DEFAULT_SCHEMA_CLASS from your REST_FRAMEWORK configuration in settings.py.
Without other specifying, DEFAULT_SCHEMA_CLASS is rest_framework.schemas.openapi.AutoSchema by this official announcement. You might want to change it to rest_framework.schemas.coreapi.AutoSchema since it is the one that compatible with django_rest_swagger.
Hope this tutorial helps people who use django-rest-swagger (2.2.0) with function-based views for their Django project.
Please leave comments if there are anything I can help on this issue.

Django Admin list page: Custom Action Buttons (url) problem, what is wrong?

i have followed this tutorial https://books.agiliq.com/projects/django-admin-cookbook/en/latest/action_buttons.html
This is the relevant part of my code:
#admin.register(Partner)
class PartnerAdmin(admin.ModelAdmin):
change_list_template = 'change_list.html'
model = Partner
.
.
.
def get_urls(self):
return super().get_urls() + [path('sync/', self.sync_partners, name='partners_sync_partners')]
#staff_member_required
def sync_partners(self, request):
#TODO: Sync code should go here
self.message_user(request, "Partners sync complete")
return HttpResponseRedirect("../")
The url on template is referenced with {% url 'admin:partners_sync_partners' %} which is pointing to /admin/partners/partner/sync/ and i think it should be /admin/partners/sync/
When i click the button, i am getting this error:
Partner with ID "sync" doesn't exist. Perhaps it was deleted?
I guess the problem is related with the url generated.
My code is inside my app 'partners' in partners/admin.py and my template is under partners/templates/change_list.html
PS: I'm using Django 2.1.1 and Python 3.6.5
Here is an example of custom user which i have created where i have to show all fields in django admin site for custom user .
so you can add that button in list display
list_display = ('email', 'phone','account_name','account_number','bank_name','bsb_number','account_summary')
now make that button a method and give url where you want to render it.
def account_summary(self,obj):
ow_tags = True
return format_html(
'<a class="button" href="{}">Account</a> ',reverse('all_accounts_view', args=[obj.pk]))
account_summary.allow_tags = True
dont forget to add
from django.urls import reverse

Django signal get request full path

I wrote a signal in my django project, inside I want to send an email with the full path of my website. But to do so, I need to get the request object inside the signal, how could I do that? Thanks.
#receiver(pre_save, sender=AccessRequest)
def email_if_access_true(sender, instance, **kwargs):
#How can I get the full path of my website here?
pass
If you don’t have access to the request object, you can use the get_current() method of the Site model’s manager.
from django.contrib.sites.models import Site
#receiver(pre_save, sender=AccessRequest)
def email_if_access_true(sender, instance, **kwargs):
current_site = Site.objects.get_current()
if current_site.domain == 'foo.com':
#do other stuff here
else:
pass
you need to ensure that you defined SITE_ID=1 in your settings
If you don’t have access to the request object, you can use the get_current() method of the Site model’s manager.
from django.contrib.sites.models import Site
#receiver(pre_save, sender=MyModel)
def my_function_without_request(sender, instance, **kwargs):
current_site = Site.objects.get_current()
domain = current_site.domain
# Do something
To enable the sites framework, follow these steps:
Add 'django.contrib.sites' to your INSTALLED_APPS setting.
Define a SITE_ID setting: SITE_ID = 1
Run migrate.
Source: https://docs.djangoproject.com/en/3.2/ref/contrib/sites/
To set the correct name and domain for your project, you can use a data migration.
To start, make an empty migration file you can work from (Django will put the file in the right place, suggest a name, and add dependencies for you):
python manage.py makemigrations --empty yourappname
Then, open up the file and create a new function and have RunPython use it.
from django.contrib.sites.models import Site
from django.db import migrations
def set_name_and_domain():
one = Site.objects.all()[0]
one.domain = 'yourdomain.com'
one.name = 'Your Name'
one.save()
class Migration(migrations.Migration):
dependencies = [
('yourappname', '0001_initial'),
]
operations = [
migrations.RunPython(set_name_and_domain),
]
All of this will save your domain and site name in your database where you can access it without having the request object. So far I have not found a better way to do this.
Source: https://docs.djangoproject.com/en/3.2/topics/migrations/#data-migrations
Put following code in your pre_save signal receiver:
from django.contrib.sites.models import get_current_site
current_site = get_current_site(request=None)
domain = current_site.domain
protocol = "http"
You can generate absolute url to your website in email by passing required context variables to template. If access_request is instance in your case and there is one get_abosulte_url() method in your AccessRequest model, then following line in email template will give you absolute url.
{{ protocol }}://{{ domain }}{% access_request.get_absolute_url %}
Reference - PasswordResetForm in django.contrib.auth.form.

Reload django url's without restarting the server

Why? I want multiple models on the first level of the path :)
Using: Django 1.4.1
Code setup urls:
PAGE_SLUGS = '|'.join(Page.objects.values_list('slug', flat=True))
BRAND_SLUGS = ... same concept
(r'^(?P<brand_slug>%s)/$' % BRAND_SLUGS, 'novomore.apps.catalog.views.product_showcase_list'),
url(r'^%s/$' % PAGE_SLUGS, 'prefab.apps.pages.views.page_detail', name='page'),
In the save method of model Page:
if self.pk is None:
clear_url_caches()
I don't want to run a query on each request so thats why i use this aproach, when i add a instance the PAGE_SLUGS need to be updated.
clear_url_caches() doesnt seem to work
Any suggestions?
This doesn't do the trick:
if settings.ROOT_URLCONF in sys.modules:
reload(sys.modules[settings.ROOT_URLCONF])
reload(importlib.import_module(settings.ROOT_URLCONF))
From How to reload Django's URL config:
import sys
from django.conf import settings
def reload_urlconf(self):
if settings.ROOT_URLCONF in sys.modules:
reload(sys.modules[settings.ROOT_URLCONF])
return import_module(settings.ROOT_URLCONF)
I don't think what you're trying to do is a good idea. Why not simply allow any slug pattern in the URL regex, but return a 404 if you can't find the Page in question? That would have the same effect and be much simpler.
url(r'^(?P<slug>\w+)/$', 'prefab.apps.pages.views.page_detail', name='page'),
then your view code can do something like
from django import shortcuts
def page_detail(request, slug):
page = shortcuts.get_object_or_404(Page, slug=slug)
...

What is the correct way to extend / modify a view of external app in Django?

I'm working on a Django project and I have a few external apps that are installed to my virtual-env.
One of the app has a feature to upload a file by defining an def upload and route the /upload to it in the urls.py
Now I want to added some features such as #login_required to the method or sending the request.user together with the parameters.
I can do it by changing directly to the external app code, however It shall breaks if the app is upgraded.
I try to copy the the views.py of the app to my local app folder under the same name and write my own code there but It doesn't seem to work (as template modification)
Is there other options for me ? Thanks !
You can wrap the external app's view with your own view. In your own views.py:
from external_app.views import upload_view
#login_required
def custom_upload_view(self, request, *args, **kwargs):
# Do something before
...
return upload_view(request, *args, **kwargs)
You just need to make sure you have your own URL pattern pointing to your custom view in your url config before the external apps urls