Django - Affiliate links setup with URL redirection - django

Does anyone know of any better ways to replace long affiliate URL's with cloaked links or short, such that users only see shortened links.
Something like this :
"anothersite.com/offer.html/affiliate_id=001"
cloaked like this:
"http://site.com/click/offer"
Assuming if there more affiliate links like this, setting up redirection would easily fill up urls.py with more patterns. Django’s built-in generic views provide ways to setup (external) URL redirection applications but just wondering whether there are any better ways to do this without filling the .htaccess or urls.py.

If you want to be able to build on this in the future, you could create your own simple model:
class AffiliateLink(models.Model):
slug = models.SlugField(unique=True)
full_url = models.URLField()
Then create a view to do the redirection:
def affiliate_link(request, slug):
link = get_object_or_404(AffiliateLink, slug=slug)
return redirect(link.full_url)
Then setup the urls file:
(r'^affiliates/(?P<slug>[^/]+/', 'myapp.views.affiliate_link'),
And that it.

Django comes with an additional redirects app.

Related

Add own functions in views.py wagtail

I have setup a wagtail website. It works great for postings like a blog and simply add new pages.
But what if I want to add some extra functions to a page. Like showing values from my own database in a table.
Normally i use a models.py, views.py and template.py. But now I don’t see any views.py to add functions or a urls.py to redirect to an url?
Don’t know where to start!
Or is this not the meaning of a wagtail site, to customize it that way?
Thnx in advanced.
You can certainly add additional data to pages. One option is to add the additional information to the context of a page type by overriding its get_context method. For example, this page is just a place to display a bunch of links. The links and the collections they belong to are plain old Django models (managed as snippets). And then there is a page model that queries the database like this:
def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
collection_tuples = []
site = Site.find_for_request(request)
for collection in Collection.objects.filter(links__audiences=self.audience, site=site).distinct():
links = Link.objects.filter(audiences=self.audience, collections=collection, site=site)
collection_tuples.append((collection.name, links.order_by('text')))
# sort collection tuples by the collection name before sending to the template
context['collection_tuples'] = sorted(collection_tuples, key=lambda x: x[0], reverse=False)
return context
Another option is to do basically the same thing - but in a StructBlock. Then you can include the StructBlock in a StreamField on your page. Most of the Caltech site is written using blocks that can be included in one large StreamField on a page. Some of those blocks manage their own content, e.g. rich text blocks or image blocks, but others query data and render it in a block template.
To add to #cnk's excellent answer - you can absolutely use views.py and urls.py just as you would in an ordinary Django project. However, any views you define in that way will be available at a fixed URL, which means they'll be distinct from the Wagtail page system (where the URL for a page is determined by the page slug that the editor chooses within the Wagtail admin).
If you're defining URLs this way, make sure they appear above the include(wagtail_urls) route in your project's top-level urls.py.

Transfer Class-based view to another

I created a DetailView class that can receive links from categories or posts from a website. In the “get_object ()” method, I identify if it is Category or Post models (by url slug). The URLs for this class are listed below:
/category/
/category/subcategory/
/category/post/
/category/subcategory/post/
The class got too long because the categories and posts have specific behaviors.
I was wondering if it is possible to "transfer" one class to another to handle specific information?
For example:
GenericView redirect to CategoryView after identifying that it is the url: / category / or for PostView, if it is / category / post /
NOTE: I am transferring the Wordpress site to Django, so I cannot change the url structure.
Is there any way to do this? Do you suggest another better solution?

Need Guidance for django wagtail

currently i'm trying to Integrating Wagtail with existing django project.
I'm new in wagtail, and still learning about wagtail
class BlogPage(Page):
body = RichTextField(blank=True)
categories = ParentalManyToManyField('blog.BlogCategory', blank=True)
location = models.ForeignKey('blog.Location', on_delete=models.PROTECT)
and then i register the category and the location model as snippets.
how's the best practice for build page contains of BlogPage with
certain category / location ?
and how to call that page from django's menu
or maybe where can i find documentation for integrating wagtail to existing django project
Thank you
I think you're looking for a Blog Listing Page, where you can list all your blog posts and then have blog posts based on a certain category.
You'll probably want to use a RoutablePageMixin (if you're not creating an SPA with Vue or React). A RoutablePageMixin lets you automatically create additional child pages, without having to create Wagtail child pages.
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
class BlogListingPage(RoutablePageMixin, Page):
"""BlogListingPage class."""
template = 'cms/blog/blog_listing_page.html'
subpage_types = ['pages.BlogPage']
# ... other fields here
#route(r'^category/(?P<cat_slug>[-\w]*)/$', name='category_list')
def category_list(self, request, cat_slug):
"""Return posts in a certain category."""
context = self.get_context(request)
posts = BlogPage.objects.live().filter(categories__slug=cat_slug).order_by('-pub_date')
context['posts'] = posts
return render(request, 'cms/blog/blog_category_page.html', context)
Note I did not test this code, you may need to fix any errors and adjust this for your needs.
The above code will take your blog listing page (say its localhost:8000/blog/) and create a category listing page (ie. localhost:8000/blog/category/topic-slug/)
That topic-slug will be passed into the category_list() method, where you can then filter your BlogPage's based on the category(ies) it's in. It will add posts to your page, and render a different listing page, where you can customize your template.
It's been a while since I checked, but the Wagtail Bakery Demo probably has examples of this in there (and a lot of really sweet goodies).
You can read more about Wagtail Routable Pages at https://docs.wagtail.io/en/latest/reference/contrib/routablepage.html as well.

