In this tutorial we are going to use django slug field in our url instead of id. Therefore we will implement this in such a way that we will be able to auto populate slug when ever we are typing anything in the title.
Slug isa process by which a valid url is generated for an already obtained data .For example, using the title of an article to generate a URL.
Slug is also a unique part of a URL whichidentifies a particular page on a website readable by any user.
Example of django slug.
how-to-create-slug-in-django.
Slug doesn’t contain spaces therefore a hiphen or dash is use in spacing. remember if there is no slug our url could have been loke thishow%20to%20use%20slug%20in%20django
In this tutorial our aim would be how to populate slug outside django admin. What I actually mean is that django would be able to use what ever you type in the title as your slug. For example if you are running a public web where every body can post , is either you provide a default one, recall that is not every body would understand what slug is all about. best option for this is to hide the slug field and populate it automatically.
Steps in using django slug field in django and populating it outside django admin
- Create a django project
- Create a model and include slug field with instance.
- Create a view for detail and list view
- Map a url to the views in views.py
- Create a template for detail and list view
- Create a post in form.py for publishing outside django admin
ILLUSTRATION OF HOW TO POPULATING SLUG OUTSIDE DJANGO ADMIN
In this tutorial I assumed that you already know how to create a django project so without wasting much time lets start by creating a model in models.py
We are going to create our model, go to your model.py and include the code below
#models.py
<strong>from</strong> django.db <strong>import</strong> models
<strong>from</strong> datetime <strong>import</strong> datetime
<strong>from</strong> django.urls <strong>import</strong> reverse
<strong>from</strong> django.utils.text <strong>import</strong> slugify
<strong>class</strong> <strong>Article</strong>(models.Model):
title = models.TextField(null=True,blank=False)
content = models.TextField(blank=False)
date_added = models.DateTimeField(default=datetime.now,blank=True)
slug = models.SlugField(max_length=100,blank=True)
<strong>def</strong> <strong>__str__</strong>(self):
<strong>return</strong> self.title
<strong>def</strong> <strong>get_absolute_url</strong>(self):
<strong>return</strong> reverse ("article_detail",kwargs={'slug':self.slug})
<strong>def</strong> <strong>save</strong>(self, *args, **kwargs): # new
<strong>if</strong> <strong>not</strong> self.slug:
self.slug = slugify(self.title)
<strong>return</strong> super().save(*args, **kwargs)
In the model abovebenchatronics/myapp/models.py
we have created a model and named it Article and added a slug field and use the get absolute url in the instances we also use kwargs and super to override the slug instances.
Now run migrations and migrated so that our intances table would be created.
./manage.py makemigrations
./manage.py migrate
Step2 Go tobenchatronics/myapp/admin.py
then register the models like my own below
You can import a specific model but I like random import so that my code would be simple and dmall
<strong>from</strong> django.contrib <strong>import</strong> admin
<strong>from</strong> . models <strong>import</strong> *
<strong>class</strong> <strong>ArticleAdmin</strong>(admin.ModelAdmin):
list_display = ('title','date_added',)
prepopulated_fields = {"slug": ("title","date_added")}
With this prepopulate field whenever you type in your admin the title could be refilling the django slug field as you are typing in the title.
The good thing there is that we can use different name for the title and slug
Now we have to create a view function in our views.py e.g benchatronics/myapp/views.py. Create a view function like the one below
<strong>from</strong> . models <strong>import</strong> *
<strong>from</strong> django.http <strong>import</strong> HttpResponse
<strong>def</strong> <strong>ArticleView</strong>(request):
article_list = Article.objects.all()
context = {'article_list':article_list}
<strong>return</strong> render(request,'article_list.html', context)
Create a url that maps the view in myapp/urls.py
<strong>from</strong> django.urls <strong>import</strong> path
<strong>from</strong> . <strong>import</strong> views
urlpatterns = [
path('blog/',views.ArticleView, name='article_list'),
]
We have to create article_list.html where we can acess our article_list therefore i assumed you know how to configure template. create a template in benchatronics/templates/article_list.html as in my own
This is article_list home
{% for article in article_list %}
{{article.title}}
{{article.content}}
{% endfor %}
We also need to create a detail view for our Article. Now add the code below in your urls.py that means in apps.
urlpatterns = [
path('/<slug:slug>',views.Article_View,name='article_detail'),
]
after this add this code below in your views.py for mapping the url you have just created above. This views is for Detail_View
# detail view
def Detail_View(request,slug):
article_detail = Article.objects.filter(slug=slug)
if article_detail.exists():
article_detail = article_detail.first()
else:
return HttpResponse("<<strong>h3</strong>>Page Not Found otherwise contact us</<strong>h3</strong>>")
context = {'article_detail':article_detail}
return render(request,'article_detail.html', context)
Now we are ready to check our instances in admin. head over to your admin then start to create an Article you will see that as you type in the title it will be populating in the slug. but i have just created all these because i want to show you guys this in outside admin.
Now create a python file in myapp, name it form.py then add this code below
benchatronics/myapp/form.py
from .models <strong>import</strong> *
from django <strong>import</strong> forms
from django.contrib.auth.models <strong>import</strong> User
<strong>class</strong> <strong>ArticleForm</strong>(forms.ModelForm):
<strong>class</strong> <strong>Meta</strong>:
model = Article
fields = ('title','content','date_added',)
widgets = {
'title': forms.TextInput(attrs={'class':'form-control'}),
'content': forms.TextInput(attrs={'class':'form-control'}),
'date_added': forms.TextInput(attrs={'class':'form-control'}),
'slug': forms.TextInput(attrs={'class':'form-control'}),
}
Django Gmail – How To Send Email In Django
After creating form.py we will need to create a view function then map the required url for posting outside django admin
go to views.py and add these codes below.
<strong>from</strong> . forms <strong>import</strong> *
<strong>from</strong> . models <strong>import</strong> *
<strong>from</strong> django.http <strong>import</strong> HttpResponse
<strong>from</strong> django.shortcuts <strong>import</strong> render,get_object_or_404
#health post
<strong>def</strong> <strong>Post_View</strong>(request):
# dictionary for initial data with
# field names as keys
context ={}
# pass the object as instance in form
form= PostForm(request.POST <strong>or</strong> None)
# save the data from the form and
# redirect to detail_view
<strong>if</strong> form.is_valid():
form.save()
<strong>return</strong> redirect('index')
# add form dictionary to context
context= {'form':form}
<strong>return</strong> render(request, "add_article.html", context)
go to myapp/urls.py and map the url accordingly
<strong>from</strong> django.urls <strong>import</strong> path
<strong>from</strong> . <strong>import</strong> views
urlpatterns = [
path('add_article',view.Post_View,name="add_article"),
]
Then we have to create an add_article.html so that we can be able to access the page.
go to templates then create html file
templates/add_article.html
<form method="post">
<div <strong>class</strong>="m-2 container ">
{% csrf_token %}
{{form.as_p}}
<button <strong>class</strong>="btn btn-primary" type="submit" >Post</button>
</div>
</form>
Then save it and refresh server by running /manage.py runserver. you can access the add_article at localhost:8000/add_article or you can add it to your homepage navbar as in<a href="{% url 'add_article' %}>Add post</a>
Your slug is now automatically populated, I have set slug to blank= True because we won't be typing slug all the time except you want to type it your self.
Another way to do this If you want users to post on your site then slug must be prepolated, you can set title to recieve a max_length of 100 and slug a max_length of 100 too then edit your add_article forms.py to be like this.
<strong>from</strong> .models <strong>import</strong> *
<strong>from</strong> django <strong>import</strong> forms
<strong>from</strong> django.contrib.auth.models <strong>import</strong> User
<strong>class</strong> <strong>ArticleForm</strong>(forms.ModelForm):
<strong>class</strong> <strong>Meta</strong>:
model = Article
fields = ('title','content','date_added',)
widgets = {
'title': forms.TextInput(attrs={'class':'form-control'}),
'content': forms.TextInput(attrs={'class':'form-control'}),
'date_added': forms.TextInput(attrs={'class':'form-control'}),
'slug': forms.TextInput(attrs={'class':'form-control','type':'hidden',}),
}