Django model : save object with custom field - django

I would like to know how I can do that : save an object in my database through Django model with custom field.
This is my modelclass :
class Document(EdqmTable):
language = models.CharField(max_length=2, verbose_name=_('language'), choices=LANGUAGE_CHOICES, null=False)
format = models.CharField(max_length=10, verbose_name=_('format'), choices=FORMAT_CHOICES, null=False)
title = models.CharField(max_length=512, verbose_name=_('document title'), null=False)
publication = models.ForeignKey(Publication, verbose_name=_('publication title'), null=False,
related_name='documents')
class Meta:
verbose_name = _('document')
verbose_name_plural = _('documents')
def save(self, *args, **kwargs):
self.title = f"{self.publication.pub_id}-{self.format.upper()}"
super(Document, self).save(*args, **kwargs)
I have a save method, which let to define my field title with combination between two fields.
title field is hidden in my django form and is set automatically by Django.
But, up to now, it doesn't work because my object is not saved into my database. Something is wrong in my save function ?
EDIT :
I edited my post with forms.py file and my view :
The field document.title is used in my django forms with formset like this :
class PublicationForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['category'].empty_label = _('Select a category') # Modify initial empty_label
class Meta:
model = Publication
fields = ['title', 'pub_id', 'category']
class DocumentForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(DocumentForm, self).__init__(*args, **kwargs)
self.fields['title'].widget = forms.HiddenInput()
for key in self.fields:
self.fields[key].required = True
class Meta:
model = Document
fields = ['publication', 'language', 'format', 'title', 'upload']
DocumentFormSet = inlineformset_factory(Publication, Document, form=DocumentForm, extra=1)
And my view according to this part :
class PublicationCreateView(EdqmCreateView):
""" Create publication with document form through formset """
model = Publication
template_name = 'freepub/publication_form.html'
def get_context_data(self, **kwargs):
context = super(PublicationCreateView, self).get_context_data(**kwargs)
context['document_form'] = DocumentFormSet(self.request.POST or None, self.request.FILES or None)
return context
def form_valid(self, form):
context = self.get_context_data()
document = context['document_form']
if document.is_valid():
self.object = form.save()
document.instance = self.object
document.save()
return super(PublicationCreateView, self).form_valid(form)
def get_success_url(self):
return reverse('publication-list-crud')

Related

How to get rid of redundant requests ord django

class Post(models.Model):
cat_post = models.ForeignKey(Category, on_delete=models.CASCADE, blank=True,null=True)
top_post = models.ForeignKey(TopicsCategory, on_delete=models.CASCADE, blank=True,null=True)
sub_post = models.ForeignKey(SubTopicsCategory, on_delete=models.CASCADE, blank=True,null=True)
class CreatePostView(CreateView):
model = Post
template_name = 'blog/create.html'
form_class = CreatePostForm
def get_context_data(self, *args, **kwards):
print(self.kwargs)
context = super(CreatePostView, self).get_context_data(**kwards)
context['btn'] = 'Add'
return context
def form_valid(self, form, *args, **kwargs):
if self.kwargs.get('category_slug') and len(self.kwargs) == 1:
category = Category.objects.get(slug=self.kwargs['category_slug'])
form.instance.cat_post = category
return super(CreatePostView, self).form_valid(form)
# передача в форму kwargs view
def get_form_kwargs(self):
kwargs = super(CreatePostView, self).get_form_kwargs()
kwargs.update({'view_kwargs': self.kwargs})
return kwargs
def get_success_url(self):
return reverse('topics_category_list', kwargs={'category_slug': self.kwargs['category_slug'], })
class CreatePostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['name', 'text', 'discussion']
# widgets = {
# 'cat_post': forms.HiddenInput(),
# }
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("view_kwargs")
super(CreatePostForm, self).__init__(*args, **kwargs)
def clean_name(self):
name = self.cleaned_data['name']
if self.request.get('category_slug') and len(self.request) == 1:
category = Category.objects.get(slug=self.request['category_slug'])
unique = Post.objects.filter(slug=slugify(self.cleaned_data['name']), cat_post=category.pk,discussion=False).exists()
if unique:
raise ValidationError(f'Post is not unique')
return name
**
I have duplicate sources in db here form_valid and clean_name.
How do I pass the form in the view form form_valid class instance that I got from the database to clean_name.
There will be posts for 2 models and requests will increase

modelForm instance not coming through

