# URL designing and  URL kwargs in Django

A clean URL is really important for a good quality web application. You can design your own URL style `i.e url can contain / or - anything` there is no any restriction but these are the things i follow (some examples),

1. `/profile/<username>/` instead of `/profile/<db_primary_key_id>/` to view user profile
2. `/hello-world/` instead of `/helloworld/`
3. `/accounts/change-password/` instead of `/profile/<username>/account/settings/change-password/` for accounts password change
4. `/blogs/?page=1` instead of `/blogs/page-1/` for paginations.

> You can follow any pattern, but make it readable and consistent in your project

### Creating a URL on Django

To create a URL on Django you simple create a path and point that path to a view function like we did in previous turorials.
Here are some examples,

```py
from django.urls import path

from profile.views import profile_view
from accounts.views import change_password_view

urlpatterns = [
    path('/profile/', profile_view),
    path('/accounts/change-password/',change_password_view)
]
```

As you can see we use `path()` function to create our URLs. The path function take arguments where we define the path of url and the view function that it points.

### Capturing Values from URL

Let's assume a URL path `/profile/<username>/` here `<username>` part is dynamic and we need to capture this value on our URL and pass it to the view function.
For this purpose we use `Path Converters`. Django already provides us some path converters in default, they are: `str` `int` `slug` `uuid` `path`. A/c to the type we need, we can select a path converter and add it to the URL like below,

```py
# urls.py
from django.urls import path

from profile.views import user_profile_detail_view

urlpatterns = [
    path('/profile/<str:username>/', user_profile_detail_view) # we used <str> path converter and assigned the value to username
]
```

since we need to grab the captured `username` on our view function as well, we can write our view function as, 
```py
# profile/views.py

def user_profile_detail_view(request, username):  # we added username argument on our view function
    # print(type(username)) # do this for every path converters to see tha magic. i.e: using <int> converter would give you <int> type
    # get this username info from DB
    # prepare output
    # send output as HttpResponse
    ....
```

> We can always create our own custom path converters if the default converters do not satisfy our need. 


### Using regular expressions in URLs

Sometime we may need to use regular expression in our URL since everytime the simple `path()` wont satisfy our need.
To create regular expression on url path use `re_path()` instead of `path()`

```py
from django.urls import path, re_path

from blog.views import all_blogs_for_year_view

urlpatterns = [
    re_path(r'^blogs/(?P<year>[0-9]{4})/$', all_blogs_for_year_view),
]
```

### How does URLconf work

Django consist of `ROOT_URLCONF` settings on your projects `settings.py` file. This is the one and only URL config file your django will look for. All urls in our project must be inside the defined `ROOT_URLCONF` file. You might come up with a question, There can be as many django apps in the project and they cna have their own urls, but if django can only look into the `ROOT_URLCONF` file, then how does our logic fit up. The answer is, you can have `n` numbers of URL files in your project, but through some way you need to integrate those urls on your `ROOT_URLCONF` file.

> If incoming Request Object has `urlconf` attribute set (this can be from middlewares), then django will use this instead of `ROOT_URLCONF`, but dont worry about it for now.

Remember these things, 
1. in request `http://127.0.0.1:8000/profile/`, Django will look only `/profile/` in your URL configurations file
2. In request `http://127.0.0.1:8000/profile/?id=123`, Django will only `/profile/` in your URL configrations file
3. It doesn't look at the request method as well, All request methods. like `HEAD` `POST` `GET` will land to the same view function. You can from some way find the request method on your view function and perform the logic accordingly. i.e: `post method` on `/profile/` will update your profile but `get` on `/profile/` will display your profile information. We will look into this in later tutorials


### Including other URLconfs

As our project grows up, we split our `url` files or group them for readability.   


```py
from django.urls import include, path
from profile.views import self_profile_view

extra_extra_url_patterns = [
    path("/me/",self_profile_view)
]

urlpatterns = [ # this is our main urlpattern list
    
    path("/profile/",include(extra_extra_url_patterns)) # include the patterns
    
    # this will create url ==> /profile/ + /me/ from extra_extra_url_patterns = /profile/me/ is the final URL created
    
    # and you can also include, other urls.py file from your app 
    path("world/",include('world.urls')) 
    # you do not need to import world.urls as you can simply write the dotted path of your url file
    # so, this means, inside your world app, there will be  urls.py file : world/urls.py
]

```



