How to have a URL like this in Django? - python

How can I have URLs like example.com/category/catename-operation/ in Django?
Also in some cases the user enters a space separated category, how can I handle that?
E.g if the user enters the category as "my home", then the URL for this category will become
example.com/my home/ which is not a valid URL.
How can I handle these things?

If you want to keep your URLs pretty, for example when a user enters "my category" you could have "my-category" instead of "my%20category" in the URL. I suggest you look into SlugField (http://docs.djangoproject.com/en/dev/ref/models/fields/#slugfield) and prepopulating that slugfield using ModelAdmin's prepopulated_fields attribute.

http://example.com/my%20home/ is a valid URL where space character is escaped and Django will do all escaping/unescaping for you.

You can use the slugify template tag within your views to deal with spaces and such like so:
from django.template.defaultfilters import slugify
slugify("This is a slug!") # Will return u'this-is-a-slug'

You can try an improved version of SlugField called AutoSlugField which is part of Django Custom Management Command Extensions.

You could consider adding a URL-friendly name to your category and using that in the URL instead.
As another example you could have example.com/tv/ and have the category called "Televisions."

How can I handle these things?
If you want to handle this thing, to obtain my-url, then use the form field clean method to return the valid url. Thats what it is meant for.

Related

How do I write something in fields with scrapy?

Is it possible to srite something in fields with scrapy ?
For example I want to write my username and password in these fields.
I suggest you use the scrapy.http.FormRequest class.
Here's the documentation for it: http://doc.scrapy.org/en/latest/topics/request-response.html#formrequest-objects

How do I make custom URLs using django?

Right now my urls.py file looks like so:
re_path(r'^product-offers/(?P<product_item_id>[-\w]+)$', views.ProductOffersListView.as_view(),
This takes a user to the page: www.shop.com/product/1234
However, is there any way to display the URL with the title (even if that URL doesn't change the dispatching). I want the URL to look like this:
www.shop.com/product/1234/toy-truck
The "toy-truck" part doesn't have to do anything, but it looks professional and would be nice to have.
You can add a slug to your model
Slug is a newspaper term. A slug is a short label for something, containing only letters, numbers, underscores or hyphens. They’re generally used in URLs
https://docs.djangoproject.com/en/2.1/ref/models/fields/#slugfield
Then add it to the url and pass it together with the item id when you call the url
re_path(r'^product-offers/(?P<product_item_id>[0-9]+/(?P<product_item_slug>[\w-]+)/$

Remove whitespaces from a url in Urlpatterns (django)

I'm new to Django and I'm developing a project in which there are profile pages.
Well, the problem is that the primary key has whitespaces but I don't want them to show in the url, neither like "%20%", I want to join the words. For example:
website.com/Example Studios --> website.com/examplestudios
I've tried this:
url ( (r'^(?P<studio_name>[\w ]+)/$').replace(" ", ""), views.StudioView, name = 'dev_profile')
But didn't work (it seems like it turns the raw part to string before reading the url) and with 're' happens the same. I've been searching for solutions but I'm not able to find them (and slugify doesn't convinces me).
What's solution to this or what do you recommend?
In urls you define patterens which Django will catch e.g. r'^test/$' this means that when someone try to get yourdomain.com/test Django will catch it and call the view which will probably render template. You need to solve your problem on url generation e.g. in template . Therefore in urls:
url ( (r'^(?P<studio_name>[\w ]+)/$'), views.StudioView, name = 'dev_profile').
You need to transform primary key to word without space in template. One way is to use slug for every record.
Also add slug field to Studio model which is autogenerated and non-editable field(you can generate it from name e.g. Example Studios->examplestudios).

How to include context variable in a wagtail cms field?

I am looking for a way to render a variable that will be available in the context of the the page where the cms page will be rendered.
Ex:
I have in the context the logged in user and I also have the last transaction he made on the website.
I would like the text in the rich text field in Wagtail to be like this so that the marketing team can tweak the copy.
Hello ||firstname|| thanks for your purchase. ||productname|| will be
shipped to you soon. The expected delivery date is
||expected_delivery_date||
To be less confusing I replace the double brackets by double pipes to show that the templating system does not need to be django templates for those ones. Simple templating is enough maybe using https://docs.python.org/3.4/library/string.html#template-strings
I think I can achieve this by doing:
A stream field that would have blocks of rich text field and a custom block with the possible context variable they can use
A custom render function that would regex and replace the merge tags in the rich text block with the context values
Create a new filter for simple templating. ex: {{ page.body|richtext|simpletemplate }}
Is there any more obvious way or out of the box way to do templating from within a rich text field?
It would be clunky with a separate streamfield block for each inserted context variable. You'd have to override the default rendering which wraps elements in div tags. However I like that it is more foolproof for the editors.
I've done something like the custom rendering before, but with simple TextFields for formatting special offer code messages. Wagtail editors were given the following help_text to illustrate:
valid_placeholders = ['offer_code', 'month_price']
template_text = models.TextField(
_('text'),
help_text="Valid placeholder values are: {all_valid}. Write as {{{example}}}".format(
all_valid=", ".join(valid_placeholders),
example=valid_placeholders[0],
)
)
This rendered as Valid placeholder values are: offer_code, month_price. Write as {{offer_code}}.
Then in the view:
template_keys = [i[1] for i in Formatter().parse(template_text)]
…and continued rendering from there. Remember to validate the field appropriately using the above Formatter().parse() function too.
I used Django's template formatting rather than Python's string.format() because it fails silently, but you could go with string.format() if cleaned adequately.
The custom template filter would feel easiest to me, so I'd start with that approach and switch to a custom render function if I ran into hurdles.
I found an easier way to do this. I wanted my editors to be able to create pages with dynamic customization to the individual user. With this, my editors are actually able to put template variables into any type of content block as {{ var }} which works just like the Django templating language. For my use case, I am allowing my editors to create email content in the CMS, then pulling that to send the emails:
This is the function to call:
def re_render_html_template(email_body, context):
"""
This function takes already rendered HTML anbd re-renders it as a template
this is necessary because variables added via the CMS are not caught by the
first rendering because the first rendering is rendering the containing block,
so instead they are rendered as plaintext in content the first render, e.g., {{ var }}
Example:
input: <p>Hey {{ user_account.first_name }}, welcome!</p>
output: <p>Hey Brett, welcome!</p>
#param email_body: html string
#type email_body: str
#param context: context dictionary
#type context: dict
#return: html string
#rtype: str
"""
from django.template import Context
from django.template import Template
template = Template(email_body)
context = Context(context)
email_body = template.render(context)
return email_body
Then I call it like so:
email_body = render_to_string(template, context)
# need to re-render to substitute tags added via CMS
email_body = re_render_html_template(email_body, context)

Python Django: urls.py questions

Need a little help with my urls.py and other stuff.
How can I replicate this in Django?
1) When user requests a non-existent page it will redirect to one up the directory level. Ex: example.com/somegoodpage/somebadpage should be redirected to example.com/somegoodpage.
2) When user requests page example.com/foo/bar/?name=John it will make url to example.com/foo/bar/name=John
3) When user requests page example.com/foo/bar/John it will change url to example.com/foo/bar/name=John.
Any help is greatly appreciated. Thank You.
For 1), if you don't want to do a separate route for every single route on your website, you'll need middleware that implements process_exception and outputs an HttpResponseRedirect.
For 2 and 3, those are rules that are presumably limited to specific routes, so you can do them without middleware.
2 might be doable in urls.py with a RedirectView, but since the relevant bit is a query string argument, I would probably make that an actual view function that looks at the query string. Putting a ? character in a url regex seems strange because it will interfere with any other use of query strings on that endpoint, among other reasons.
For 3, that's a straightforward RedirectView and you can do it entirely in urls.py.
according to django doc for number 1:
django URL dispatcher runs through each URL pattern, in order, and stops at the first one that matches the requested URL, so add a pattern that matches "somebadpage"s and assign it to a view which redirects the user to "somegoodpage".
for number 2:
the doc says "The URLconf searches against the requested URL, as a normal Python string. This does not include GET or POST parameters, or the domain name."
so i don't think that you can get the "?name=John" in url dispather, so if you describe what you want to do maybe I can help better
and for 3:
to capture bits of the URL and pass them as positional arguments to a view you should use named regular-expression groups, for example :
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', 'news.views.month_archive'),
and the request to /articles/2005/03/ would call the function news.views.month_archive(request, year='2005', month='03'), instead of news.views.month_archive(request, '2005', '03').
hope this helped :)

Categories