DateField's DateInput widget with 'format="%B"' is not localized/translated - python

I have an UpdateView and when I visit the edit page, my date field renders the month as non-localized.
In my Form I'm using format("%B %Y") to have the full month + year representation, like so:
class CampaignForm(ModelForm):
date = DateField(widget=DateInput(attrs={"autocomplete": "off"}, format="%B %Y"))
I'm using the form in a basic UpdateView setup, and I render the template...
<div class="form-row">
<div class="form-group flatpickrdatetimeinput col-md-6 mb-0">
{{ form.date|as_crispy_field }}
</div>
</div>
The date representation works in terms of month + year, but I need to localize the month name to the local language.
I cannot find the error, I tried changing the field attribute (localize=True) and also I have played around with the settings (i18n, l10n, etc) with no success.
In fact, the settings have worked out so far. In the same template I am using the 'date' template filter and it translates the month just fine
<h2>{{campaign.date | date:'F Y' }}</h2>
How to make use of the internal django localization inside a form/form-field?

While writing the question, I had the idea to try to set the initial data and localize it there.
It indeed worked but it's a workaround and I still think it should work directly from the form.
If you have a solution please feel free to add it. Or leave a comment if you have experienced the issue and you think this is a bug.
from django.utils import formats
class CampaignUpdateView(CampaignMixin, UpdateView):
def get_initial(self):
initial = super().get_initial()
initial.update({"date": formats.date_format(self.object.date, format="F Y", use_l10n=True)})
return initial

Related

Django: I want to track from which url a request was made? [duplicate]

I have a Post model that requires a certain category before being added to the database, and I want the category to be generated automatically. Clicking the addPost button takes you to a different page and so the category will be determined by taking a part of the previous page URL.
Is there a way to get the previous page URL as a string?
I have added my AddPost button here.
<aside class="addPost">
<article>
<form action="/Forum/addPost">
<input type="submit" name="submit" value="Add Post"/>
</form>
</article>
</aside>
You can do that by using request.META['HTTP_REFERER'], but it will exist if only your tab previous page was from your website, else there will be no HTTP_REFERER in META dict. So be careful and make sure that you are using .get() notation instead.
# Returns None if user came from another website
request.META.get('HTTP_REFERER')
Note: I gave this answer when Django 1.10 was an actual release. I'm not working with Django anymore, so I can't tell if this applies to Django 2
You can get the referring URL by using request.META.HTTP_REFERER
More info here: https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META
I can't answer #tryingtolearn comment, but for future people, you can use request.META['HTTP_REFERER']
Instead of adding it to your context, then passing it to the template, you can place it in your template directly with:
Return
A much more reliable method would be to explicitly pass the category in the URL of the Add Post button.
You can get the previous url in "views.py" as shown below:
# "views.py"
from django.shortcuts import render
def test(request):
pre_url = request.META.get('HTTP_REFERER') # Here
return render(request, 'test/index.html')
You can also get the previous url in Django Template as shown below:
# "index.html"
{{ request.META.HTTP_REFERER }}

WTForms DateField returning None

I have a DateField that is part of a WTForm in Flask
from wtforms.fields.html5 import DateField
dob = DateField('Date of Birth', [InputRequired()], format='%m-%d-%Y')
if form.is_submitted():
print(form.dob.data)
HTML Template
{{ form.dob.label }}
<input type="date" id="DateofBirth" name="dob" class="form-control">
When the form is submitted it returns None. All other fields of the form work properly. Any suggestions?
Solved it after a bit. Figured out I needed to remove the format parameter in the DateField object. The corrected field looks like this:
dob = DateField([InputRequired()])
When submitted the form.dob.data now outputs the correct date. This answer on another semi-unrelated question helped me out: https://stackoverflow.com/a/9519493/16549743. I guess HTML5 can't accept different formats as explained in that answer and passing the format parameter was messing things up.

Generic way to filter django query set by multiple fields (e.g. date)?

