Useful knowledge of Django - 2

linkaiyi
Follow

JsonResponse

need to set parameter safe=True in case of returning non object data

def get_users(request):
    users = User.objects.all().values('first_name', 'last_name')  # or simply .values() to get all fields
    users_list = list(users)  # important: convert the QuerySet to a list object
    return JsonResponse(users_list, safe=False)

Call Celery task

important: call celery task need to use delay() function

views.py

from myapp.tasks import prepare_and_submit_data

def register(request):
  form = SignupForm(request.POST or None)
  if form.is_valid():

    # Async function.
    prepare_and_submit_data.delay(form.cleaned_data)

    return render(request, 'success.html', {})
  return render(request, 'signup.html', {'form': form})

tasks.py

from celery.decorators import task

@task
def prepare_and_submit_data(data):
  # do some external API requests and modify data
  data = requests.post(BASE_URL, data=data).json()
  # ...

Picture manipulation

Use Pillow

from PIL import Image

im = Image.open("sweet_pic.ppm")
im.save("sweet_pic.jpg")

Use os to handle files

Extracting extension from filename from Python
os.path.splittext() # return a 2-tuple
os.path.exists() # File/Folder exists
os.path.dirname() # Folder name
os.path.basename() # filename without Folder
os.path.join() # join folder
os.listdir() # iterate over the folder

files = [i for i in os.listdir("Path/to/directory/storing/emails") if i.endswith("txt")]
delete folder with files
import shutil

shutil.rmtree('/folder_name')

import os
filename, file_extension = os.path.splitext('/path/to/somefile.ext')
#filename
'/path/to/somefile'
#file_extension
'.ext'

several Exceptions together

except (IDontLikeYouException, YouAreBeingMeanException) as e:
    print(e)

Iterate number in for loop of a template

Django provides it. You can use either:

{{ forloop.counter }} index starts at 1.
{{ forloop.counter0 }} index starts at 0.

In template, you can do:

{% for item in item_list %}
    {{ forloop.counter }} # starting index 1
    {{ forloop.counter0 }} # starting index 0

    # do your stuff
{% endfor %}

extract a page from a pdf as a jpeg

The pdf2image library can be used.

You can install it simply using,

pip install pdf2image

Once installed you can use following code to get images.

from pdf2image import convert_from_path
pages = convert_from_path('pdf_file', 500)

Saving pages in jpeg format

for page in pages:
    page.save('out.jpg', 'JPEG')

Need to poppler to be installed beforehand. Path to poppler bin folder can be specified in convert_from_path function

Pass variable from save to post_save signal

use getattr()
You can:

Define and send your own signals.

Store additional info in model instance. Like this

def save(self, commit=True):
    user = super(CustomFormThing, self).save(commit=False)
    #set some other attrs on user here ...
    user._some = 'some'
    user._other = 'other'
    if commit:
    user.save()

    return user

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    some_id = getattr(instance, '_some', None)
    other_id = getattr(instance, '_other', None)

    if created:
    #do something with the kwargs above...

Or to check if something is changed in object
def init(self, args, **kwargs):
super(YOURMODEL, self)._init(
args, **kwargs)

    # SAVE THE INITIAL VALUE
    self.__original_value = self.value_you_want_to_track

def save(self, *args, **kwargs):
    # Compare the initial value with the current value
    if self.__original_value != self.value_you_want_to_track:
         # DO SOMETHING, MAYBE TRIGGER SIGNAL
    super(YOUR_MODEL, self).save(*args, **kwargs)
    # Finally update the initial value after the save complete
    self.__original_value = self.value_you_want_to_track

Validate file type

You can create a custom validator

def validate_file_extension(value):
    import os
    from django.core.exceptions import ValidationError
    ext = os.path.splitext(value.name)[1]
    valid_extensions = ['.xml']
    if not ext.lower() in valid_extensions:
    raise ValidationError(u'Unsupported file extension.')

Then in your form field
coupling_file = forms.FileField(label=’XML File Upload:’,required=True, validators=[validate_file_extension])

Use MD5 to discard uploaded duplicates

import hashlib
import os

from django.core.files.storage import FileSystemStorage
from django.db import models

