I try to understand how I can fill automatically the seller user field:
Assume I got private group with two users (one is consumer the other is seller)
Only consumer can have access to this form.
So form.instance.consumer = self.request.user works well.
form.instance.channel = self.object works well also.
In my forms I'm using crispy forms and it's only display two fields (rate and comment).
But my question is how I can get seller user? I'm beginning with Django :)
#Channel REVIEW
#method_decorator(login_required(login_url='/cooker/login'),name="dispatch")
class ChannelReview(generic.DetailView, FormMixin):
model = Channel
context_object_name = 'channel'
template_name = 'channel_review.html'
form_class = ChannelRatingForm
def get_context_data(self, **kwargs):
context = super(ChannelReview, self).get_context_data(**kwargs)
context['form'] = self.get_form()
return context
def form_valid(self, form):
if form.is_valid():
form.instance.channel = self.object
form.instance.seller = seller #### Here is my question
form.instance.consumer = self.request.user
form.save()
return super(ChannelReview, self).form_valid(form)
else:
return super(ChannelReview, self).form_invalid(form)
def post(self,request,*args,**kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_valid(form)
def get_success_url(self):
return reverse('channel:channel_detail',kwargs={"slug":self.object.slug})
def get(self,request,*args,**kwargs):
self.object = self.get_object()
if not (request.user == self.object.consumer or request.user == self.object.seller):
return HttpResponseRedirect('/')
return super(ChannelReview, self).get(request,*args,**kwargs)
class Channel(models.Model):
consumer = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="channel_consumer", blank=True, null=True)
name = models.CharField(max_length=10)
seller = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="channel_seller")
class Rating(models.Model):
channel = models.OneToOneField(Channel,on_delete=models.CASCADE,related_name="rating_channel")
consumer = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.CASCADE,related_name='rating_consumer')
seller = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.CASCADE,related_name='rating_seller')
is_rated = models.BooleanField('Already rated', default=True)
comment = models.TextField(max_length=200)
publishing_date = models.DateTimeField(auto_now_add=True)
ratesugar = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)])
You can use the .update to update a model object, like this in case.
https://www.kite.com/python/examples/5166/django-models-update-a-model-object-without-loading-the-object-from-the-database
Related
I am trying to add more lines on the inline formset factory using the same methodology that I used before on a formset factory but is getting an error:
MultiValueDictKeyError form-TOTAL_FORMS'
models.py:
class ttransactions(models.Model):
transaction_type = models.CharField(max_length=10, choices=tx_choices)
description = models.CharField(max_length=50, null=False, blank=False, default='Description')
transaction_date = models.DateField(default=datetime.today, db_index=True)
company = models.ForeignKey(tcompany, on_delete=models.PROTECT, db_index=True)
def __str__(self):
return self.description
class ttransaction_lines(models.Model):
transaction = models.ForeignKey(ttransactions, on_delete=models.PROTECT, db_index=True)
sequence = models.IntegerField()
transaction_type = models.CharField(max_length=6, choices=debit_credit)
ledger_account = models.ForeignKey(tledger_account, on_delete=models.PROTECT, db_index=True)
amount = models.DecimalField(max_digits=14, decimal_places=2, default=0.0)
vat_amount = models.DecimalField(max_digits=14, decimal_places=2, default=0.0)
vat_code = models.ForeignKey(tvat, on_delete=models.PROTECT, blank=True, null=True)
quantity = models.IntegerField(blank=True, null=True)
posted = models.BooleanField(default=True)
forms.py:
class TransactionsForm(forms.ModelForm):
transaction_date = forms.DateField(widget=forms.SelectDateWidget(years=year_range), initial=datetime.today)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super(TransactionsForm, self).__init__(*args, **kwargs)
class Meta:
model = ttransactions
fields = ['description',
'transaction_date']
class TransactionLinesForm(forms.ModelForm):
class Meta:
model = ttransaction_lines
fields = ['transaction_type', 'ledger_account', 'amount']
class BaseTransactionLinesFormSet(BaseModelFormSet):
def clean(self):
super(BaseTransactionLinesFormSet, self).clean()
# Check errors dictionary first, if there are any error, no point in validating further
if any(self.errors):
return
balance = 0
for form in self.forms:
if form.cleaned_data['DELETE'] == True or form.cleaned_data['DELETE'] == '':
continue
if form.cleaned_data['transaction_type']=='Debit':
balance = balance + form.cleaned_data['amount']
else:
balance = balance - form.cleaned_data['amount']
if balance != 0:
message = 'Transactions not balanced (excluding deleting lines)'
raise forms.ValidationError(message)
TransactionLineFormset = inlineformset_factory(ttransactions,
ttransaction_lines,
form=TransactionLinesForm,
can_order=True, can_delete=True)
views.py
class JournalCreateView(LoginRequiredMixin, CreateView):
template_name = 'accounting/journal.html'
model = ttransactions
formset = TransactionLineFormset
form_class = TransactionsForm
success_url = '/accounting/transaction_list'
def get_form_kwargs(self):
kwargs = super(JournalCreateView, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
formset = TransactionLineFormset(queryset=ttransaction_lines.objects.none())
formset.form.base_fields['ledger_account'].queryset = \
tledger_account.objects.filter(company=request.user.current_company)
return self.render_to_response(
self.get_context_data(form=form, formset=formset))
def post(self, request, *args, **kwargs):
extra_forms = 1
if 'additems' in request.POST and request.POST['additems'] == 'true':
formset_dictionary_copy = self.request.POST.copy()
formset_dictionary_copy['form-TOTAL_FORMS'] = \
int(formset_dictionary_copy['form-TOTAL_FORMS']) + extra_forms
formset = TransactionLineFormSet(formset_dictionary_copy)
return self.render_to_response(
self.get_context_data(form=form,
formset=formset))
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
formset = TransactionLineFormset(self.request.POST)
if (form.is_valid() and formset.is_valid()):
return self.form_valid(form, formset)
else:
return self.form_invalid(form, formset)
def form_valid(self, form, formset):
form.instance.company = self.request.user.current_company
self.object = form.save()
sequence = 1
for line in formset:
line.instance.sequence = sequence
sequence += 1
formset.instance = self.object
formset.save()
return super().form_valid(form)
def form_invalid(self, form, formset):
return self.render_to_response(
self.get_context_data(form=form,
formset=formset))
I get the error on the line that dictionary copy line. The code for adding the line is added in the post function. I am not sure if that is the correct place to add this code. Help will be appreciated.
This error occurs if the form submitted is missing the key.
The .get() method allows for a default when accessing a missing key in a dict.
formset_dictionary_copy['form-TOTAL_FORMS'] = \
int(formset_dictionary_copy.get('form-TOTAL_FORMS', 1)) + extra_forms
It appears that, the formset is not getting all it's hidden values or a different form is submitted.
I would consider a frontend solution or sending a single initial formset with the add button values.
A frontend / js example:
https://www.brennantymrak.com/articles/django-dynamic-formsets-javascript
As a newbie in Django, I'm sure there is something obvious I'm not seeing. I have a user model with a one to one relationship to a userprofile model, where I'm storing the profile photo. I mixed DetailView and Formview because I want the user to go to his details page and update just the photo, but somehow its not working for me. I know I could do the job with UpdateView, but for didactic purposes, can anyone tell me why this is not working? I'm trying to updated the model fields in the form_valid method but this is not working, they just remain with the old values. I thought at the beginning it was the photo that could not be updated because of some errors on my side, but I've tried also updating other string fields and it doesnt work. Here the code: (the commented out fields are the places where I tried updating several model fields using get_object_or_404 and other functions)
class UserDetail(FormMixin, DetailView):
template_name = "users/user_detail.html"
model = User
form_class = forms.UserPhotoForm
def get_success_url(self):
return reverse('users:user_detail', args=[str(self.get_object().pk)])
def get_context_data(self, **kwargs):
user = self.get_object()
form = forms.UserPhotoForm(instance=user)
context = super().get_context_data(**kwargs)
context['user_rating'] = CotizacionReview.objects.filter(cotizacion__user=self.get_object()).aggregate(Avg('nota'))
context['form'] = form
return context
def form_valid(self, form):
form.save()
return super(UserDetail, self).form_valid(form)
def post(self, request, *args, **kwargs):
a = get_object_or_404(User, pk=self.get_object().id).userprofile
form = forms.UserPhotoForm(request.FILES['avatar'], instance=a)
# get_object_or_404(User, pk=self.get_object().id).apellido = '1234'
if form.is_valid():
# print(get_object_or_404(User, pk=self.get_object().id).userprofile.avatar)
# I tried updating several model fields here, but didnt work
# print(request.FILES['avatar'])
return self.form_valid(form)
else:
return self.form_invalid(form)
Here the model:
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
avatar = models.ImageField(upload_to='profile_pics', default='profile_pics/default-user-icon-4.jpg', blank=True)
telefono = models.CharField(max_length=12, blank=True)
nombre = models.CharField(max_length=64, blank=True)
apellido = models.CharField(max_length=64, blank=True)
link = models.CharField(max_length=256, blank=True)
educacion = models.CharField(max_length=256, blank=True)
experiencia = models.TextField(max_length=512, blank=True)
birthdate = models.DateField(blank=True, null=True)
#receiver(post_save, sender=User)
def update_profile_signal(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
So I achieved it by using commit=False in my form_valid method:
class UserDetail(FormMixin, DetailView):
template_name = "users/user_detail.html"
model = User
form_class = forms.UserPhotoForm
def get_success_url(self):
return reverse('users:user_detail', args=[str(self.get_object().pk)])
def get_context_data(self, **kwargs):
user = self.get_object()
form = forms.UserPhotoForm(instance=user)
context = super().get_context_data(**kwargs)
context['user_rating'] = CotizacionReview.objects.filter(cotizacion__user=self.get_object()).aggregate(Avg('nota'))
context['form'] = form
return context
def form_valid(self, form):
user_instance = form.save(commit=False)
user_instance.avatar = form.cleaned_data['avatar']
user_instance.id = self.get_object().userprofile.id
user_instance.save(update_fields=['avatar'])
return super(UserDetail, self).form_valid(form)
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
But now I have another problem. Every time I update the photo, a new photo is saved to the database. Is there a way of doing this and deleting the old photo? or replacing it?
I got a question I did not solved. I try to create a chat with the author of the post. But I got an issue when I tried to catch him directly with form instance:
I've created a form with crispy form without field. All field are passed with form.instance. I really thank you in advance.
#Post detail
class PostDetail(generic.DetailView,FormMixin):
model = Cuisine
context_object_name = 'post'
template_name = 'post_detail.html'
form_class = CreateChannelForm
def get_context_data(self, **kwargs):
context = super(PostDetail, self).get_context_data(**kwargs)
context['cuisine_user'] = Cuisine.objects.get(pk=user_id)
context['form'] = self.get_form()
return context
def form_valid(self, form):
if form.is_valid():
form.instance.post = self.object
form.instance.usera = self.request.user
form.instance.userb = cuisine_user #Here is the error
form.save()
return super(PostDetail, self).form_valid(form)
else:
return super(PostDetail, self).form_invalid(form)
I got private space:
class Channel(models.Model):
usera = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="channel_usera")
userb = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="channel_userb")
post = models.ForeignKey(Cuisine,on_delete=models.CASCADE,related_name="channel_post")
date_created = models.DateTimeField(auto_now_add=True, null=True)
is_active = models.BooleanField('', default=False)
slug = models.SlugField(editable=False,unique=True)
Here is the model of the post:
class Cuisine(models.Model):
#Remplir manuellement
title = models.CharField(max_length=90)
user = models.ForeignKey(User,on_delete=models.CASCADE,related_name='cuisine_user')
image = models.ImageField(upload_to='nutriscore/')
description = models.TextField(max_length=1000, blank=True)
In order to get userb:
def get_context_data(self, **kwargs):
context = super(PostDetail, self).get_context_data(**kwargs)
context['form'] = self.get_form()
return context
def form_valid(self, form):
if form.is_valid():
form.instance.post = self.object
form.instance.usera = self.request.user
form.instance.userb = self.get_object().user #Here is the change
form.save()
return super(PostDetail, self).form_valid(form)
else:
return super(PostDetail, self).form_invalid(form)
I got this error when I'm trying to submit data in my view. Masjid is taking data from a specific login user. I cannot understand where the error is coming because my form allow my to view the specific user.
form = ImamForm(request.POST, instance=masjid)
error message is coming from that line
forms.py
class ImamForm(forms.ModelForm):
def __init__(self,user, *args, **kwargs):
super(ImamForm, self).__init__(*args, **kwargs)
try:
masjid_id = Info.objects.values_list('user_id', flat=True).get(user=user)
self.fields['masjid'].queryset = Info.objects.filter(user=masjid_id)
print(masjid_id)
except Info.DoesNotExist:
### there is not userextend corresponding to this user, do what you want
pass
class Meta:
model = Imam
exclude = ('updated_at', 'created_at', 'user')
views.ppy
class NewImam(CreateView):
# template_name = "addimam.html"
# model = Imam
# form_class = ImamForm
# #success_url = reverse_lazy('person_changelist')
# def form_valid(self, form):
# #if not UserProfile.objects.filter(recruiter=self.request.user).exists():
# p = form.save(commit=False)
# p.user = self.request.user
# p.save()
# messages.success(self.request, 'The Imam Details Has Been Added Successully!')
# return redirect('addimam')
# # else:
# # messages.warning(self.request, 'The Profile has been Added Before!')
# # return redirect('recruiter:edit_recruiter_profile')
def get(self, request, *args, **kwargs):
form = ImamForm(user=self.request.user)
context = {'form': form}
return render(request, 'addimam.html', context)
def post(self, request, *args, **kwargs):
user = self.request.user
print(user)
user = CustomUser.objects.get(email=user)
masjid = user.id
print(type(masjid))
form = ImamForm(request.POST, instance=masjid)
print(form)
if form.is_valid():
p = form.save(commit=False)
p.user = self.request.user
p.save()
messages.success(self.request, 'The Project Details Has Been Added Successully!')
return redirect('addimam')
return render(request, 'addimam.html', {'form': form})
models.py
class Imam(models.Model):
CERTIFICATE = (
('PhD', 'PhD'),
('MSc', 'MSc'),
('Bsc', 'Bsc'),
)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
masjid = models.ForeignKey(Info, related_name='imam', on_delete=models.CASCADE)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
imam_address = models.TextField(blank=False, null=False)
phone_no = models.CharField(max_length=20)
certificate = models.CharField(max_length=50, choices=CERTIFICATE)
occupation = models.CharField(max_length=50, blank=False, null=False)
no_of_wives = models.IntegerField(blank=False, null=False)
no_of_children = models.IntegerField(blank=False, null=False)
created_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
Since you have override the __init__(...) method, Django expects the arguments in the different order.
So change
form = ImamForm(request.POST, instance=masjid)
to
form = ImamForm(masjid,request.POST)
I'm developing the web site where users can register and edit their information. I would like to use multi form in the single page. I can develop register form using CreateView. But when I use UpdateVIew, I don't know how to add initial value in multi form.
My code(view.py) is below. I can add form data as initial value, but not form2. Please tell me how to add form2 data as initial value.
▪️view.py
class UserUpdate(OnlyYouMixin, generic.UpdateView):
model = Profile
form_class = ProfileForm
second_form_class = ProfileNearStationForm
template_name = 'accounts/user_form.html'
def get_context_data(self, **kwargs):
context = super(UserUpdate, self).get_context_data(**kwargs)
if 'form' not in context:
context['form'] = self.form_class(self.request.GET, instance=self.request.user)
if 'form2' not in context:
context['form2'] = self.second_form_class(self.request.GET, instance=self.request.user)
return context
def get(self, request, *args, **kwargs):
super(UserUpdate, self).get(request, *args, **kwargs)
form = self.form_class
form2 = self.second_form_class
return self.render_to_response(self.get_context_data())
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.form_class(request.POST, instance=self.request.user)
form2 = self.second_form_class(request.POST, instance=self.request.user)
if form.is_valid() and form2.is_valid():
profile = form.save(commit=False)
profile.save()
station = form2.save(commit=False)
station.user = user
station.save()
messages.success(self.request, 'Settings saved successfully')
return HttpResponseRedirect(self.get_success_url())
else:
return self.render_to_response(
self.get_context_data(form=form, form2=form2))
def get_success_url(self):
return resolve_url('accounts:user_form', pk=self.kwargs['pk'])
▪️form.py
class ProfileForm(forms.ModelForm):
name = forms.CharField(required=True)
tel_number = forms.CharField(required=True)
class Meta:
model = Profile
fields = ('name', 'tel_number')
class ProfileNearStationForm(forms.ModelForm):
prefecture = forms.ModelChoiceField(queryset=areas_model.Prefecture.objects.all(), required=True)
railway = forms.ModelChoiceField(queryset=areas_model.Railway.objects.none(), required=True)
station = forms.ModelChoiceField(queryset=areas_model.Station.objects.none(), required=True)
memo = forms.CharField(required=False)
class Meta:
model = ProfileNearStation
fields = ('prefecture', 'railway', 'station', 'memo')
▪️model.py
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=255)
tel_number = models.CharField(max_length=13)
class ProfileNearStation(models.Model):
prefecture = models.ForeignKey(areas_model.Prefecture, on_delete=models.CASCADE)
railway = models.ForeignKey(areas_model.Railway, on_delete=models.CASCADE)
station = models.ForeignKey(areas_model.Station, on_delete=models.CASCADE)
memo = models.CharField(max_length=255, null=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)