I'm passing an instance of a model into a modelForm, but, within the view, when I print the form, the values within the model don't show up. Also, when the form is rendered on my template, the values from the instance don't show up.
Views.py
def support_ticket_view(request, id=None):
id = int(id)
instance = SupportTicket.objects.get(id=id, user=user)
form = SupportTicketEditForm(request.POST or None, request.FILES or None, instance=instance)
context = {
'form': form,
}
return render(request, 'accounts/support_ticket_view.html', context)
forms.py
class SupportTicketEditForm (forms.ModelForm):
def __init__(self, *args, **kwargs):
self.instance = kwargs.pop('instance',None)
super(SupportTicketEditForm, self).__init__(*args, **kwargs)
class Meta:
model = SupportTicket
fields = (
'image',
'body_question',
'urgency',
'question_type',
'status',
)
widgets = {
'image': ImageThumbnailFileInput
}
models.py
class SupportTicket(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
question = models.TextField(max_length=10000, null=True, blank=False)
def __str__(self):
return self.user.username
Removed the following:
def __init__(self, *args, **kwargs):
self.instance = kwargs.pop('instance',None)
super(SupportTicketEditForm, self).__init__(*args, **kwargs)
Thanks Daniel Roseman!

I want to dynamically change the form of django according to user information

Although it is in the title, I want to change the form dynamically with django.
But now I get an error.
I can't deal with it.
I was able to get user information, but if I filter it, it will be “cannot unpack non-iterable UPRM object”.
#forms.py
class RecordCreateForm(BaseModelForm):
class Meta:
model = URC
fields = ('UPRC','URN','UET','URT',)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(RecordCreateForm,self).__init__(*args, **kwargs)
for field in self.fields.values():
field.widget.attrs['class'] = 'form-control'
self.fields['URN'].choices = UPRM.objects.filter(user=user)
#views.py
class RecordCreate(CreateView):
model = URC
form_class = RecordCreateForm
template_name = 'records/urcform.html'
success_url = reverse_lazy('person:home')
def get_form_kwargs(self):
kwargs = super(RecordCreate, self).get_form_kwargs()
# get users, note: you can access request using: self.request
kwargs['user'] = self.request.user
return kwargs
#models
class UPRM(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
URN = models.CharField( max_length=30,editable=True)
def __str__(self):
return self.URN
class URC(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
UPRC = models.CharField(max_length=300)
URN = models.ForeignKey(UPRM, on_delete=models.CASCADE)
def __str__(self):
return self.UPRC
cannot unpack non-iterable UPRM object
You should use queryset instead of choices here:
class RecordCreateForm(BaseModelForm):
class Meta:
model = URC
fields = ('UPRC','URN','UET','URT',)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(RecordCreateForm,self).__init__(*args, **kwargs)
for field in self.fields.values():
field.widget.attrs['class'] = 'form-control'
self.fields['URN'].queryset = UPRM.objects.filter(user=user)

Django - UpdateView with multi model forms - one submit

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)

Display auth.User fields in related model

I have created this Django model:
class Teacher(models.Model):
user = models.OneToOneField('auth.User', on_delete=models.CASCADE, default=1)
surname = models.CharField(max_length=15, null=True)
creation_date = models.DateTimeField('creation date', auto_now_add=True)
deletion_date = models.DateTimeField('deletion date', null=True, blank=True)
and a form to represent it in read-only mode:
class TeacherViewForm(ModelForm):
def __init__(self, *args, **kwargs):
super(TeacherViewForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if instance and instance.pk:
for field in self.fields:
self.fields[field].widget.attrs['disabled'] = True
class Meta:
model = Teacher
exclude = ['deletion_date']
The view looks like this:
class TeacherViewDetail(generic.DetailView):
model = Teacher
template_name = 'control/teacher_detail.html'
form_class = TeacherViewForm
def get_form(self):
# Instantiate the form
form = self.form_class(instance=self.object)
return form
def get_context_data(self, **kwargs):
context = super(TeacherViewDetail, self).get_context_data(**kwargs)
context.update({
'form': self.get_form(),
})
return context
As you can see, there is a OneToOne relation between the Teacher and the auth.User models. I need to displayfirst_name and last_name from auth.User model, but only the username is shown.
How can I display these fields the same way field Teacher.surname is being displayed?
Do I have to include them in the model, the form.fields or is there a property I have to modify in order to achieve it?
Thanks
You would have to remove the user field and add the appropriate fields instead. Then in your form's __init__, fill the initial values:
# forms.py
class TeacherViewForm(ModelForm):
first_name = forms.CharField()
last_name = forms.CharField()
def __init__(self, *args, **kwargs):
super(TeacherViewForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if instance and instance.pk:
for field in self.fields:
self.fields[field].widget.attrs['disabled'] = True
# set initial values
self.fields['first_name'].initial = instance.user.first_name
self.fields['last_name'].initial = instance.user.last_name
class Meta:
model = Teacher
exclude = ['user', 'deletion_date'] # exclude user
But why do you use a form at all if you disable all fields? You can just render all this information much more freely in the template.