Save file with Django Model to JSONField - python

I need to save files, but the number of files is uncertain, and in one request I can add a file, then in another request post, I can add one more file ...
For this reason I thought that creating a JSONField type field could help me in this matter, but I don't know if it is possible and if it is possible I have no idea how to implement it in Django.
Here is an example of how I currently upload a single file to Django Model:
import uuid
import time
from users.models import User
from django.db import models
def upload_location(instance, filename):
filebase, extension = filename.split('.')
milliseconds = int(round(time.time() * 1000))
return 'events/thumbnail_images/%s__%s__%s.%s' % (instance.user_id, instance.name, milliseconds, extension)
class Test(models.Model):
id = models.UUIDField(primary_key=True, unique=True, default=uuid.uuid4, editable=False, null=False)
image_link = models.FileField(upload_to=upload_location)
user = models.ForeignKey(
User,
null=True,
blank=False,
on_delete=models.CASCADE
)
As I'm using Postgres relational database, and I'm not sure how many files the user will want to save, I figured using JSONField, so that as the user adds files, the 'path+filename' is also added.
It's possible? How to make?

I suggest you to create a separate model Attachment and make the relation with this model by adding ForeignKey field To Attachment model or using ManyToManyField by desired model.
With this approach you can add many files to the desired model.
Here is an example of Attachment model:
import uuid
import time
from users.models import User
from django.db import models
def upload_location(instance, filename):
filebase, extension = filename.split('.')
milliseconds = int(round(time.time() * 1000))
return 'events/thumbnail_images/%s__%s__%s.%s' % (instance.user_id, instance.name, milliseconds, extension)
class Test(models.Model):
id = models.UUIDField(primary_key=True, unique=True, default=uuid.uuid4, editable=False, null=False)
user = models.ForeignKey(User,null=True,blank=False,on_delete=models.CASCADE)
class Attachment(models.Model):
# here is the relation
test = models.ForeignKey(Test, on_delete=models.CASCADE)
name = models.CharField(verbose_name="Attachment Name", max_length=255, null=True, blank=True)
att_img = models.ImageField(
upload_to=upload_location,
verbose_name="Attach an Image",
null=True, blank=True, max_length=255
)
att_file = models.FileField(
upload_to=upload_location,
verbose_name="Attach a File",
null=True, blank=True, max_length=255
)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s - %s' % (self.name, self.test)

For file i am just taking image as an example
class ImageClass(models.Model):
YourClassHere_FK_image = models.ForeignKey(
'YourClassHere', related_name='images', on_delete=models.CASCADE)
title = models.CharField(max_length=200, blank=True)
image = models.ImageField(upload_to=UploadedConfigPath_image, verbose_name='Image', null=True, blank=True, validators=[FileExtensionValidator(allowed_extensions=[
'jpg', 'png', 'jpeg', 'webp'])], help_text="Something related images")
Then in your forms.py file do something like this
class Mult_ImageForm(forms.Form):
multiple_images = forms.FileField(required=False, help_text='Select Multiple Images(jpg,png) for your Class if you want (Optional) Max:10',
widget=forms.ClearableFileInput(attrs={'multiple': True, 'accept': 'image/*'}))
Then do the views.py
def post_create(request):
mul_images_product = Mult_ImageForm(request.POST,request.FILES)
if request.method == 'POST':
Your code here
Also in your HTML you need to render this form as you said it could be requested again and again. This is the simplest way to do it as per my understanding. You can add as many files as you like just provide them same foreign key to your ImageClass model in your views :)

Related

'project.Account' has no ForeignKey to 'project.Object': How to link an account model to the objects of a project?

