Search code examples
pythondjangodjango-allauth

In Django, how do I update a user profile if a model is added to database?


I'm creating a site where users can upload files. I have my upload form working, and it correctly associates the current user with the uploaded file. Once it's uploaded however, I would like the User Profile model to update the number of files uploaded for that specific user. I'm using django-allauth with a custom admin model.

models.py (works to recognize current user)

class ConfigFiles(models.Model):
    user = models.ForeignKey(
    settings.AUTH_USER_MODEL, blank=True, null=True)

    Printer = models.CharField(_('Printer Model'),
    max_length=100, blank=True, null=True, unique=False, help_text="Something like 'i3'")
    printerbrand = models.CharField(_('Printer Brand'),
    max_length=100, blank=True, null=True, unique=False, help_text="Something like 'Prusa'")
    Plastic = models.CharField(_('Plastic'),    
    max_length=40, blank=True, null=True, unique=False, help_text="Something like 'ABS' or 'Nylon'")

    HDConfig = models.FileField(_('High Detail, Slow Speed'), 
    upload_to=UploadedConfigPath, validators=[validate_file_extension], help_text="Displayed as HD on Infinity-Box")
    LDConfig = models.FileField(_('Fast speed, Low Detail'), 
    upload_to=UploadedConfigLDPath, validators=[validate_file_extension], help_text="Displayed as FAST on Infinity-Box")

    pub_date = models.DateTimeField(_('date_joined'), 
    default=timezone.now)

And here's my custom admin models.py (doesn't auto update configuploaded)

class UserProfile(models.Model):
    user = models.OneToOneField(DemoUser, primary_key=True, verbose_name='user', related_name='profile')

    avatar_url = models.CharField(max_length=256, blank=True, null=True)

    configuploaded = models.IntegerField(_('Number of uploaded Config files'), default=0, unique=False)
    filesuploaded = models.IntegerField(_('Number of uploaded STL files'), default=0, unique=False)


    dob=models.DateField(verbose_name="dob", blank=True, null=True)

    def __str__(self):
        return force_text(self.user.email)

    class Meta():
        db_table = 'user_profile'

EDIT 1

Here's view.py.

@login_required
def uplist(request):
    if request.method == 'POST':
        form = ConfigUpload(request.POST, request.FILES)
        if form.is_valid():

            comment = form.save(commit=False)
            comment.user = request.user
            #newdoc = ConfigFiles(HDConfig=request.FILES['HD file'])

            comment.save()


            messages.add_message(request, messages.SUCCESS, "Configuration added")    

            # Redirect to the document list after POST
            return HttpResponseRedirect(reverse_lazy('list'))
    else:
        form = ConfigUpload()  # A empty, unbound form
    print (request.user.first_name)
    # Load documents for the list page
    documents = ConfigFiles.objects.all()

    # Render list page with the documents and the form
    return render(
        request,
        'visitor/configupload.html',
        {
        'documents': documents,
        'form': form,
        }
    )

Ideally, whenever the user uploads a file the configuploaded variable increase correspondingly. Is there a simple way to do this within models or should I do if from my views.py?


Solution

  • Theres a few ways to solve this, how best to go about it depends on your use case. In my current site I use a mix of properties and signals to acheive this functionality.

    Using a property - less db writes works & even if you execute bulk deletes on a model, but generates a query everytime you display it.

    class UserProfile(models.Model):
        #your stuff
        def _get_uploaded_files(self):
              return ConfigFiles.objects.filter(some_appropriate_filter).count()
        uploaded_files = property(_get_uploaded_files)
    

    Override the save method to increment your field:

    class ConfigFiles(models.Model):
    #your model definition here
        def save(self, *args, **kwargs):
            super(ConfigFiles, self).save(*args, **kwargs)
            self.user.filesuploaded += 1
    

    You can also use the postsave signals as per Atul Yadav's answer. However IMO they are somewhat less clear (because you end up defining functionality outside of the model) although they are useful if you need to do several things