How to override the default wagtail page slug - django

I'm trying to make a wagtail pages for the astrologer based on category, country and city.
And my url's are:
https//localhost:8080/<category>
https//localhost:8080/<category>/<country>
https//localhost:8080/<category><country>/<city>
If I am trying to save the url with '/' forward slash then it removing the '/' form the slug and saving it as a string.
Ex: <category><country>/<city> to categorycountrycity
So Is it possible to override the wagtail default page slug type 'SlugField' to 'CharField'.
or is there any other solution ?

URLs are tightly tied to the page tree, and the slug is just the part which identifies the page at that level, rather than any parent levels. So if you want https://localhost:8080/<category>/<country>/<city>, you will need:
A page at https://localhost:8080/<category>/, whose slug is just the name of the category
The above category page to have a child, with the slug of just the country (which will give it the URL https://localhost:8080/<category>/<country>/)
The country page to have a child page, with the slug of just the city name (which will give it the URL https://localhost:8080/<category>/<country>/<city>).
Need other cities, make more child pages under the "country" page. Need more countries, make more child pages under the "category" page. Need more categories, make more child pages under the root page.

Related

Wagtail: Limit choice dynamically based on current object

How can I limit the choices for the districtobject field in wagtail admin?
class DistrictPage(Page):
districtobject = models.ForeignKey(DistrictTranslated, on_delete=models.SET_NULL, null=True, blank=True)
I know that I can use "limit_choices_to" for basic limitations with Q. But I want to use a more dynamic approach which allows me to use the "content" of the current object. (Like self.attribute ... etc)
For example:
def my_limit_function(self):
1. get parent page
2. read date from parent page and extract this information for a filter query
I don't think you can do that in the Page class definition. I think you are going to need to customize the page form as in this example in the documentation. The values can be set in the form __init__.py. Don't forget that there won't be a parent page until your page is saved for the first time.

How to put the page title in a url pattern with Django?

If I wanted to send the blogpost id to the url pattern, and have the url automatically turn into something like www.blog.com/post/2/this-is-my-second-blogpost, how might I do that?
Inside of urls.py I have a url pattern that accepts the blogpost id, and its title. It doesn't seem to be working, and once it does, would be tedious to add the title for every page in this manner.
urls.py:path('post/<int:post_id>/<str:post_title>', views.view_post, name='view_post'),
blogposts.html template:
Read More
views.py: def view_post(request, post_id, post_title):.
Simply, add the default argument of post_title to be None. If you are wishing to get the post_title directly from the post_id, neclect the post_title, doing this won't give you error as functions already got all the satisfied argument values.
So:
def view_post(request, post_id, post_title=None):
Edit
Okay, what user wanted was about slug field. Slug field is the field type in django model. Basically, it is used for the url type. In above problem, what pyknight202 wanted was the url patter for the post_title. So, you could not use tilte directly as url as they contain spaces, so for that you have to add post_title in hyphens or underscore to be readable. Therefore, you need slug field in Post model.
https://helloworld.com/1/this-is-example
So, 1 is post_id as slug could not be unique, so you could not only retrieve from post_title therefore you need post_id too. Refs
Maybe you should use a slug field for the url instead of the combination of id and title, your url will look like example.org/title-to-object-2/.
Now you have a unique slug field with the title and the id.

Wagtail url prefix for a custom Page model

This question is probably trivial, but I am unable to see a simple solution.
I have custom page model representing Post:
class PostPage(Page):
I would like to make all instances of this model (all Posts) accessible only with url prefix
/posts/
Example:
User creates new Post, the assigned slug will be
awesome-first-post
What should happen is, that
/awesome-first-post/
will result in 404, while
/posts/awesome-first-post/
will display the post.
Note: I want this prefix only for the specific model Postpage. Other pages should be served directly from their slug.
In Wagtail, page URLs are formed from the list of slugs of the page's parent and ancestor pages, based on the page's position in the tree - the developer doesn't specify them directly. So, to get the URL /posts/awesome-first-post/, create a page with the slug posts (usually you'd create a dedicated PostIndexPage page model to serve as a listing page), and create the page awesome-first-post as a child of that one (by clicking the '+' icon next to the Posts page in the explorer listing view).
If you want to make sure that users only ever create PostPages as children of the PostIndexPage, use a subpage_types / parent_page_types setting, for example:
class PostPage(Page):
# ...
parent_page_types = ['PostIndexPage']

Wagtail - made custom slug but page not serving from it

I made a custom slug because the default slug does not meet my needs and already set the url_path with the new slug. But the page is still serving with the default slug.
I've already set the url_path with the following code:
def set_url_path(self, parent):
super().set_url_path(self)
if parent:
self.url_path = parent.url_path + self.custom_slug + '/'
return self.url_path
But when I publish the page, it still returns the page with the default slug value. I thought Wagtail serves the page on url_path. What other methods or variables do I have to override for the page to be served on my custom slug?
You can not switch to some other field then slug. The slug field is used all over Wagtail to lookup url's, queries and serve the correct page.
You can programatically set the slug value to something else. The Page.slug definition is:
slug = models.SlugField(
verbose_name=_('slug'),
allow_unicode=True,
max_length=255,
help_text=_("The name of the page as it will appear in URLs e.g
http://example.com/blog/[my-slug]/")
)
The field accepts unicode chars.
You should override Page._get_autogenerated_slug, Page.full_clean and Page.clean. Change how slug is handled and adopt to your wishes.
Note you can use some other field eg my_custom_slug as an input and use this value in your custom methods. Eg: self.my_custom_slug. However, the final result has to be stored in the slug field.
You can remove the slug field from the content panels to remove it from the admin user interface.
Finally, the slug has to comply with https://www.rfc-editor.org/rfc/rfc1738

django - dynamic query on form field

Lets say I have a form with some fields. I was wondering if it is possible to do dynamic query where I could do a string match while the user is typing into a field. Like when typing into google it returns a list of choices when you type into the search bar. Can someone give me an example on how and where to implement it?
If what you're looking to achieve is fields for a ForeignKey then you can provide a Queryset on the form field then use an app like django_select2 which can then provide a widget which will allow a user to search for items in the Queryset for the field. e.g.
city = forms.ModelChoiceField(
queryset=City.objects.all(),
label=u"City",
widget=ModelSelect2Widget(
model=City,
search_fields=['name__icontains'],
dependent_fields={'country': 'country'},
max_results=500,
)
)
Then in the form, as you started to type into the city field it'd start to search on City.name using an icontains lookup. The docs for this are here.
If that's not what you're looking for then you could just write some Javascript which detected input to a field, then sent an ajax request to a view with the contents of your field. That could then return a response which displayed content in the page related to the input.