Parametrizing a Date on urls.py in Django - python

I have the following URL definition:
url(r'^date-add/(?P<entity_id>\d+)$', views.date_add, name='date_add'),
That allows me to call date_add function with the following URL:
/app_name/date-add/<id>
I would like to fix this to allow a date. For example:
/app_name/date-add/1/2013-04-23
How should I edit my urls.py definition in order to achieve this?

You can define your URL regex like this:
url(r'^date-add/(?P<entity_id>\d+)/(?P<date>\d{4}-\d{2}-\d{2})/$', views.date_add, name='date_add'),
and the view, obviously would be
def date_add(request, entity_id, date):
#convert to datetime object from string here.

Typically you break it down into named parameters corresponding to the year, month and date:
url(r'^date-add/(?P<entity_id>\d+)/(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})/$', views.date_add, name='date_add_with_param'),
Then you can use datetime.date to construct the datetime in your view, which should receive year, month and day as parameters.
This is the usual pattern in particular for archive views, where the URLs might get more specific as you drill down - /archive/2013/ and /archive/2013/11/ might both be valid, although of course you probably wouldn't have a single regexp matching either. It might be unnecessarily complex compared to the single named pattern regexp karthikr's answer shows, which you could then parse with datetime.strptime.
In either case you can also use somewhat more restrictive regexps if you like, like ones that don't allow a first digit other than 0, 1, 2 or 3 for the month.

Related

Check if string is in certain format in Python

I have string as below.
/customer/v1/123456789/account/
The id in the url is dynamic.
What I want to check is if I have that string how can I be sure that if first part and second part is matching with below structure. /customer/v1/<customer_id>/account
What I have done so far is this. however, I want to check if endpoints is totally matching to the structure or not.
endpoint_structure = '/customer/v1/'
endpoint = '/customer/v1/123456789/account/'
if endpoint_structure in endpoint:
return True
return False
Endpoint structure might change as well.
For example: /customer/v1/<customer_id>/documents/<document_id>/ and there will be again given endpoint and I need to check if given endpoint fits with the structure.
You can use a regular expression;
import re
return re.match(r'^/customer/v1/\d+/account/$', endpoint)
or you can examine the beginning and the end:
return endpoint.startswith('/customer/v1/') and endpoint.endswith('/account/')
... though this doesn't attempt to verify that the stuff between the beginning and the end is numeric.
Can solve this using regular expression
^(/customer/v1/)(\d)+(/account/)$
Also if you want to specify the minimum length for customer_id
(/customer/v1/<customer_id>/account ) then use the following regexp
^(/customer/v1/)(\d){5,}(/account/)$
Here expecting the customer_id must have at least 5 digits length
Check here

Best practices to filter in Django

