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.
Related
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.
I am currently working on a little django app, the app is like a social media app.
User can post, like and comment.
I recently created the User Profiles. Which I can now see the user for that user profile in my view, but I cant seem to dig into the Posts that may be related to the UserProfile.
what I am trying to do is in my view of HTML, I want to be able to get the post from the userprofile and the comment, and likes.
But I have tried everything and nothing works.
Currently in my HTML view I have rendered {{ profile.user }} and it displays the users name, but If I try profile.user.post or profile.user.comments I get nothing.
Here is some code to show where I am at.
Any help would be much appreciated.
Profile View.
def profile(request):
profile = get_object_or_404(UserProfile, user=request.user)
template = 'profiles/profile.html'
context = {
'profile': profile,
# 'posts': posts
}
return render(request, template, context)
Profile Model
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class UserProfile(models.Model):
"""
A user profile model to link posts and likes
"""
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
def __str__(self):
return self.user.username
Post Model
from django.db import models
from django.contrib.auth.models import User
from cloudinary.models import CloudinaryField
from profiles.models import UserProfile
class Post(models.Model):
user_profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, null=True, blank=True, related_name='user_posts')
title = models.CharField(max_length=220, unique=True)
location = models.CharField(max_length=220)
rating = models.DecimalField(
max_digits=6, decimal_places=2)
#slug = models.SlugField(max_length=220, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="activity_post")
updated_on = models.DateTimeField(auto_now=True)
description = models.TextField()
featured_image = CloudinaryField('image', blank=False)
created_on = models.DateTimeField(auto_now_add=True)
likes = models.ManyToManyField(User, related_name='activity_likes', blank=True)
like_count = models.BigIntegerField(default='0')
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
def number_of_likes(self):
return self.likes.count()
def liked_by_user(self):
return self.likes.values_list('id', flat=True)
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
name = models.CharField(max_length=80)
email = models.EmailField()
body = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['created_on']
def __str__(self):
return f"Comment {self.body} by {self.name}"
enter code here
My Signal to create / save the profile, also have it registered in apps.py
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import UserProfile
#receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
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 :)
I'm trying to hide and delete two fields from showing in a form I created in the Django administration page using ModelForm.
I looked at answers that said I should use the "exclude" meta field, but I don't know why it's not working in my case.
Here is my code:
models.py:
class Activity(models.Model):
type = models.CharField(max_length=50, default="")
title = models.CharField(max_length=200, default="")
description = models.CharField(max_length=500)
owner = models.ForeignKey(User, related_name="owner")
college = models.CharField(max_length=200)
location = models.CharField(max_length=200)
room = models.CharField(max_length=200)
startDate = models.DateTimeField(null=True, blank=True)
endDate = models.DateTimeField(null=True, blank=True)
attendee = models.ManyToManyField(Attendee, related_name="attendees",null=True, blank=True)
volunteer = models.ManyToManyField(Volunteer, related_name="volunteers",null=True, blank=True)
I'm trying to exclude the "attendee & volunteer" fields from displaying in the Django administration form.
In admin.py I have:
from django.contrib import admin
from django import forms
from KSUvity.models import Activity
class ActivityForm(forms.ModelForm):
class Meta:
model = Activity
exclude = ['attendee', 'volunteer',]
class ActivityAdmin(admin.ModelAdmin):
exclude = ['attendee', 'volunteer',]
form = ActivityForm
admin.site.register(Activity, ActivityAdmin)
You have to create an admin.py file in your app and register your models
Follow the instuctions
See the example below
from django import forms
from django.contrib import admin
from myapp.models import Person
class PersonForm(forms.ModelForm):
class Meta:
model = Person
exclude = ['name']
class PersonAdmin(admin.ModelAdmin):
exclude = ['age']
form = PersonForm
admin.site.register(Person, PersonAdmin)
You can use either fields or exclude in one class.
In your app admin field add this code.
app_name/admin.py
from django.contrib import admin
class ActivityAdmin(admin.ModelAdmin):
exclude = ('attendee', 'volunteer',)
You have to use ModelAdmin option to exclude fields from form in Django administration, either ModelAdmin.exclude or ModelAdmin.fields. Below is an example:
class ActivityAdmin(admin.ModelAdmin):
exclude = ('attendee', 'volunteer', )
To make it work, you register model like this:
admin.site.register(Activity, ActivityAdmin)
You add this code to admin.py file.
i am using django default receiver to handle signal. but its not working.
i have modified User model in APP1 whenver new User object create a receiver in APP2 signal.py is listen to it, but its not working.
app1/model.py
class User(BaseModel, AbstractBaseUser, PermissionsMixin):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
username = models.CharField(max_length=40, unique=True)
first_name = models.CharField(max_length=30, blank=True, null=True)
last_name = models.CharField(max_length=30, blank=True, null=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_email_verified = models.BooleanField(default=False)
is_paid = models.IntegerField(default=0)
access_token = models.CharField(max_length=128, blank=True)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
class Meta:
db_table = 'users'
def __str__(self):
return self.email
app2/signals.py
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from accounts.models import User
#receiver(post_save, sender=User)#settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
print ("token generated")
if created:
print("data at signal ****", instance.email, instance)
Finally I got the answer. Its because I'm not importing signals.py on startup.
Working code
apps.py
from __future__ import unicode_literals
from django.apps import AppConfig
class StreamsConfig(AppConfig):
name = 'streams'
def ready(self):
print("at ready")
import streams.signals
init.py
default_app_config = 'streams.apps.StreamsConfig'
after this change I'm receiving signals
Update:
As per django 3.0 documentation for newer applications adding default_app_config in init.py is not required if you are using dotted path to application configuration.
https://docs.djangoproject.com/en/3.0/ref/applications/#django.apps.AppConfig.ready
Just replace
INSTALLED_APPS = (
...,
'streams',
)
with
INSTALLED_APPS = (
...,
'streams.apps.StreamsConfig',
)
It will work.