submit form as superuser vs regular user - python

In my django app I have a Myuser(User) class. It inherits the User class.
When a new user is created the Myuser table is poplulated.
myusers.py
class Myuser(User):
address = models.CharField(max_length=40)
pobox = models.CharField(max_length=40)
models.py
class Someclass(models.Model):
objectid = models.IntegerField()
objecttype = models.CharField(max_length=200)
created = models.DateTimeField(default=timezone.now)
modified = models.DateTimeField(auto_now=True)
class Someotherclass(Someclass):
status = models.IntegerField(default=0,)
name = models.CharField(max_length=200)
created = models.DateTimeField(default=timezone.now)
modified = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User)
forms.py
class SomeotherclassForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request")
self.user = kwargs.pop('user')
self.app = kwargs.pop('app')
self.table = kwargs.pop('table')
self.mytype = kwargs.pop('mytype')
initial = kwargs.get('initial', {})
super(SomeotherclassForm, self).__init__(*args, **kwargs)
create.py
class DataCreate(CreateView):
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
#some code here not relevant at all
def get_form_kwargs(self):
kwargs = super(DataCreate, self).get_form_kwargs()
objectid = self.request.GET.get('objectid',None)
objecttype = self.request.GET.get('objecttype',None)
kwargs.update({'mytype': objecttype})
kwargs.update({'request': self.request})
kwargs.update({'user': self.request.user})
kwargs.update({'app': self.app})
kwargs.update({'table': self.kwargs['table'].lower()})
return kwargs
def form_valid(self, form):
obj = form.save(commit=False)
group = ''
if not self.request.user.is_superuser:
group = MyUser.objects.get(user_ptr_id=self.request.user.pk)
else:
groups = self.request.user.groups.all()
if self.kwargs['table'] == 'Myprotocol':
obj = form.save(commit=False)
table = eval(self.request.GET.get('objecttype',None).title()).objects.get(pk=int(self.request.GET.get('objectid',None)))
obj.objectid = table.pk
obj.objecttype = table.__class__.__name__.lower()
obj.user_id = self.request.user.pk
obj.save()
else:
obj = form.save()
if self.request.POST.get('is_popup'):
check = int(self.kwargs['is_list'])
if self.kwargs['table'] == 'Someclass':
popup = 1
a = checkPopup2(obj,check,popup,obj.pk)
else:
a = checkPopup(obj,check)
return a
else:
return super(DataCreate, self).form_valid(form)
When I have logged in as a regular user ,everything works fine.
When I log in as a superuser, I get form error that objecttype,objectid and user are not filled.
In my attempts to troubleshoot it , I realized that when I am logged in as a superuser ,it dowsn't reach the form_valid() function.
I can't figure out why that is happening.
Any suggestions or advice on how to troubleshoot it?

Related

Custom django inlineformset validation based on user permissions