In one of the pages of my Django app I have a page that simply displays all employees information in a table:
Like so:
First Name: Last Name: Age: Hire Date:
Bob Johnson 21 03/19/2011
Fred Jackson 50 12/01/1999
Now, I prompt the user for 2 dates and I want to know if an employee was hired between those 2 dates.
For HTTP GET I just render the page and for HTTP POST I'm sending a URL with the variables in the URL.
my urls.py file has these patterns:
('^employees/employees_by_date/$','project.reports.filter_by_date'),
('^employees/employees_by_date/sort/(?P<begin_date>\d+)/(? P<end_date>\d+)/$', EmployeesByDate.as_view()),
And my filter_by_date function looks like this:
def filter_by_date(request):
if request.method == 'GET':
return render(request,"../templates/reports/employees_by_date.html",{'form':BasicPrompt(),})
else:
form = BasicPrompt(request.POST)
if form.is_valid():
begin_date = form.cleaned_data['begin_date']
end_date = form.cleaned_data['end_date']
return HttpResponseRedirect('../reports/employees_by_date/sort/'+str(begin_date)+'/'+str(end_date)+'/')
The code works fine, the problem is I'm new to web dev and this doesn't feel like I'm accomplishing this in the right way. I want to use best practices so can anyone either confirm I am or guide me in the proper way to filter by dates?
Thanks!
You're right, it's a bit awkward to query your API in that way. If you need to add the employee name and something else to the filter, you will end up with a very long URL and it won't be flexible.
Your filter parameters (start and end date) should be added as a query in the url and not be part of path.
In this case, the url would be employees/employees_by_date/?start_date=xxx&end_date=yyy and the dates can be retrieved in the view using start_date = request.GET['start_date].
If a form is used with method='get', the input in the form are automatically converted to a query and appended at the end of the url.
If no form is used, parameters need to be encoded with a function to be able to pass values with special characters like \/ $%.
Use Unix timestamps instead of mm/dd/yyyy dates. A unix timestamp is the number of seconds that have elapsed from Jan 1 1970. ("The Epoch".) So it's just a simple integer number. As I'm writing this, the Unix time is 1432071354.
They aren't very human-readable, but Unix timestamps are unambiguous, concise, and can be filtered for with the simple regex [\d]+.
You'll see lots of APIs around the web use them, for example Facebook. Scroll down to "time based pagination", those numbers are Unix timestamps.
The problem with mm/dd/yyyy dates is ambiguity. Is it mm/dd/yyyy (US)? or dd/mm/yyyy (elsewhere)? What about mm-dd-yyyy?

Finer control over Django timeuntil output possible?

I'm currently using the timeuntil tag to show an items expiration date. It's currently spitting out...
{{rental_till|timeuntill}}
Which produces...
3 months, 1 week
Is it possible to get it to just show, the months, for example? Or any type of finer control over the output format, similar to the date tags.
To only show months, you could write a simple template filter that splits the string on the comma, and returns the first item of the resulting list. The filter code would look like this:
from django.template import Library
register = Library()
#register.filter
def split_timeuntil(duration):
return duration.split(",")[0]
Then in your template: {{rental_till|timeuntil|split_timeuntil}}
However, the timeuntil filter does not have the kind of formatting date has. You can easily create a custom filter that returns the format you want by copying the timeutil code in django/template/defaultfilters.py and django/utils/timesince.py.
No, timeuntil doesn't have any options, but you can simply create your own templatetag based on timeuntil and make it do whatever you like. See: https://code.djangoproject.com/browser/django/tags/releases/1.3/django/template/defaultfilters.py (line 729)

django autoconverting datetime property

my datetime property is saving in mysql in this format 2011-03-17 00:00:00 but after fetchind the data with filter function it is giving March 17,2011 midnight but i have not say to do any this type of task. My question is how can i insist django to stic to show same value what is saved in MYSQL.
you'll want to use the datetime format, django's DateTimeField[1] really is a wrapper for datetime.datetime.
in the templates you can use the date[2] filter to apply the format you want for example:
{{ item.date|date:"Y-m-d H:i:s" }}
This should print out 2011-03-17 00:00:00 in the template. In views use datetimes.strftime[3]
[1] http://docs.djangoproject.com/en/dev/ref/models/fields/#datetimefield
[2] http://docs.djangoproject.com/en/1.2/ref/templates/builtins/#date
[3] http://docs.python.org/library/datetime.html#strftime-and-strptime-behavior
I have a feeling your database schema knows this is a date, right? In that case it's not being stored in the format you describe, but as some representation such as seconds since the era.
This means that when you retreave it your code has to do something with it to make it look right. If you don't tell it how to look it'll default to the format you see, but if you use strftime in your python code and a filter in your templates you can make it look however you like, including the original format how you saw it.
Of course the easy way out is to store it in the db as text...

Django: Arbitrary number of unnamed urls.py parameters

I have a Django model with a large number of fields and 20000+ table rows. To facilitate human readable URLs and the ability to break down the large list into arbitrary sublists, I would like to have a URL that looks like this:
/browse/<name1>/<value1>/<name2>/<value2>/ .... etc ....
where 'name' maps to a model attribute and 'value' is the search criteria for that attribute. Each "name" will be treated like a category to return subsets of the model instances where the categories match.
Now, this could be handled with GET parameters, but I prefer more readable URLs for both the user's sake and the search engines. These URLs subsets will be embedded on each page that displays this model, so it seems worth the effort to make pretty URLs.
Ideally each name/value pair will be passed to the view function as a parameter named name1, name2, etc. However, I don't believe it's possible to defined named patterns via a regex's matched text. Am I wrong there?
So, it seems I need to do something like this:
urlpatterns = patterns('',
url(r'^browse/(?:([\w]+)/([\w]+)/)+$', 'app.views.view', name="model_browse"),
)
It seems this should match any sets of two name/value pairs. While it matches it successfully, it only passes the last name/value pair as parameters to the view function. My guess is that each match is overwriting the previous match. Under the guess that the containing (?:...)+ is causing it, I tried a simple repeating pattern instead:
urlpatterns = patterns('',
url(r'^browse/([\w]+/)+$', 'app.views.view', name="model_browse"),
)
... and got the same problem, but this time *args only includes the last matched pattern.
Is this a limitation of Django's url dispatcher, and/or Python's regex support? It seems either of these methods should work. Is there a way to achieve this without hardcoding each possible model attribute in the URL as an optional (.*) pattern?
A possibility that you might consider is matching the entire string of possible values within the url pattern portion and pull out the specific pieces within your view. As an example:
urlpatterns = patterns('',
url(r'^browse/(?P<match>.+)/$', 'app.views.view', name='model_browse'),
)
def view(request, match):
pieces = match.split('/')
# even indexed pieces are the names, odd are values
...
No promises about the regexp I used, but I think you understand what I mean.
(Edited to try and fix the regexp.)
I agree with Adam, but I think the pattern in urls.py should be:
... r'^browse/(?P<match>.+)/$' ...
The '\w' will only match 'word' characters, but the '.' will match anything.
I've an alternative solution, which isn't quite different from the previous but it's more refined:
url(r'^my_app/(((list\/)((\w{1,})\/(\w{1,})\/(\w{1,3})\/){1,10})+)$'
I've used unnamed url parameters and a repetitive regexp. Not to get the "is not a valid regular expression: multiple repeat" i place a word at the beginning of the list.
I'm still working at the view receiving the list. But i think ill' go through the args or kwargs.. Cannot still say it exactly.
My 2 cents
Same answer came to me while reading the question.
I believe model_browse view is the best way to sort the query parameters and use it as a generic router.
I think the answer of Adam is more generic than my solution, but if you like to use a fixed number of arguments in the url, you could also do something like this:
The following example shows how to get all sales of a day for a location by entering the name of the store and the year, month and day.
urls.py:
urlpatterns = patterns('',
url(r'^baseurl/location/(?P<store>.+)/sales/(?P<year>[0-9][0-9][0-9][0-9])-(?P<month>[0-9][0-9])-(?P<day>[0-9][0-9])/$', views.DailySalesAtLocationListAPIView.as_view(), name='daily-sales-at-location'),
)
Alternativly, you could also use the id of the store by changing (?P<store>.+) to (?P<store>[0-9]+). Note that location and sales are no keywords, they just improve readability of the url.
views.py
class DailySalesAtLocationListAPIView(generics.ListAPIView):
def get(self, request, store, year, month, day):
# here you can start using the values from the url
print store
print year
print month
print date
# now start filtering your model
Hope it helps anybody!
Best regards,
Michael

Categories

Resources