I am trying to create an announcement website (All) that can be visible to others (the Users, for which I added an Account). For this I wanted to modify a little the user profile to add fields like telephone, email address...
So I modified admin.py:
from django.contrib import admin
from .models import Todo, Account
from django.contrib.auth.models import User
class AccountInline(admin.StackedInline):
model = Account
can_delete = False
verbose_name_plural = 'Accounts'
class TodoAdmin(admin.ModelAdmin):
readonly_fields = ('created',)
inlines = (AccountInline, )
admin.site.unregister(User)
admin.site.register(Todo, TodoAdmin)
But got back:
<class 'todo.admin.AccountInline'>: (admin.E202) 'todo.Account' has no ForeignKey to 'todo.Todo'.
So I added a ForeignKey to Todo with account = models.ForeignKey(Account, on_delete=models.CASCADE):
from django.db import models
from django.contrib.auth.models import User
class Account(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
email = models.CharField(max_length=100)
firstname = models.CharField(max_length=30)
lastname = models.CharField(max_length=50)
company = models.CharField(max_length=5)
def __str__(self):
return self.user.username
class Todo(models.Model):
title = models.CharField(max_length=100)
datetime = models.DateTimeField()
memo = models.TextField(blank=True)
created = models.DateTimeField(auto_now_add=True)
datecompleted = models.DateTimeField(null=True, blank=True)
important = models.BooleanField(default=False)
user = models.ForeignKey(User, on_delete=models.CASCADE)
account = models.ForeignKey(Account, on_delete=models.CASCADE)
def __str__(self):
return self.title
But I still have the error, and I don't have any Users in the admin panel anymore
You accidentally wrote unregister for Users in your admin.py file. It should be admin.site.register(User)
You misinterpretted the error: the error states that you don't have a foreign key in your Account model to Todo.
This means your inline admin code isn't correct as it's expecting the other way around.

How can I hide current uploaded image location path in django?

I have made a feature in Django where every user can change his platform's logo. The image selected by the user will be saved in static/{user.customer.public_id}/platformLogo/image.jpg. When i save the changes, i can see the uploaded image's path which also contain unique public ID which i don't want user to see for security purpose. Can anyone help me to hide this image path in Django for user? Attaching my code part here below.
Here we can see the image path which has unique ID in path, which we need to hide
Here is the uploaded image path directory
Here is my models.py
from sre_constants import CATEGORY
from unicodedata import category
from attr import fields
from django.db import models
from datetime import date
from django.contrib.auth.models import User
import uuid
def upload_path(instance, filename):
filename = str(date.today())
name = instance.user.customer.public_id.hex
return f'{name}/platformLogo/{filename}.jpg'
class Customer(models.Model):
user = models.OneToOneField(User, null=True, blank =True, on_delete=models.CASCADE)
public_id = models.UUIDField(primary_key=True, default = uuid.uuid4, editable=False)
date_created = models.DateTimeField(auto_now_add=True, null=True)
name = models.CharField(max_length=200, null=True)
otp_code = models.CharField(max_length=6, null=True)
first_name = models.CharField(max_length=200, null=True)
last_name = models.CharField(max_length=200, null=True)
email = models.CharField(max_length=200, unique=True)
phone = models.CharField(max_length=200, null=True)
profile_pic= models.ImageField(upload_to=upload_path, default='logo.png', null=True, blank=False,)
def __str__(self):
return self.name
Here is my views.py
#login_required(login_url='login')
def accountSetting(request):
customer = request.user.customer
form = CustomerForm(instance= customer)
if request.method == 'POST':
form = CustomerForm(data=request.POST, files=request.FILES, instance=customer)
if form.is_valid():
form.save()
context = {'form': form}
if request.user.is_anonymous:
return redirect("/")
return render(request, 'account-settings.html', context)
Here is my forms.py
from django.forms import ModelForm
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import Customer
from django import forms
class CustomerForm(ModelForm):
class Meta:
model = Customer
fields = '__all__'
exclude = ['user', 'email','name','otp_code']
class CreateUserForm(UserCreationForm):
class Meta:
model = User
fields = ['username','first_name','last_name', 'email', 'password1', 'password2']
Here is settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
MEDIA_URL = '/platformLogo/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'static/platformLogo')
Since you already made public_id UUID, why not hash the logo and image name?
In Django environments I’ve used xsendfile with Apache or nginx. You end up placing the images in a folder that is accessible by Apache and served by apache, but can only be served after a request to the Django backend. It prevents all of the logos being visible to prying eyes.

Django - Membership matching query does not exist

I'm trying to create a subscription style service on Django (using Django3)
Basically, I had it working..ish, but my stripe customer keys weren't being added in, so I fiddled around to get that sorted.
Now I'm getting this error - Membership matching query does not exist. this is whenever I'm trying to create an account, login or login to the admin of my Django project.
I can't really figure out what the issue is, as I've reverted the changes I made to get the cust-Id (any tips here would be appreciated! lol) working again, but it's still throwing it up at me.
Here's my code in my models, I can't even pinpoint where this issue is coming from if I'm honest. (I got this mostly from the JustDjango tutorial btw!)
The debug thing is saying it's to do with the free_membership variable in the post_save_usermembership_create method though.
So far I just have models.py and admin.py done to get this up & running -
from django.conf import settings
from django.db import models
from django.db.models.signals import post_save
from datetime import datetime
import stripe
stripe.api_key = settings.STRIPE_SECRET_KEY
MEMBERSHIP_CHOICES = (
('Regular', 'reg'),
('Premium', 'premium'),
('Free', 'free')
)
class Membership(models.Model):
slug = models.SlugField()
membership_type = models.CharField(
choices=MEMBERSHIP_CHOICES,
default='Free',
max_length=30)
price = models.IntegerField(default=15)
stripe_plan_id = models.CharField(max_length=40)
def __str__(self):
return self.membership_type
class UserMembership(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
stripe_customer_id = models.CharField(max_length=40)
membership = models.ForeignKey(
Membership, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.user.username
def post_save_usermembership_create(sender, instance, created, *args, **kwargs):
user_membership, created = UserMembership.objects.get_or_create(
user=instance)
if user_membership.stripe_customer_id is None or user_membership.stripe_customer_id == '':
new_customer_id = stripe.Customer.create(email=instance.email)
free_membership = Membership.objects.get(membership_type='Free')
user_membership.stripe_customer_id = new_customer_id['id']
user_membership.membership = free_membership
user_membership.save()
post_save.connect(post_save_usermembership_create,
sender=settings.AUTH_USER_MODEL)
class Subscription(models.Model):
user_membership = models.ForeignKey(
UserMembership, on_delete=models.CASCADE)
stripe_subscription_id = models.CharField(max_length=40)
active = models.BooleanField(default=True)
def __str__(self):
return self.user_membership.user.username

How to create/update nested Serializers with Filefields

I have a python 3.6 + django 1.10 + djangorestframework 3.6.4 project.
I have 2 Model classes called Report and ReportFile. I want to create the CRUD operations to get, post and put those files together with a report.
1 Report has a type (which doesn't really matter here) and can have many ReportFiles that the user should be able to upload.
The modelclasses look like this:
class Report(CreationModificationMixin):
report_type = models.ForeignKey(ReportType, on_delete=models.SET_NULL,
null=True, related_name='issues',
verbose_name='Report', editable=False)
name = models.CharField(max_length=50, blank=True)
class ReportFile(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
report = models.ForeignKey(Report, on_delete=models.CASCADE, related_name='files')
uploaded_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name='uploads',
null=True)
file = models.FileField(upload_to=upload_report_to, max_length=500)
and the serializer class:
class ReportSerializer(serializers.ModelSerializer):
files = ReportFileSerializer(many=True)
formats = serializers.SerializerMethodField()
class Meta:
model = Report
fields = ('id', 'name', 'report_type', 'files')
def create(self, validated_data):
rfs_data = validated_data.pop('files')
rf = Report.objects.create(**validated_data)
for rf_data in rfs_data:
ReportFile.objects.create(Report=rf, **rf_data)
return rf
and the ViewSet:
class ReportViewSet(viewsets.ModelViewSet):
serializer_class = ReportSerializer
queryset = Report.objects.all().prefetch_related('report_type')
But I cannot manage to upload the files correctly. Because first I cannot manage to upload that correctly with Postman and I somehow also doubt that this is the correct way to go. Can somebody hint me how I should do this?
Thank you a lot!

How to execute CASCADE on delete?

I have this model in Django, where a person has the same information from the user provided by Django plus a little bit more information. When I create a new person it requires to create a new user also, that's fine. But when I delete a person the user still remains on my database. What am I missing here ? I would like to delete the user too.
class Person(models.Model):
user = OneToOneField(User)
gender = CharField(max_length=1, choices=GenderChoices, blank=True, null=True)
birth_date = DateField(blank=True, null=True)
def __unicode__(self):
return self.user.username
Try to override the delete method on the model (code not tested):
class Person(models.Model):
user = OneToOneField(User)
gender = CharField(max_length=1, choices=GenderChoices, blank=True, null=True)
birth_date = DateField(blank=True, null=True)
def __unicode__(self):
return self.user.username
def delete():
theuser = User.objects.get(id=user)
theuser.delete()
I have found some relevant documentation about CASCADE usage in Django here.

Categories