Django custom user profile image not saving properly - django

I've got a custom user model that when the image is updated it adds characters to the file path making django unable to find the new updated profile image.
MODELS.PY
from django.db import models
from django.contrib.auth.models import AbstractUser
from PIL import Image
from django.conf import settings
import os
class CustomUser(AbstractUser):
username = models.CharField(max_length=255, unique=True)
password = models.CharField(max_length=255)
email = models.EmailField(unique=True)
# Add any additional fields you want to store about users, such as their profile picture, etc.
image = models.ImageField(default='default.png',
upload_to='profile_pics', null=True, blank=True)
def save(self, *args, **kwargs):
# Check if the image field has changed
if self.pk:
orig = CustomUser.objects.get(pk=self.pk)
if orig.image != self.image:
# Delete the previous image file
if orig.image:
orig.image.delete(save=False)
# Create a thumbnail image
if self.image:
try:
image = Image.open(self.image)
except FileNotFoundError:
print("Image file not found:", self.image.path)
return
image.thumbnail((200, 200), Image.ANTIALIAS)
# Save the image to the correct path
image_path = os.path.join(
settings.MEDIA_ROOT, self.image.field.upload_to, self.image.name)
image.save(image_path)
super().save(*args, **kwargs)
Views.py
class UserPostListView(ListView):
model = Post
template_name = 'gorl/user_posts.html'
context_object_name = 'posts'
# paginate_by = 5
def get_queryset(self):
user = get_object_or_404(
CustomUser, username=self.kwargs.get('username'))
return Post.objects.filter(author=user).order_by('-date_posted')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
user = get_object_or_404(
CustomUser, username=self.kwargs.get('username'))
context['user'] = user
context['show_profile_settings'] = self.request.user.username == user.username
context['comments'] = Comment.objects.all()
total_likes = 0
context['likes'] = {}
# Get the number of likes for each post and store it in the context data
for post in context['posts']:
likes = Like.objects.filter(post_id=post).count()
if likes >= 0:
context['likes'][post.id] = likes
total_likes += likes
context['total_likes'] = total_likes
return context
class UpdateProfileView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = CustomUser
form_class = UpdateProfileForm
template_name = 'gorl/update_profile.html'
def test_func(self):
# Check if the current user is the owner of the profile
return self.request.user == self.get_object()
def form_valid(self, form):
# Save the form data to the database
form.save()
# Check if the user has uploaded a new image
if form.cleaned_data['image']:
# If a new image has been uploaded, delete the old image file
if self.get_object().image:
self.get_object().image.delete(save=False)
# Save the new image to the database
form.save()
messages.success(self.request, 'Your profile has been updated')
return redirect('update-profile', pk=self.object.pk)
def form_invalid(self, form):
messages.error(
self.request, 'There was an error updating your profile')
return redirect('update-profile', pk=self.object.pk)
def handle_no_permission(self):
messages.success(
self.request, "Don't be like that Gorl.")
# redirect to an error page if the user is not the author of the post
return render(self.request, 'gorl/error.html', {'error': "You don't have permission to edit this post."})
FORMS.PY
class UpdateProfileForm(forms.ModelForm):
image = forms.ImageField(required=False)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_show_labels = True
self.helper.layout = Layout(
Field('username', css_class='form-control'),
Field('email', css_class='form-control'),
Field('image', css_class='form-control'),
)
class Meta:
model = CustomUser
fields = ['username', 'email', 'image']
Clip of settings
STATIC_URL = 'static/'
STATICFILES_DIRS = [BASE_DIR / "static", ]
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
Template
{% extends 'gorl/layout.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% crispy form %}
{% block content %}
<div class="my-5">
<div class="container">
<div class="card shadow mb-3 p-3">
<h3 class="card-header text-pink">Profile Settings</h3>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4 text-pink">
</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group my-3">
<button class="btn btn-outline-info hot-pink-button" type="submit">Save</button>
</div>
</form>
</div>
</div>
</div>
{% endblock content %}
I have in my root project urls.py file
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
I just cannot understand why when I choose a different image file to upload it will take that file and add characters to the end of the file and then when the profile is looking for the image file it does not match the one that was uploaded.

Related

How to save multiple dynamically created forms in django

I am trying to create a page where various data corresponding to mutliple models can be input by the user, and to have an option to dynamically add additional forms. I have been attempting to use htmx for this and am able to dynamically add forms, however when I save it is only the last entered form that is saved. I haven't used formsets as this wont integrate well with htmx https://justdjango.com/blog/dynamic-forms-in-django-htmx#django-formsets-vs-htmx.
Code below any suggestion as to how to get all the dynamically created forms to be save would be most appreciated!
models.py
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=50)
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
forms.py
from django import forms
from .models import Book, Author
from crispy_forms.helper import FormHelper
class AuthorForm(forms.ModelForm):
class Meta:
model = Author
fields = ['name']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'id-CaseForm'
self.helper.form_class = 'blueForms'
self.helper.form_method = 'post'
self.helper.form_tag = False
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = ('title',)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_method = 'post'
self.helper.form_tag = False
self.helper.form_show_labels = False
views.py
class create_book(TemplateView):
template_name = 'create_book.html'
def get(self, *args, **kwargs):
author_form = AuthorForm
book_form = BookForm
return self.render_to_response(
{'book_form': BookForm,
"author_form": AuthorForm,}
)
def post(self, *args, **kwargs):
author_form = AuthorForm(data=self.request.POST)
book_form = BookForm(data=self.request.POST)
if author_form.is_valid():
author = author_form.save()
if book_form.is_valid():
book = book_form.save(commit=False)
book.author = author
book.save()
def create_book_form(request):
form = BookForm()
context = {
"form": form
}
return render(request, "partials/book_form.html", context)
urls.py
urlpatterns = [
path('create_book/', create_book.as_view(), name='create-book'),
path('htmx/create-book-form/', create_book_form, name='create-book-form'),]
create_book.html
{% extends "base.html" %}
{% block content %}
{% load crispy_forms_tags %}
<form class="blueForms" id="id-CaseForm" method="post" >
{% crispy author_form %}
{% crispy book_form %}
<button type="button" hx-get="{% url 'create-book-form' %}" hx-target="#bookforms" hx-swap="beforeend">
Add book form
</button>
<div id="bookforms"></div>
</form>
partials/book_form.html
{% load crispy_forms_tags %}
<div hx-target="this" hx-swap="outerHTML">
{% csrf_token %}
{% crispy form %}
{{ form.management_form }}
</div>
A quick Google finds me this module:
https://github.com/adamchainz/django-htmx
It seems someone may have already done this for you my friend :)