I'm trying to create a generic date class based view for the blog I'm creating, but it does not seem to work. This is what I've got (regex inspired by this gist):
"""Creativeflow URL Configuration the blog app."""
from django.conf.urls import url
from .views import BlogListView, BlogDetailView
urlpatterns = [
url(r'posts/(?P<year>\d{4})/(?P<months>\d{2}|\w{3})/(?P<day>\d{2})/(?P<slug>\w+)',
BlogDetailView.as_view(), name="blog-detail"),
url(r'posts(?:/(?P<year>\d{4}))(?:/(?P<months>\d{2}|\w{3}))?(?:/(?P<day>\d{2}))?',
BlogListView.as_view(paginate_by=25), name="blog-list"),
]
And my views:
class BlogListView(ListView):
"""CBV for list of blog posts."""
model = Post
context_object_name = "blog_objects"
def get_query_set(self):
"""Get the posts in the specified date range.
Year defaults to todays year
Month defaults to last month of the year
Day defaults to last day of the month
"""
now = datetime.now()
year = self.kwargs.get('year', now.year)
month = self.kwargs.get('month', 12)
day = self.kwargs.get('day', calendar.monthrange(year, month)[1])
date = datetime.date(year=year,
month=month,
day=day)
print(date)
print('hello')
return Post.objects.filter(published__lt=date)
Going to http://blog.creativeflow.org.uk/posts/2016/07/09 doesn't provide any data up to the template, post_list.html:
{% extends "base.html" %}
{% block content %}
<main>
{% for blog in blog_objects %}
<div>
<h3>{{ blog.title }}</h3>
</div>
{% endfor %}
</main>
{% endblock content %}
(I can provide the base as well if people want)
My intention is that accessing posts/2016 gets all of 2016s posts (because it defaults to the end of 2016, i.e. 2016/12/31), posts/2016/02 gets all of the posts from February 2016 (defaults to the end of Feb 2016, i.e. 2016/02/29) etc. But running resolve('/posts/2016/07/09') produces an error because I'm on a subdomain, and using django-subdomain's from subdomains.utils import reverse works...
>>> reverse('blog-list', subdomain="blog", kwargs={"year":"2016", "months":"02", "day":"13"})
'http://blog.creativeflow.org.uk/posts/2016/02/13'
but my attempt in the browser don't return anything. I'm also not getting anything printed in the terminal when I refresh the page, despite my two print statements.
I feel like there is something drastic that I'm missing that's obvious, but I'm struggling to connect the dots.
How can I make this route work?
This works, my two main issues were
Not having blogs in the DB
As Alasdair said:
You are using the keyword months in your url pattern but month when you try to reverse.
I believe that's all it took to resolve this.

How to get the previous URL from a POST in Django

I have a Post model that requires a certain category before being added to the database, and I want the category to be generated automatically. Clicking the addPost button takes you to a different page and so the category will be determined by taking a part of the previous page URL.
Is there a way to get the previous page URL as a string?
I have added my AddPost button here.
<aside class="addPost">
<article>
<form action="/Forum/addPost">
<input type="submit" name="submit" value="Add Post"/>
</form>
</article>
</aside>
You can do that by using request.META['HTTP_REFERER'], but it will exist if only your tab previous page was from your website, else there will be no HTTP_REFERER in META dict. So be careful and make sure that you are using .get() notation instead.
# Returns None if user came from another website
request.META.get('HTTP_REFERER')
Note: I gave this answer when Django 1.10 was an actual release. I'm not working with Django anymore, so I can't tell if this applies to Django 2
You can get the referring URL by using request.META.HTTP_REFERER
More info here: https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META
I can't answer #tryingtolearn comment, but for future people, you can use request.META['HTTP_REFERER']
Instead of adding it to your context, then passing it to the template, you can place it in your template directly with:
Return
A much more reliable method would be to explicitly pass the category in the URL of the Add Post button.
You can get the previous url in "views.py" as shown below:
# "views.py"
from django.shortcuts import render
def test(request):
pre_url = request.META.get('HTTP_REFERER') # Here
return render(request, 'test/index.html')
You can also get the previous url in Django Template as shown below:
# "index.html"
{{ request.META.HTTP_REFERER }}

Django forms question

I don't have an example because I'm not working on anything relevant right now, but am still curious, after reading the docs about formsets:
What is a best practice for having a single view with multiple different model forms that post at the same time (rather 1 combined form, since you can't post multiple forms at the same time, but for lack of a better explanation...), some being single model forms, and others being 1-or-more formsets (e.g. Person, his 1 Address, and his 1 or more Pet objects), like Django does with TabularInline. Inlines have been in Django for some times, so my suspicion is that there are better practices than what I may find by simply copy/pasting what's in admin/options.py, no?
Thanks in advance
You should:
Make sure you're using transactions (so, make sure they're turned on, and that you're using something other than MySQL with MyISAM tables). This is true all the time, really, but it's even more true now. :)
Use multiple forms.Form/forms.ModelForm objects, which are grouped together in a single HTML <form> element, such as...
Python:
from django import forms
class FormA(forms.ModelForm):
[...]
class FormB(forms.ModelForm):
[...]
HTML:
<form method="post" action="/path/to/view/">
{% csrf_token %}
{{ form_a }}
{{ form_b }}
<input type="submit" value="Submit Form" />
</form>
Then, when you're processing your forms, simply process them both and make sure that you're requiring both to be valid to actually complete the view in a success case.
from django.db import transaction
from django.http import HttpResponseRedirect
from django.template.response import TemplateResponse
from myapp.forms import FormA, FormB
#transaction.commit_on_success
def present_forms_to_user(request):
if request.method == 'POST':
form_a = FormA(request.POST)
form_b = FormB(request.POST)
if form_a.is_valid() and form_b.is_valid():
# processing code
return HttpResponseRedirect('/path/to/thank/you/page/')
else:
form_a = FormA()
form_b = FormB()
return TemplateResponse(request, 'templates/eggs.html', {
'form_a': form_a,
'form_b': form_b,
})
As a disclaimer, remember that this is a basic example stub, and not meant to be copied blindly. Your ultimate use case for this may be slightly different, and that's fine.

Categories