class MediaFileSystemStorage(FileSystemStorage):
    def get_available_name(self, name, max_length=None):
        if max_length and len(name) > max_length:
            raise(Exception("name's length is greater than max_length"))
        return name

    def _save(self, name, content):
        if self.exists(name):
            # if the file exists, do not call the superclasses _save method
            return name
        # if the file is new, DO call it
        return super(MediaFileSystemStorage, self)._save(name, content)


def media_file_name(instance, filename):
    h = instance.md5sum
    basename, ext = os.path.splitext(filename)
    return os.path.join('mediafiles', h[0:1], h[1:2], h + ext.lower())


class Media(models.Model):
    # use the custom storage class fo the FileField
    orig_file = models.FileField(
        upload_to=media_file_name, storage=MediaFileSystemStorage())
    md5sum = models.CharField(max_length=36)
    # ...

    def save(self, *args, **kwargs):
        if not self.pk:  # file is new
            md5 = hashlib.md5()
            for chunk in self.orig_file.chunks():
                md5.update(chunk)
            self.md5sum = md5.hexdigest()
        super(Media, self).save(*args, **kwargs)

Use annotate in queryset to add new aggregate/summary field

Add two field in queryset
User.objects.filter(
username_startswith=”ab”).annotate(
posts=Count(‘post’, distinct=True)).annotate(
topics=Count(‘topic’, distinct=True)).values_list(
“username”,”posts”, “topics”)

Add new field in admin
def queryset(self):
qs = super(MandantAdmin, self).queryset()
qs = qs.annotate(students=Count(‘usermandantrelation’, distinct=True)).annotate(courses=Count(‘mandantcourse’, distinct=True))
return qs
def coursesnumber(self, instance):
counts = MandantCourse.objects.filter(mandant=instance).all().count()
url = reverse(‘xadmin:operation_mandantcourse_changelist’)
return_url = ‘{3}‘.format(url, str(instance.id), str(instance.id), str(counts)) # return link in list field
return return_url
courses_number.short_description = (‘Anzahl der Schulungen’)
courses_number.allow_tags = True
courses_number.admin_order_field = ‘courses’

How to create and save dynamic fields in Django Admin

The following code worked perfectly. The overridden init and clean methods on the ModelForm adds the dynamic fields and defines how the values should be saved.

The overridden get_form and get_fieldsets together with the fieldsets attribute on the AdminModel make sure the dynamic form fields get displayed in the admin.

class PersonAdminForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(PersonAdminForm, self).__init__(*args, **kwargs)
        new_fields = {}
        initial = self.instance.groups.all()
        for group_type in GroupType.objects.all():
        field_name = '{0}_groups'.format(group_type.name.lower())
        qs = Group.objects.filter(group_type=group_type)
        field = forms.ModelMultipleChoiceField(
        queryset=qs,
        required=False,
        initial=initial,
        )
        new_fields[field_name] = field
        self.fields.update(new_fields)

    def clean(self):
        cleaned_data = super(PersonAdminForm, self).clean()
        groups = []
        for group_type in GroupType.objects.all():
        gt_name = '{0}_groups'.format(group_type.name.lower())
        groups.extend(cleaned_data.get(gt_name))
        self.instance.groups.clear()
        self.instance.groups.add(*groups)
        return cleaned_data

    class Meta:
    model = Person
    fields = '__all__'


@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
form = PersonAdminForm

# using the fieldsets attribute instead of fields in order to dynamically
# add group type fields later.
fieldsets = (
(None, {
'fields': (
'name',
),
}),
)

def get_form(self, request, obj=None, **kwargs):
    kwargs['fields'] = flatten_fieldsets(self.declared_fieldsets)
    return super(PersonAdmin, self).get_form(request, obj, **kwargs)

def get_fieldsets(self, request, obj=None):
    fieldsets = super(PersonAdmin, self).get_fieldsets(request, obj)
    newfieldsets = list(fieldsets)
    fields = []
    for group_type in GroupType.objects.all():
    fields.append('{0}_groups'.format(group_type.name.lower()))
    newfieldsets.append(['Groups', {'fields': fields}])
    return newfieldsets
Object has 0 attachments

Was this article helpful?

This article is viewed 60 times!

Recent Viewed Articles

0 Comments

Leave a Comment