Using formsets for my fileupload does not work when doing an update class based view only on create in django

I have used as many examples online as I could cobble together in an attempt to get my two simple models to have the ability to do an inline formset allowing me to add many files to a technial drawing.
This is not working, I can only add one file for the Create and the update only updates the Technical_Entry model, not a file...which in of itself acts funny. The UI ona create shows one spot to add a file, then save the entire record and its child record. That works.
The update, the UI shows the file that was saved earlier..(great!) but then has two more 'choose file' slots (random?) and adding a file to those does nothing when the save is clicked. It doesn't remove the file previously added in the create, but it also
does not save the new file added to the now three slots (one used, two free). So update does not work for the files for some reason.
class Technical_Entry(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
ema = models.ForeignKey(EMA, on_delete=models.CASCADE)
system = models.ForeignKey('System', on_delete=models.CASCADE) # are SYSTEMS RELATED TO SUBSYSTEMS OR JUST TWO GROUPS?
sub_system = models.ForeignKey(SubSystem, on_delete=models.CASCADE)
drawing_number = models.CharField(max_length=200)
drawing_title = models.CharField(max_length=255)
engineer = models.CharField(max_length=200)
vendor = models.ForeignKey(Vendor, on_delete=models.CASCADE)
date_drawn = models.DateField()
ab = models.BooleanField()
class Technical_Entry_Files(models.Model):
tech_entry = models.ForeignKey(Technical_Entry, on_delete=models.CASCADE)
file = models.FileField(upload_to='techdb/files/')
def __str__(self):
return self.tech_entry.drawing_number
To upload using a formset. While the page 'displays' mostly correctly, it flat out does not create the record in the Technical_Entry_Files model.
Relevant forms.py:
class FileUploadForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(FileUploadForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-lg-4'
self.helper.field_class = 'col-lg-8'
class Meta:
model = Technical_Entry_Files
fields = ('file',)
TechFileFormSet = inlineformset_factory(Technical_Entry, Technical_Entry_Files, form=FileUploadForm, extra=1, max_num=15)
class Technical_EntryForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(Technical_EntryForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_class = 'form-horizontal'
self.helper.label_class = 'col-lg-4'
self.helper.field_class = 'col-lg-8'
self.helper.add_input(Submit('submit', 'Submit'))
class Meta:
model = Technical_Entry
fields = ('category', 'ema', 'system', 'sub_system', 'drawing_number', 'drawing_title', 'engineer', 'vendor', 'date_drawn', 'ab')
widgets = {
'date_drawn':DateInput(attrs={
'class':'datepicker form-control',
'id' : 'datetimepicker2',
'tabindex' : '1',
'placeholder' : 'MM/DD/YYYY hh:mm',
'autocomplete':'off',
}, format='%m/%d/%Y'),
'system' : Select(attrs={'tabindex':'2'}),
}
Relevant views.py:
class TechEntryCreateView(LoginRequiredMixin, CreateView):
print ("we are here")
model = Technical_Entry
form_class = Technical_EntryForm
template_name = 'techdb/tech_entry_form.html'
print(template_name)
success_url = '/techentry_add'
def get_context_data(self, **kwargs):
data = super(TechEntryCreateView, self).get_context_data(**kwargs)
if self.request.POST:
data['file_upload'] = TechFileFormSet(self.request.POST, self.request.FILES)
else:
data['file_upload'] = TechFileFormSet()
return data
def form_valid(self, form):
context =self.get_context_data()
file_upload = context['file_upload']
with transaction.atomic():
self.object = form.save()
if file_upload.is_valid():
file_upload.instance =self.object
file_upload.save()
return super(TechEntryCreateView, self).form_valid(form)
class TechEntryUpdateView(LoginRequiredMixin, UpdateView):
model = Technical_Entry
form_class = Technical_EntryForm
template_name = 'techdb/tech_entry_form.html'
success_url = '/'
def get_context_data(self, **kwargs):
context = super(TechEntryUpdateView, self).get_context_data(**kwargs)
if self.request.POST:
context["file_upload"] = TechFileFormSet(self.request.POST, self.request.FILES,instance=self.object)
else:
context["file_upload"] = TechFileFormSet(instance=self.object)
return context
def form_valid(self, form):
context = self.get_context_data()
file_upload = context["file_upload"]
self.object = form.save()
if file_upload.is_valid():
file_upload.instance =self.object
file_upload.save()
return super(TechEntryUpdateView, self).form_valid(form)
and the tech_entry_form.html:
{% extends 'base.html' %}
{% load static %}
{% block page-js %}
<script>
$('.link-formset').formset({
addText: 'add file',
deleteText: 'remove',
});
</script>
{% endblock %}
{% block content %}
<main role="main" class="container">
<div class="starter-template">
<h1>New Tech Entry</h1>
</div>
<h2> Details of Technical Entry </h2>
<div class="row">
<div class="col-sm">
<form action="" method="post" enctype="multipart/form-data">{% csrf_token %}
{{ form.as_p }}
<h2> Files </h2>
{{ file_upload.management_form }}
{% for upload_form in file_upload.forms %}
<div class="link-formset">
{{ upload_form.file }}
</div>
{% endfor %}
<input type="submit" value="Save"/>back to the list
</form>
</div>
</div>
</div>
</main><!-- /.container -->
{% endblock %}
And what the UI looks like on edit...
class TechEntryUpdateView(LoginRequiredMixin, UpdateView):
model = Technical_Entry
form_class = Technical_EntryForm
template_name = 'techdb/tech_entry_form.html'
success_url = '/'
#log_entry_class = Technical_EntryForm(Technical_Entry) #removed
def get_context_data(self, **kwargs):
context = super(TechEntryUpdateView, self).get_context_data(**kwargs)
#self.object = self.get_object() #removed
if self.request.POST:
context["file_upload"] = TechFileFormSet(self.request.POST, self.request.FILES,instance=self.object)
else:
context["file_upload"] = TechFileFormSet(instance=self.object)
return context
def form_valid(self, form):
context = self.get_context_data()
file_upload = context["file_upload"]
self.object = form.save()
if file_upload.is_valid():
file_upload.instance =self.object
file_upload.save()
#return super().form_valid(form)
return super(TechEntryUpdateView, self).form_valid(form) #replaced old one
UPDATE
1. in order to be able to add mulitple files when creating,
TechFileFormSet = inlineformset_factory(Technical_Entry, Technical_Entry_Files, form=FileUploadForm, extra=4, max_num=4)
# note I changed to extra=4, if you always want to have only 4 files, then also change to max_num=4
2. When update, the reason why the update is not working even after modifying the views was because you were not passing hidden fields. You were not passing the ids of the files, therefore, your formsets were not passing .is_valid(), hence, no update. Add for loop about hidden fields like below.
{{ file_upload.management_form }}
{% for upload_form in file_upload.forms %}
{% for hidden in upload_form.hidden_fields %}
{{hidden}}
{% endfor %}
<div class="link-formset">
{{ upload_form.file }}
</div>
{% endfor %}
#Note the for loop I add about hidden fields.

image upload in a template

My issue is if I upload from admin an image it works fine but if I want to add an image from my template, it seems that my image does not updload.
It is weird as in the request.Post form, path of my image is present.
I've no message of error...
this is my model:
class Listing(models.Model):
title = models.CharField('Title',max_length=64, blank=False)
description = models.TextField('Descritpion', blank=False)
Creation_date = models.DateField(auto_now_add=True)
enddate= models.DateField('Ending Date', blank=False)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="category")
initialBid = models.DecimalField('Bid', max_digits=12, decimal_places=2, blank=False)
photo = ResizedImageField(size=[300, 150], upload_to='images/', default='images/default.jpg')
active = models.BooleanField('Active', default=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="author")
def __str__(self):
return f"{self.id} : {self.title} {self.initialBid} {self.Creation_date}"
def save(self, *args, **kwargs):
# Check how the current ending date is after created date,
d1 = self.Creation_date
d2 = self.enddate
if d2 <= d1:
raise ValueError("End date must be a day after today")
super(Listing, self).save(*args, **kwargs)
my form:
class NewListingForm(forms.ModelForm):
enddate = forms.DateField(label='Date of auction End', widget=forms.DateInput(format = '%d/%m/%Y'),
input_formats=('%d/%m/%Y',))
def __init__(self, *args, **kwargs):
self._newly_created = kwargs.get('instance') is None
self.Creation_date = datetime.now()
super().__init__(*args, **kwargs)
class Meta:
model = Listing
fields = ('title','description','enddate','category','initialBid','photo','active')
my template:
<h2>{% if not form.instance.pk %}Create listing {% else %} Edit {% endif %}</h2>
<form id="create-edit-client" class="form-horizontal" action="" method="post" accept-charset="utf-8" enctype="multipart/form-data">
{% csrf_token %}
{{ form.title|as_crispy_field }}
{{ form.description|as_crispy_field }}
<br>
<div class="row">
<div class="col-3">
{{ form.category|as_crispy_field }}
</div>
<div class="col-2">
{{ form.initialBid|as_crispy_field }}
</div>
</div>
<br>
<div class="row">
<div class="col-3">
{{ form.enddate|as_crispy_field }}
</div>
<div class="col-2">
{{ form.active|as_crispy_field }}
</div>
</div>
<br>
{{ form.photo|as_crispy_field }}
<br>
<br>
</form>
in settings:
STATIC_URL = '/static/'
# gestion ds media
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
in urls:
urlpatterns = [
......
]+static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
my views:
#login_required
def editlisting(request, listing_id):
obj = Listing.objects.filter(pk=listing_id).first()
if obj is None:
return render(request, "errors/404.html", {
"entryTitle": listing_id
})
else:
form = NewListingForm(instance=Listing.objects.get(pk=listing_id))
modification=True # used in template to check if modification are allowed
# read only form if not author
user = request.user.id
if obj.author.id != user:
modification=False
# manage save
if request.method == "POST":
form = NewListingForm(request.POST, instance=Listing.objects.get(pk=listing_id))
if form.is_valid():
form.save()
messages.success(request, 'listing saved') # message for inform user of success - See messages in html file
return HttpResponseRedirect(reverse("index"))
# check if in wishes on get
wishbool=False
wish = Wishing.objects.filter(item=listing_id, follower=request.user.id).first()
if wish is not None:
wishbool = True
return render(request, 'auctions/newListing.html', {
"form": form,
"existing": True,
'title': "Edit Listing",
"wishing": wishbool,
"modification":modification
})
thanks for help
form = NewListingForm(request.POST, request.FILES,instance=Listing.objects.get(pk=listing_id))
for getting the images or files you need pass another request that it's called request.FILES, so:
#login_required
def editlisting(request, listing_id):
obj = Listing.objects.filter(pk=listing_id).first()
if obj is None:
return render(request, "errors/404.html", {
"entryTitle": listing_id
})
else:
form = NewListingForm(instance=Listing.objects.get(pk=listing_id))
modification=True # used in template to check if modification are
allowed
# read only form if not author
user = request.user.id
if obj.author.id != user:
modification=False
# manage save
if request.method == "POST":
form = NewListingForm(request.POST, request.FILES,
instance=Listing.objects.get(pk=listing_id))
if form.is_valid():
form.save()
messages.success(request, 'listing saved') # message for
inform user of success - See messages in html file
return HttpResponseRedirect(reverse("index"))
# check if in wishes on get
wishbool=False
wish = Wishing.objects.filter(item=listing_id,
follower=request.user.id).first()
if wish is not None:
wishbool = True
return render(request, 'auctions/newListing.html', {
"form": form,
"existing": True,
'title': "Edit Listing",
"wishing": wishbool,
"modification":modification
})

Django Formset image.url Not Populated

I have an image field on a model that i'd like to render inside an img tag. It's inside of a formset and I can see the link to the image, but if I try to reference form.image.url nothing comes back. form.image returns "Current :" "" which breaks because of the leading string. How can get the images to display?
Stack
Django 2.1, django-storages using S3
Storages Settings
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
AWS_DEFAULT_ACL = 'None'
AWS_S3_REGION_NAME = "us-east-1"
AWS_LOCATION = "images"
AWS_STORAGE_BUCKET_NAME = 'fakebucketname'
MEDIA_URL = 'http://%s.s3.amazonaws.com/' % AWS_STORAGE_BUCKET_NAME
AWS_S3_HOST = 's3.us-east-1.amazonaws.com'
AWS_DEFAULT_ACL = None
Models
class Note(models.Model):
user = models.CharField(null=True, max_length=25)
image = models.ImageField(upload_to="%Y/%m/%d/")
text = models.TextField(verbose_name='Text', null=True)
pub_date = models.DateTimeField(auto_now_add=True)
report = models.ForeignKey(Report, on_delete=models.CASCADE, null=True)
def __str__(self):
return self.user
class Report(models.Model):
name = models.DateField(auto_now_add=True, unique=True, verbose_name='Report Name')
slug = models.SlugField(blank=True)
def __str__(self):
return str(self.name)
def __unicode__(self):
return u"%s" % self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
return super(Report, self).save(*args, **kwargs)
def get_absolute_url(self):
from django.urls import reverse
return reverse('report_detail', args=[str(self.id)])
Forms
from TheDaily.models import Report, Note
from django.forms import ModelForm, inlineformset_factory
class NoteForm(ModelForm):
def __init__(self, *args, **kwargs):
super(NoteForm, self).__init__(*args, **kwargs)
self.fields['image'].required = False
class Meta:
model = Note
exclude = ()
class ReportForm(ModelForm):
class Meta:
model = Report
fields = '__all__'
NoteFormset = inlineformset_factory(Report, Note, form=NoteForm, extra=1)
View
def manage_reports(request, pk):
class Media(object):
js = formset_media_js + (
)
report = Report.objects.get(pk=pk)
note_inline_form_set = inlineformset_factory(Report, Note, extra=2,
fields=('user', 'category', 'text', 'report', 'image'),
widgets={'text': forms.Textarea(attrs={'class': 'form-control'}),
'user': forms.TextInput(attrs={'class': 'form-control'}),
'image': forms.ClearableFileInput,
'category': forms.Select(attrs={'class': 'form-control'})})
if request.method == "POST":
formset = note_inline_form_set(request.POST, request.FILES, instance=report)
if formset.is_valid():
for form in formset:
form.cleaned_data['user'] = request.user.username
formset.save()
return HttpResponseRedirect('/')
else:
formset = note_inline_form_set(instance=report)
return render(request, 'daily/report.html', {'formset': formset})
Template
<form action="" method="post" enctype="multipart/form-data">{% csrf_token %}
{% load formset_tags %}
<div id="formset" data-formset-prefix="{{ formset.prefix }}">
{{ formset.management_form }}
<div data-formset-body>
<!-- New forms will be inserted in here -->
{% for form in formset %}
<div data-formset-form>
{{ form.as_p }}
<img id="image_preview"src="{{ form.image.url }}"/>
</div>
{% endfor %}
</div>
<!-- The empty form template. By wrapping this in a <script> tag, the
__prefix__ placeholder can easily be replaced in both attributes and
any scripts -->
<script type="form-template" data-formset-empty-form enctype="multipart/form-data">
{% escapescript %}
<div data-formset-form>
{{ formset.empty_form }}
</div>
{% endescapescript %}
</script>
<!-- This button will add a new form when clicked -->
<input type="button" value="Add another" data-formset-add class="btn btn-w-md btn-info">
<input type="submit" value="Submit" class="btn btn-w-md btn-accent"/>
<script>jQuery(function ($) {
$("#formset").formset({
animateForms: true
});
});</script>
</div>
</form>
Django ModelForm ImageField
I went with the 2nd option and made the NonClearableImageInput widget. Seems to be working well

Django class-based UpdateView

We are using Django 1.9.5. I am writing update company profile view. I want to have two fields on my update profile page:
company name,
apikey(generated with a dedicated function).
I want to change field name by hands and then save by clicking button Update. For filed apikey I want to have separated button which would automatically generate new key, save it to db and update my page.
I am overwriting post method at UpdateView class. But simething isn't working. Please take a look at my code:
models.py:
class Organization(models.Model):
name = models.CharField(_('organisation display name'), max_length=512,
blank=True)
apikey = models.CharField(_("API authentication key"), max_length=APIKEY_LENGTH,
default=get_apikey)
where get_apikey is
from django.utils.crypto import get_random_string
APIKEY_PREFIX = "key-"
APIKEY_LENGTH = 80
def get_apikey():
rnd_len = APIKEY_LENGTH - len(APIKEY_PREFIX)
return "{}{}".format(
APIKEY_PREFIX,
get_random_string(rnd_len, "abcdefghijklmnopqrstuvwxyz0123456789")
)
forms.py:
from django import forms
from crispy_forms.helper import FormHelper, Layout
from orgs.models import Organization
class OrgProfileForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(OrgProfileForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
class Meta:
model = Organization
fields = ['name', 'apikey']
views.py
from django.views.generic.edit import UpdateView, BaseUpdateView
from orgs.forms import OrgProfileForm
from orgs.models import Organization
from local.auth import get_apikey
class OrgProfileView(UpdateView):
model = Organization
template_name = 'orgs/orgprofile.html'
form_class = OrgProfileForm
url_name = 'profile'
success_url = '/'
def get_object(self, queryset=None):
org_obj = Organization.objects.get(orgname=self.kwargs["orgname"])
return org_obj
def post(self, request, *args, **kwargs):
import ipdb
ipdb.set_trace()
if '_key' in request.POST:
org_obj = Organization.objects.get(orgname=self.kwargs["orgname"])
org_obj.apikey = get_apikey()
org_obj.save()
self.object = org_obj
return super(BaseUpdateView, self).post(request, *args, **kwargs)
template.html
{% extends "base.html" %}
{% load i18n %}
{% load staticfiles %}
{% load crispy_forms_tags %}
{% block title %}{% trans "Organization profile" %}{% endblock title %}
{% block header_title %}{% trans "Organization profile" %}{% endblock header_title %}
{% block content %}
<form action="" method="post">{% csrf_token %}
{% crispy form %}
<input type="submit" value="{% trans 'Generate new key' %}" name="_key">
<input type="submit" value="{% trans 'Update form' %}" name="_update">
</form>
{% endblock content %}
Using _key and '_update' I want to differentiate between two buttons and actions update name and regenerate new apikey.
Ohh, I have found the way around. In post request for updating apikey I need to:
update apikey value in model and save it,
redirect back to get request
views.py
class OrgProfileView(UpdateView):
model = Organization
template_name = 'orgs/orgprofile.html'
form_class = OrgProfileForm
url_name = 'profile'
def get_object(self, queryset=None):
org_obj = Organization.objects.get(orgname=self.kwargs["orgname"])
return org_obj
def post(self, request, *args, **kwargs):
if '_key' in request.POST:
org_obj = Organization.objects.get(orgname=self.kwargs["orgname"])
org_obj.apikey = get_apikey()
org_obj.save()
self.object = org_obj
return super(BaseUpdateView, self).get(request, *args, **kwargs)
else:
self.object = self.get_object()
return super(BaseUpdateView, self).post(request, *args, **kwargs)