📜 ⬆️ ⬇️

Several useful Django fields

I work as a full-time programmer at the St. Petersburg State University of Economics and my task recently is to support the activities of the department of photo-video production (beginning university television). As soon as the head of the department asked everyone to register with Bitrix24 in order to automate reports, I thought about automating incoming tasks (in fact, everything was a little deeper and the goal was discipline, but not the post).

Actually, the first thing I took was the application form for a photo-video shoot, which, without thinking twice, sketched in Django. At this point, my knowledge of the framework was limited to several views for listing lists on the internal server of the department. Suddenly fields became the main difficulty in the form - at the same time I wanted to bring beauty away and prevent user input errors from entering. I was particularly interested in two fields - the phone entry field and the timing. About them and speech.

I'll start with the phone entry field. At first I turned to Habra and found a certain post , but what I saw seemed too cumbersome for my purpose (after all, I just had to give the phone to the operator). I realized that using CharField would not lead to any of my goals and, after reading the documentation of Django, I found MultiValueField and MultiWidget there (I just want to say that using only MultiValueField generates the usual text line, which does not make any sense) . A few minutes later the code was written under the cut.
')

1) For a start, import the necessary.
from django.forms import MultiValueField, CharField, ChoiceField, MultiWidget, TextInput, Select 


2) Then we define PhoneWidget, the base class for which is MultiWidget.
 class PhoneWidget(MultiWidget): def __init__(self, code_length=3, num_length=7, attrs=None): widgets = [TextInput(attrs={'size': code_length, 'maxlength': code_length}), TextInput(attrs={'size': num_length, 'maxlength': num_length})] super(PhoneWidget, self).__init__(widgets, attrs) def decompress(self, value): if value: return [value.code, value.number] else: return ['', ''] 

A bit of explanation:
The length of the city code in St. Petersburg and mobile all Russia is 3 characters, and the phone number itself is 7. But both parameters can vary, so they were indicated in the constructor with default values ​​suitable for me.
Next comes the definition of 2x widgets themselves (I think you can call them field representations for understanding) with restrictions on the length of the input field (for beauty) and the number of characters (for error protection) by the code_length (code length) and num_length (number length) parameters.

For the sake of beauty fenshui , I added another method format_output ()
 def format_output(self, rendered_widgets): return '+7' + '(' + rendered_widgets[0] + ') - ' + rendered_widgets[1] 

in order to get the output beautiful formatting in html.

3) We define the field itself as the base class for which will be MultiValueField.
 class PhoneField(MultiValueField): def __init__(self, code_length, num_length, *args, **kwargs): list_fields = [CharField(), CharField()] super(PhoneField, self).__init__(list_fields, widget=PhoneWidget(code_length, num_length), *args, **kwargs) def compress(self, values): return '+7' + values[0] + values[1] #,      

A bit of explanation:
The constructor contains the same parameters to pass to the widget's constructor. Otherwise, as I already wrote, we get the usual string for entering text.

4) In the end, in the form we specify the field
 p_num = PhoneField() # \    : PhoneField(code_length=some_value, num_length=some_value) 

and adding to the template
 {{ form.p_num.errors }} <label for="phone_num"> :</label> </br> {{ form.p_num }} 

we get two beautiful fields of length 3 and 7 (or how many are indicated) characters and an international code in front for its standardization and a hint to the user.

By analogy, a widget and a time entry field were made:
 class TimeWidget(MultiWidget): def __init__(self, h_choices, m_choices, attrs=None): widgets = [Select(choices=h_choices), Select(choices=m_choices)] super(TimeWidget, self).__init__(widgets, attrs) def decompress(self, value): if value: return [value.hours, value.minutes] else: return ['', ''] class TimeField(MultiValueField): def __init__(self, h_choices, m_choices, *args, **kwargs): list_fields = [ChoiceField(), ChoiceField()] super(TimeField, self).__init__(list_fields, widget=TimeWidget(h_choices, m_choices),*args, **kwargs) def compress(self, values): return return values[0] + ':' + values[1] #      datetime 

To protect the user from specifying the time outside the work day, as well as outside the reasonable limit (24 and 60), I made 2 lists with a choice of parameter.

Call:
 time = TimeField(h_choices=HOURS_CHOICES, m_choices=MINUTES_CHOICES) 

And the parameters themselves (in accordance with the Django documentation, must be a list of tuples and be defined outside the form class):
 HOURS_CHOICES = [(str(x), x) for x in range(9, 21)] #      ,     MINUTES_CHOICES = [(1, 0), (2, 10), (3, 20), (4, 30), (5, 40), (6, 50),] #  -  ,  - .     . 



It remains only to understand how to insert some character separators between fields (for example, ':' between hours and minutes), but this does not carry the functional load. However, I will try to solve this problem and supplement the post with the found solution, as well as other examples of the fields.

UPD: the format_output () method is described for getting any neat formatting brackets .

Source: https://habr.com/ru/post/212047/


All Articles