How Do I Capture the Subdomain in a Django URL Pattern?

I have a Django app that currently supports multiple languages. I'd like to add subdomain support so that going to 'de.mysite.com' queries articles in German, while 'mysite.com' queries things in English (the default language). There will be about 20 subdomains all pointing to the same Django app.
I have an abstract model with all of the fields for my data and a derived model for each language. Each language has its own database table, like so:
class ArticleBase(models.Model):
title = models.CharField(max_length=240, unique=True)
date_added = models.DateField(auto_now_add=True)
class Meta:
abstract = True
# This is English, the default.
class Article(ArticleBase):
pass
class Article_de(ArticleBase):
pass
I can get articles like this (I have this working today):
def article(request, title, language=None):
if language:
mod = get_model('app', 'Article_' + language)
items = mod.filter(title=title)
else:
items = Article.objects.filter(title=title)
This is my current URL pattern:
url(r'^article/(?P<title>[a-zA-Z_-]+)/$", 'app.views.article', name='article'),
How can I parse the subdomain prefix in a URL pattern so it can be passed into the article view? Or should I be getting this info from the request when I'm processing the view?
The URLS in django don't have access to the domain section of the URL, so that is not an option.
Doing it manually in each view is doable but not so easy to maintain.
I think that a custom middleware solution is probably better where you check the request headers in the middleware and then load the appropriate language (or you replace the accept-language headers and let django do it's magic)
The localemiddleware can make the language available which you can then easily use to pass through to the models/queries as needed.
Also if I may ask: why store every entry in a separate table/model? Can't you just add a language field to the model and store everything in one table? Because going for 20 or so models for articles can become harder to maintain than just 1 model.
UPDATE:
I've played around a little bit and the middleware required is quite simple (although my testing was quite limited):
class SubDomainLanguage(object):
def process_request(self, request):
try:
request.session['django_language'] = request.META['HTTP_HOST'].split('.')[0]
except KeyError:
pass
is the middleware and then change the settings to include the following:
MIDDLEWARE_CLASSES = (
...
'django.contrib.sessions.middleware.SessionMiddleware',
'subdomainmiddleware.SubDomainLanguage',
'django.middleware.locale.LocaleMiddleware',
...
)
This way you can then leverage the normal Django builtin i18n support.
In the views the language is then available in request.LANGUAGE_CODE
I have a case that I have subdomains with periods such as 1.2.3.mydomain.net. I know my domain and set it in my local_settings.py as:
DOMAIN = 'EXAMPLE.net'
TEST_SUBDOMAINS = ["127.0.0.1", "localhost", "testserver"]
I then check that I don't do anything if its for test purposes.
After that I get my sub domain as follows:
if (DOMAIN in TEST_SUBDOMAINS):
return HttpResponse("test only")
subdomain = request.META['HTTP_HOST'].replace((DOMAIN), "")[:-1]
# -1 is to remove the trailing "." from the subdomain
if subdomain and subdomain != "www" :
# whatever you need...
You can just use this easy to use django-subdomains library. It also support subdomain-based URL routing and reversing.

reverse django url to object, not view. possible?

I have a set of URLs for which I would like to retrieve the django model associated with this url, not the django view which is what the reverse URL Dispatcher does. The code would ideally look something like this:
urls_to_lookup = get_urls_to_lookup()
models = []
for url in urls_to_lookup:
model = retrieve_django_model(url)
models.append(model)
Since the urls I would like to lookup have unique models associated with them (via the #permalink decorator), it seems like this is possible but my google skillz are coming up empty handed. Thanks for your help!
EDIT In case it helps brainstorming solutions, I'm pulling these URLs from Google Analytics for all blog posts and I want to dynamically display most frequently viewed pages. The URL itself is helpful, but I would like to grab the title, teaser, etc for each blog post for display and that is all stored in the database.
If you are trying to create a sitemap; there's the sitemaps contrib app.
If you are trying to print out all the URLs in a nice format, see this answer.
I'm trying to think of a reason for having such a feature, but it escapes me. However, this should do what you want (not tested):
from django.db import models
def retrieve_django_model(url):
m_instances = [m for m in models.get_models() \
if m.objects.all().count()]
for m in m_instances:
if m.objects.all().order_by('?')[0].get_absolute_url() == url:
return m
else:
return None
Since we can only fetch the absolute url from instances not models, the initial list comprehension filters out those models for which there are no instances, and hence we cannot get the absolute URL.