The objective is to have a simple workflow where an order and associated orderlines (created in a previous step) needs to be approved by the relevant budget holder. The approval form shows all order lines but disables those lines that the current user is not associated with (they should be able to see the overall order but only be able to edit lines that they are permitted to). They should be able to add new lines if necessary. The user needs to decide whether to approve or not (approval radio cannot be blank)
The initial form presents correctly and is able to save inputs correctly when all values are inputted correctly - however, if it fails validation then the incorrect fields get highlighted and their values are cleared.
models.py
class Order(models.Model):
department = models.ForeignKey(user_models.Department, on_delete=models.CASCADE)
location = models.ForeignKey(location_models.Location, on_delete=models.CASCADE, null=True)
description = models.CharField(max_length=30)
project = models.ForeignKey(project_models.Project, on_delete=models.CASCADE)
product = models.ManyToManyField(catalogue_models.Product, through='OrderLine', related_name='orderlines')
total = models.DecimalField(max_digits=20, decimal_places=2, null=True, blank=True)
def __str__(self):
return self.description
class OrderLine(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
project_line = models.ForeignKey(project_models.ProjectLine, on_delete=models.SET_NULL, null=True, blank=False)
product = models.ForeignKey(catalogue_models.Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField()
price = models.DecimalField(max_digits=20, decimal_places=4)
total = models.DecimalField(max_digits=20, decimal_places=2)
budgetholder_approved = models.BooleanField(null=True)
def get_line_total(self):
total = self.quantity * self.price
return total
def save(self, *args, **kwargs):
self.total = self.get_line_total()
super(OrderLine, self).save(*args, **kwargs)
def __str__(self):
return self.product.name
views.py
class BudgetApprovalView(FlowMixin, generic.UpdateView):
form_class = forms.BudgetHolderApproval
def get_object(self):
return self.activation.process.order
def get_context_data(self, **kwargs):
data = super(BudgetApprovalView, self).get_context_data(**kwargs)
if self.request.POST:
data['formset'] = forms.OrderLineFormet(self.request.POST, instance=self.object)
else:
data['formset'] = forms.OrderLineFormet(instance=self.activation.process.order, form_kwargs={'user': self.request.user})
return data
def post(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
form = forms.BudgetHolderApproval(self.request.POST, instance=self.activation.process.order)
formset = forms.OrderLineFormet(self.request.POST, instance=self.activation.process.order)
if form.is_valid() and formset.is_valid():
return self.is_valid(form, formset)
else:
return self.is_invalid(form, formset)
def is_valid(self, form, formset):
self.object = form.save(commit=False)
self.object.created_by = self.request.user
self.activation.process.order = self.object
with transaction.atomic():
self.object.save()
self.activation.done()
formset.save()
return HttpResponseRedirect(self.get_success_url())
def is_invalid(self, form, formset):
return self.render_to_response(self.get_context_data(form=form, formset=formset))
I have tried a couple of things to figure this out - without success:
to override the clean() method of the ModelForm - however, I cannot figure out how to determine if the submitted form is disabled or not.
forms.py
class OrderForm(forms.ModelForm):
class Meta:
model = models.Order
fields = ['description', 'project', 'location']
def __init__(self, *args, **kwargs):
super(OrderForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
class OrderLine(forms.ModelForm):
class Meta:
model = models.OrderLine
exclude = ['viewflow']
def __init__(self, *args, **kwargs):
YES_OR_NO = (
(True, 'Yes'),
(False, 'No')
)
self.user = kwargs.pop('user', None)
super(OrderLine, self).__init__(*args, **kwargs)
self.fields['project_line'].queryset = project_models.ProjectLine.objects.none()
self.fields['budgetholder_approved'].widget = forms.RadioSelect(choices=YES_OR_NO)
if self.instance.pk:
self.fields['budgetholder_approved'].required = True
self.fields['order'].disabled = True
self.fields['project_line'].disabled = True
self.fields['product'].disabled = True
self.fields['quantity'].disabled = True
self.fields['price'].disabled = True
self.fields['total'].disabled = True
self.fields['budgetholder_approved'].disabled = True
if 'project' in self.data:
try:
project_id = int(self.data.get('project'))
self.fields['project_line'].queryset = project_models.ProjectLine.objects.filter(project_id=project_id)
except (ValueError, TypeError):
pass
elif self.instance.pk:
self.fields['project_line'].queryset = self.instance.order.project.projectline_set
project_line_id = int(self.instance.project_line.budget_holder.id)
user_id = int(self.user.id)
if project_line_id == user_id:
self.fields['budgetholder_approved'].disabled = False
self.helper = FormHelper()
self.helper.template = 'crispy_forms/templates/bootstrap4/table_inline_formset.html'
self.helper.form_tag = False
def clean(self):
super(OrderLine, self).clean()
pprint(vars(self.instance))
//This just returns a list of fields without any attributes to apply the validation logic
OrderLineFormet = forms.inlineformset_factory(
parent_model=models.Order,
model=models.OrderLine,
form=OrderLine,
extra=2,
min_num=1
)
to override the clean() method of the BaseInlineFormSet - however, I cannot disable the fields in the init or any of the validation rules (it silently fails validation and presents a blank inlineformset on failure - it never gets to clean() method.
forms.py
class OrderForm(forms.ModelForm):
class Meta:
model = models.Order
fields = ['description', 'project', 'location']
def __init__(self, *args, **kwargs):
super(TestOrderForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
class BaseTestOrderLine(forms.BaseInlineFormSet):
def __init__(self, user, *args, **kwargs):
self.user = user
super(BaseTestOrderLine, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.template = 'crispy_forms/templates/bootstrap4/table_inline_formset.html'
self.helper.form_tag = False
// Never gets to the clean method as is_valid fails silently
def clean(self):
super(BaseTestOrderLine, self).clean()
if any(self.errors):
pprint(vars(self.errors))
return
OrderLineFormet = forms.inlineformset_factory(
parent_model=models.Order,
model=models.OrderLine,
formset=BaseTestOrderLine,
exclude=['order'],
extra=2,
min_num=1
)
Edit - reflecting progress based on Dao's suggestion (the form reloads correctly with the validation errors showing correctly)
The only remaining problem is that when the form reloads - the field (budgetholder_approved) that should still be enabled is disabled. One of the two approval checkbox lines lines should be editable
Looks like because you have different formset context data on submit invalid
if self.request.POST:
data['formset'] = forms.OrderLineFormet(self.request.POST, instance=self.activation.process.order, form_kwargs={'user': self.request.user})
else:
data['formset'] = forms.OrderLineFormet(instance=self.activation.process.order, form_kwargs={'user': self.request.user})
return data
Edit for updated Q:
Didn't test this out because of time constraint but because you already initiated the field and overwrite the widget, so if you need to update disabled attr of widget instead of field.
self.fields['budgetholder_approved'].widget = forms.RadioSelect(choices=YES_OR_NO)
self.fields['budgetholder_approved'].widget.attrs['disabled'] = False

Django createView passing current user_id to Modelform

I am trying to make a calendar app and currently trying to stop people from being about to save an event when they are already busy during that time period. I believe my issue is that the modelForm doesn't have the user_id as part of the form object. how can I pass the user_id so I can use it to filter with the clean().
I tried using get_form_kwargs() but this doesn't seem to be the correct route to take.
Please can you point me in the right direction of how to do this.
view.py
class CalendarEventAdd(LoginRequiredMixin, CreateView):
model = Event
form_class = EventForm
template_name = 'calendar_create_event_form.html'
success_url = reverse_lazy('calendar_list')
def form_valid(self, form):
form.instance.manage = self.request.user
return super(CalendarEventAdd, self).form_valid(form)
def get_form_kwargs(self, *args, **kwargs):
kwargs = super(CalendarEventAdd, self).get_form_kwargs()
kwargs['user_id'] = self.request.user
return kwargs
form.py
class EventForm(forms.ModelForm):
class Meta:
model = Event
widgets = {
'start_time': DateInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M'),
'end_time': DateInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M'),
}
fields = ['avilibility','start_time','end_time']
def __init__(self, *args, **kwargs):
super(EventForm, self).__init__(*args, **kwargs)
# input_formats parses HTML5 datetime-local input to datetime field
self.fields['start_time'].input_formats = ('%Y-%m-%dT%H:%M',)
self.fields['end_time'].input_formats = ('%Y-%m-%dT%H:%M',)
def clean(self, *args, **kwargs):
form_start_time = self.cleaned_data.get('start_time')
form_end_time = self.cleaned_data.get('end_time')
form_manage_id = self.cleaned_data.get('manage_id')
between = Event.objects.filter(manage_id=1, end_time__gte=form_start_time, start_time__lte=form_end_time)
if between:
raise forms.ValidationError('Already Calendar entry for this time')
super().clean()
model.py
class Event(models.Model):
avilibility_choices = [
('Avilible', 'Avilible'),
('Busy', 'Busy'),
]
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
manage = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
avilibility = models.CharField(max_length=10, choices=avilibility_choices, editable=True)
start_time = models.DateTimeField()
end_time = models.DateTimeField()
def __str__(self):
return self.avilibility + " - " + str(self.start_time) + " - " + str(self.end_time) + " - " +str(self.id)
def get_absolute_url(self):
return reverse('calendar_event_detail', args=[str(self.id)])
def get_absolute_url_edit(self):
return reverse('calendar_event_detail_update', args=[str(self.id)])
def get_html_url(self):
url = reverse('event_edit', args=(self.id,))
return f' {self.avilibility} '
In your view, you should pass the primary key of the user, so:
def get_form_kwargs(self, *args, **kwargs):
kwargs = super(CalendarEventAdd, self).get_form_kwargs()
kwargs['user_id'] = self.request.user.pk
return kwargs
You can save it in the EventForm object:
class EventForm(forms.ModelForm):
def __init__(self, *args, user_id=None, **kwargs):
super(EventForm, self).__init__(*args, **kwargs)
self.user_id = user_id
# input_formats parses HTML5 datetime-local input to datetime field
self.fields['start_time'].input_formats = ('%Y-%m-%dT%H:%M',)
self.fields['end_time'].input_formats = ('%Y-%m-%dT%H:%M',)
def clean(self, *args, **kwargs):
form_start_time = self.cleaned_data.get('start_time')
form_end_time = self.cleaned_data.get('end_time')
form_manage_id = self.cleaned_data.get('manage_id')
between = Event.objects.exclude(pk=self.instance.pk).filter(
manage_id=self.user_id,
end_time__gte=form_start_time,
start_time__lte=form_end_time
)
if between.exists():
raise forms.ValidationError('Already Calendar entry for this time')
return super().clean()
The .exclude(pk=self.instance.pk) will exclude the object you are editing, if you later decide to use the EventForm not only to create but also update an Event object.
Note: The documentation advises to
use the AUTH_USER_MODEL setting [Django-doc] over
get_user_model() [Django-doc].
This is safer, since if the authentication app is not yet loaded, the settings
can still specify the name of the model. Therefore it is better to write:
from django.conf import settings
class Event(models.Model):
# …
manage = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)

django formset: it is always trying to create when the form is updated

I have been Googling around for this question for quite long. And sadly no luck. Indeed I found questions like SO question and SO question. I would say I found myself having a very similar question to the first one. However, I do not understand the discussions under that question.
So first of all, to make it clear, I did not even get formset.is_valid() to return True--that is the problem. There are indeed uniqueness check but my edit should be able to pass that check in the database level.
And here comes my code:
### models.py
class DataAccess(models.Model):
user = models.ForeignKey(User, models.CASCADE)
project_data = models.ForeignKey(ProjectData, models.CASCADE)
role = models.CharField(
max_length=2, choices=ROLES, default='N'
)
created_at = models.DateTimeField(auto_now=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = (('user', 'project_data', 'role'),)
# query from project data should happen more
index_together = [['project_data', 'user', 'role']]
def __str__(self):
return '{}&{}&{}'.format(self.user, self.project_data, self.role)
def save(self, *args, **kwargs):
curr = datetime.now()
if not self.created_at:
self.created_at = curr
self.updated_at = curr
return super(DataAccess, self).save(*args, **kwargs)
class DataSyncPath(models.Model):
server = models.ForeignKey(Server, models.CASCADE)
project_data = models.ForeignKey(ProjectData, models.CASCADE)
path = models.CharField(max_length=128)
created_at = models.DateTimeField(auto_now=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = (('server', 'project_data',),)
index_together = [['project_data', 'server']]
def __str__(self):
return '{}&{}'.format(self.server, self.project_data)
def save(self, *args, **kwargs):
curr = datetime.now()
if not self.created_at:
self.created_at = curr
self.updated_at = curr
return super(DataSyncPath, self).save(*args, **kwargs)
### forms.py
class DataAccessForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(DataAccessForm, self).__init__(*args, **kwargs)
helper = FormHelper()
helper.template = 'bootstrap/table_inline_formset.html'
self.helper = helper
self.helper.form_tag = False
class Meta:
model = DataAccess
exclude = ['created_at', 'updated_at']
def get_data_access_formset(initial=[], extra=3):
return inlineformset_factory(
ProjectData, DataAccess,
form=DataAccessForm, extra=extra + len(initial)
)
class DataSyncPathForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(DataSyncPathForm, self).__init__(*args, **kwargs)
helper = FormHelper()
helper.template = 'bootstrap/table_inline_formset.html'
self.helper = helper
self.helper.form_tag = False
class Meta:
model = DataSyncPath
exclude = ['created_at', 'updated_at']
def clean(self):
super(DataSyncPathForm, self).clean()
if (self.cleaned_data['id'] is None and 'path' in self.errors and
self.errors['path'][0] == 'This field is required.'):
# a special hack to silent path error
self.errors.pop('path')
def get_data_sync_path_formset(initial=[], extra=0):
return inlineformset_factory(
ProjectData, DataSyncPath, can_delete=False,
form=DataSyncPathForm, extra=extra + len(initial)
)
### views.py, import and everything is taken care of already
class ProjectDataUpdateView(LoginRequiredMixin, UpdateView):
login_url = reverse_lazy('login')
redirect_field_name = 'redirect_to'
template_name = 'project_data/project_data_form.html'
form_class = ProjectDataForm
context_object_name = 'project_data'
pk_url_kwarg = 'project_data_id'
success_url = reverse_lazy('data_projects:project_data_list')
def get_queryset(self):
return dbmanager.get_project_data_by_user(
self.request.user
)
def get_initial(self):
initial = super(ProjectDataUpdateView, self).get_initial()
try:
initial['phabricator_links'] = ','.join(json.loads(
self.object.phabricator_links))
except Exception:
initial['phabricator_links'] = ''
return initial
def get_data_access_initial(self):
data_access_queryset = self.object.dataaccess_set.all()
data_access_initial = [
model_to_dict(obj) for obj in data_access_queryset
]
return data_access_initial
def get_data_sync_path_initial(self):
datasyncpath_set = self.object.datasyncpath_set.all()
sync_path_initial = [
model_to_dict(obj) for obj in datasyncpath_set
]
servers = self.request.user.server_set.all()
missing_servers = set(
[server.id for server in servers]) - set(
[obj['server'] for obj in sync_path_initial]
)
for server_id in missing_servers:
sync_path_initial.append({'server': server_id})
return sync_path_initial
def process_context_data(self, data):
data_access_initial = self.get_data_access_initial()
sync_path_initial = self.get_data_sync_path_initial()
if self.request.POST:
if (self.request.user.is_superuser or
self.request.user.groups.filter(name='Manager').exists()):
data['data_access_formset'] = get_data_access_formset()(
self.request.POST, self.request.FILES,
instance=self.object, initial=data_access_initial,
queryset=self.object.dataaccess_set.all()
)
data['data_sync_path_formset'] = get_data_sync_path_formset()(
self.request.POST, self.request.FILES,
instance=self.object, initial=sync_path_initial,
queryset=self.object.datasyncpath_set.all()
)
else:
data['data_access_formset'] = get_data_access_formset(
initial=data_access_initial
)(initial=data_access_initial)
data['data_sync_path_formset'] = get_data_sync_path_formset(
initial=sync_path_initial
)(initial=sync_path_initial)
return data
def get_context_data(self, **kwargs):
data = super(ProjectDataUpdateView, self).get_context_data(**kwargs)
data_access_formset = kwargs.pop('data_access_formset', None)
data_sync_path_formset = kwargs.pop('data_sync_path_formset', None)
if data_access_formset and data_sync_path_formset:
data['data_access_formset'] = data_access_formset
data['data_sync_path_formset'] = data_sync_path_formset
else:
data = self.process_context_data(data)
data['is_data_sync_path_set'] = True
return data
def post(self, request, *args, **kwargs):
self.object = self.get_object()
if not (self.request.user.is_superuser or
self.request.user.groups.filter(name='Manager').exists()):
self.request.POST['name'] = self.object.name
self.request.POST['dmgr'] = self.object.dmgr
form_class = self.get_form_class()
form = self.get_form(form_class)
context_data = self.get_context_data()
data_access_formset = context_data.get('data_access_formset')
sync_path_formset = context_data.get('data_sync_path_formset')
if (form.is_valid() and
data_access_formset.is_valid() and
sync_path_formset.is_valid()):
return self.form_valid(
form, data_access_formset, sync_path_formset)
else:
return self.form_invalid(
form, data_access_formset, sync_path_formset)
def form_valid(
self, form, data_access_formset, sync_path_formset, **kwargs):
for deleted_form in data_access_formset.deleted_forms:
try:
deleted_form.cleaned_data['id'].delete()
except Exception:
pass
self.object = form.save()
data_access_formset.save()
sync_path_formset.save()
return HttpResponseRedirect(self.get_success_url())
def form_invalid(
self, form, data_access_formset, sync_path_formset, **kwargs):
return self.render_to_response(
self.get_context_data(
form=form, data_access_formset=data_access_formset,
sync_path_formset=sync_path_formset
)
)
I have also put breakpoint in post method of the UpdateView class:
ipdb> sync_path_formset.is_valid()
False
ipdb> sync_path_formset.forms[0]
<DataSyncPathForm bound=True, valid=False, fields=(server;project_data;path;id;DELETE)>
ipdb> sync_path_formset.forms[0].cleaned_data
{'DELETE': False, 'project_data': <ProjectData: bbb>, 'path': 'that', 'server': <Server: jgu-pc>, 'id': <DataSyncPath: jgu-pc&bbb>}
ipdb> sync_path_formset.forms[0].instance
<DataSyncPath: jgu-pc&bbb>
ipdb> sync_path_formset.forms[0].save(commit=False)
*** ValueError: The DataSyncPath could not be created because the data didn't validate.
ipdb> sync_path_formset.forms[0].has_changed()
True
So clearly the instance exists. But it just tries to create another instance anyway.

Model object has no attribute save

This is the model I've defined:
class Post(models.Model):
user = models.ForeignKey(MSUser)
upvote_count = models.IntegerField()
post_status = models.IntegerField(choices = POST_STATUS)
title = models.CharField(max_length=200,null = True,blank = True)
content = models.CharField(max_length=1000,null = False,blank = False)
created_at = models.DateTimeField(auto_now_add=True, null=True)
updated_at = models.DateTimeField(auto_now=True, null=True)
def __unicode__(self):
return self.content
def get_user(self):
return self.user.__unicode__()
def save(self, **kwargs):
super(Post, self).save(**kwargs)
Here is the view:
class Post (View):
#method_decorator(csrf_exempt) # To be removed
def dispatch(self, request, *args, **kwargs):
# Placeholder for fine grained permission system to prevent unwarranted GET/POST/PUTS
# Check request.user properties (like group etc) and request.method
# return HttpResponseForbidden()
return super(Post, self).dispatch(request, *args, **kwargs)
def get(request):
pass
def post(self, request):
responseMessage = {}
user = request.user
if user.is_authenticated():
title = request.POST.get('title', None)
content = request.POST.get('content', None)
if title is None or content is None:
responseMessage['status'] = 'failure'
responseMessage['message'] = 'Mandatory data is missing.'
return HttpResponse(json.dumps(responseMessage))
else:
newPost = Post(user = user,
title = title,
content = content,
post_status = PS_CREATED,
upvote_count = 0)
newPost.save()
responseMessage['status'] = 'success'
responseMessage['message'] = 'Post created successfully'
responseMessage['server_id'] = newPost.id
return HttpResponse(json.dumps(responseMessage))
When sending a request from Postman I keep getting the following error:
AttributeError: 'Post' object has no attribute 'save'
What am I doing wrong?
Your view class and the model class have the same name i.e. Post.
So, when you do Post(user=..) in your view, it tries to create the Post view object and then call .save() on it whereas it should have created the Post model object and saved it.
To solve your problem, you need to change your view class name to something else.
Try changing
class Post(View):
to something like
class PostView(View):
You have duplicated objects named Post which you got mixed. It looks like you are trying to save the View object instead of the Model object.

How do I write a form in django

I am writing a forums app for my final project in class and I am trying to write a form for creating a new thread, Basically all I need it to do is
username: text box here
Name of thread: Text box here
Post: text box here
I want to do this in forms.py instead of making a template for it.
url(r"^(.+)/new_thread/$", new_thread, name="thread_new_thread"),
That's my url thread
def list_threads(request, forum_slug):
"""Listing of threads in a forum."""
threads = Thread.objects.filter(forum__slug=forum_slug).order_by("-created")
threads = mk_paginator(request, threads, 20)
template_data = {'threads': threads, 'forum_slug': forum_slug}
return render_to_response("forum/list_threads.html", template_data, context_instance=RequestContext(request))
That is my list_threads view, I have a button that should link to the forms.py version of my new thread post
class Thread(models.Model):
title = models.CharField(max_length=60)
slug = models.SlugField(max_length=60)
created = models.DateTimeField(auto_now_add=True)
creator = models.ForeignKey(User, blank=True, null=True)
forum = models.ForeignKey(Forum)
class Meta:
unique_together = ('slug', 'forum', )
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Thread, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('forum_list_posts', args=[self.forum.slug, self.slug])
def __unicode__(self):
return unicode(self.creator) + " - " + self.title
def num_posts(self):
return self.post_set.count()
def num_replies(self):
return self.post_set.count() - 1
def last_post(self):
if self.post_set.count():
return self.post_set.order_by("created")[0]
This is my thread model
Any suggestions?
Read the documentation:
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/
I guess that the Thread has a model.
class ThreadForm(ModelForm):
def __init__(self, forum, user, *args, **kwargs):
super(ThreadForm, self).__init__(*args, **kwargs)
self.forum = forum
self.user = user
def save(self):
thread = super(ThreadForm, self).save(commit=False)
thread.forum = self.forum
thread.creator = self.user
thread.save()
return thread
class Meta:
model = Thread
exclude = ('slug', 'created', 'creator', 'forum')
In your views:
def thread_add(self, forum_id):
data = None
if request.method == 'POST':
data = request.POST
forum = Forum.objects.get(id=form_id)
form = ThreadForm(forum=forum, user=request.user, data=data)
if form.is_valid():
form.save()
.............
return render_to_response .....
In your model left a field to "Post: text box here"

Categories

Resources