Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to have my template "load" for a second or two before refreshing after a POST

I'm having an issue where I have a MariaDB event combined with my Django Model. For context, here is my model code:

class PartGroup(models.Model):
    GroupID = models.AutoField(primary_key=True, unique=True)
    Label = models.CharField(max_length=40, blank=True)
    SiteID = models.ForeignKey('Site', on_delete=models.CASCADE, null=True)
    InspectionPeriod = models.IntegerField(blank=False, null=True)
    LastInspected = models.DateField(blank=True, null=True)
    InspectionDue = models.CharField(max_length=255, blank=True)
    ConnectedTo = models.ManyToManyField('self', blank=True, null=True)

The fields I want to highlight here are InspectionPeriod, LastInspected, and InspectionDue. I have another model which adds Inspections related to the GroupID. This contains a date of the inspection:

class GroupInspection(models.Model):
    InspectionID = models.AutoField(primary_key=True, unique=True)
    GroupID = models.ForeignKey('PartGroup', on_delete=models.CASCADE, null=True, unique=True)

class GroupReport(models.Model):
    ReportID = models.AutoField(primary_key=True, unique=True)
    InspectionID = models.ForeignKey('GroupInspection', on_delete=models.CASCADE, null=True)
    Date = models.DateField(auto_now=False, auto_now_add=False, null=True)
    Comment = models.CharField(max_length=255, blank=True)
    Signature = models.CharField(max_length=255, blank=True)

I have a MariaDB event to update the LastInspected field, and from there some code in my view checks that date against the inspection period to see if an inspection is due.

Here's where the problem occurs

I have to have my MariaDB Event updating every 1 second in order to make this work reasonably well. I'm not sure if that's absolutely horrendous performance wise or not, if anyone has another solution that works smoother that's welcome. But that's not the real issue. When I create an inspection, this redirects immediately to my Group template page. This takes less than a second to redirect, which leaves my users confused as they just created an inspection and it doesn't show on the redirect yet unless they immediately refresh after 1 second.

How can I get around this?

EDIT 1 I forgot to mention - the way this works at template level is that I have a page which shows a table view of all my groups and their attributes. I then have a few buttons that create an inspection depending on which button is pressed. This just redirects back to the same page which is why the one second thing is an issue as the redirect usually takes less than a second.

EDIT 2 Here's my view:

def groupList(request, site):
    status = "default"
    if request.method == "POST":

        list = GroupInspection.objects.filter(GroupID = request.POST.get("group"))
        if not list.exists():
            insp = GroupInspection.create(PartGroup.objects.get(GroupID = request.POST.get("group")))
            insp.save()


        if 'pass' in request.POST:
            groupReport = GroupReport.create(GroupInspection.objects.get(GroupID = request.POST.get("group")), date.today(), "Pass", request.user.username)
            groupReport.save()
        if 'fail' in request.POST:
            groupReport = GroupReport.create(GroupInspection.objects.get(GroupID = request.POST.get("group")), date.today(), "Fail", request.user.username)
            groupReport.save()
        if 'checkSubmit' in request.POST:
            groupReport = GroupReport.create(GroupInspection.objects.get(GroupID = request.POST.get("group")), date.today(), request.POST.get("comments"), request.user.username)
            groupReport.save()
        status = "changed"
    siteselected = Site.objects.get(SiteID = site)
    groupList = PartGroup.objects.filter(SiteID = siteselected)
    warnings = 0
    expired = 0
    good = 0

    for group in groupList:
        if group.LastInspected == None:
            group.InspectionDue = "Yes"
            expired = expired + 1

        else:
            Deadline = group.LastInspected + timedelta(days=group.InspectionPeriod)

            if datetime.now().date() > Deadline:
                group.InspectionDue = "Yes"
                expired = expired + 1

            elif datetime.now().date() > (Deadline - timedelta(days=30)):
                group.InspectionDue = "<30 Days"
                warnings = warnings + 1
            else:
                group.InspectionDue = "No"
                good = good + 1
        group.save()

    context = {
        'status': status,
        'SiteNo': siteselected.SiteID,
        'SiteName':siteselected.SiteName,
        'groupList': groupList,
        'expired': expired,
        'warnings': warnings,
        'good': good,
        }
    template = loader.get_template('moorings/groupList.html')
    return HttpResponse(template.render(context, request))

EDIT 3 Here's my SQL Event

CREATE EVENT updateLastInspected 
 ON SCHEDULE EVERY 1 SECOND
 DO
 UPDATE proj_partgroup g INNER JOIN (   SELECT i.GroupID_id, max(r.Date) Date   FROM proj_groupinspection i    INNER JOIN proj_groupreport r ON r.InspectionID_id = i.InspectionID   GROUP BY i.GroupID_id ) t ON g.GroupID = t.GroupID_id SET g.LastInspected = t.Date;
like image 924
CalMac Avatar asked Nov 07 '22 10:11

CalMac


1 Answers

You can replace your SQL Event with Django signal that runs after any GroupReport update, and in case it was new report created - updates corresponding PartGroup last updated date.

proj/signals.py

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.apps import apps


GroupReport = apps.get_model("proj", "GroupReport")
PartGroup = apps.get_model("proj", "PartGroup")


@receiver(post_save, sender=GroupReport)
def update_partgroup_lastinspection(sender, instance, created, **kwargs):
    if created:
        # cause FKs can be null - may need to add
        # null checks or try / except
        pg = instance.InspectionID.GroupID
        if instance.Date > pg.LastInspected:
            pg.LastInspected = instance.Date
            pg.save(update_fields=['Date'])

        # another option to perform same update
        PartGroup.objects.filter(
            LastInspected__lt=instance.Date,
            group_inspection__group_report=instance
        ).update(
            LastInspected=instance.Date
        )

proj/apps.py

...
class ProjConfig(AppConfig):
    name = "proj"
...
  def ready(self):
      import proj.signals

You can skip checking that value is greater and just update right away. Or add logic in model's save() method instead (which generally is more preferred than signals).


Previous answer - is not the case here, groupList contains changes to instances.

You are returning groupList which contains old results.

The reason for this is that while being iterated over (for group in groupList) QuerySets are evaluated with the result being cached in this QuerySet instance and when later it is used in context - this evaluated result is passed, although instances were updated in the database. QuerySets need to be run and be evaluated again to fetch fresh results.

One simple solution to reuse the QuerySet and evaluate it again - is append .all() to previous QuerySet - this will make a copy of provided QuerySet and since it is new one - it is not yet evaluated.

    context = {
        ...
        'groupList': groupList.all(),
        ...
        }
like image 199
Oleg Russkin Avatar answered Nov 12 '22 14:11

Oleg Russkin