Django: Adding "created by" field to object - django

I need to store the user who is creating a specific object in the database, like so:
(models.py)
class Address(models.Model):
createdBy = models.ForeignKey(User)
address1 = models.CharField("Address Line 1", max_length=40)
address2 = models.CharField("Address Line 2", max_length=40, blank=True)
city = models.CharField(max_length=20)
state = models.CharField(max_length=3)
zipCode = models.CharField("Postal Code", max_length=10)
My view for handling the form is here (views.py):
def handlePopAdd(request, addForm, field):
if request.method == "POST":
form = addForm(request.POST)
if form.is_valid():
try:
newObject = form.save(request)
except forms.ValidationError, error:
newObject = None
if newObject:
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>'% (escape(newObject._get_pk_val()), escape(newObject)))
else:
form = addForm()
pageContext = {'form': form, 'field': field}
return render_to_response("address_popup.html", pageContext, context_instance=RequestContext(request))
And finally, here is my form code: (forms.py)
class AddressForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
return super(AddressForm, self).__init__(*args, **kwargs)
def save(self, *args, **kwargs):
obj = super(AddressForm, self).save(commit=False)
if self.request:
obj.createdBy = self.request.user
obj.save()
class Meta:
model = Address
exclude = ('createdBy',)
I am using the top answer suggested by this question, and have hit a wall after a few hours staring a hole through this.
Here's my traceback. Error is IntegrityError at /app/address/add/ (1048, "Column 'createdBy_id' cannot be null")
Traceback:
File "/usr/local/lib/python2.6/dist-packages/django/core/handlers/base.py" in get_response
111. response = callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/contrib/auth/decorators.py" in _wrapped_view
23. return view_func(request, *args, **kwargs)
File "/home/matthew/lessonhelper/../lessonhelper/lessons/views.py" in address_add
78. return handlePopAdd(request, AddressForm, 'address')
File "/usr/local/lib/python2.6/dist-packages/django/contrib/auth/decorators.py" in _wrapped_view
23. return view_func(request, *args, **kwargs)
File "/home/matthew/lessonhelper/../lessonhelper/lessons/views.py" in handlePopAdd
66. newObject = form.save(request)
File "/home/matthew/lessonhelper/../lessonhelper/lessons/forms.py" in save
29. obj.save()
File "/usr/local/lib/python2.6/dist-packages/django/db/models/base.py" in save
460. self.save_base(using=using, force_insert=force_insert, force_update=force_update)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/base.py" in save_base
553. result = manager._insert(values, return_id=update_pk, using=using)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/manager.py" in _insert
195. return insert_query(self.model, values, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/query.py" in insert_query
1436. return query.get_compiler(using=using).execute_sql(return_id)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/compiler.py" in execute_sql
791. cursor = super(SQLInsertCompiler, self).execute_sql(None)
File "/usr/local/lib/python2.6/dist-packages/django/db/models/sql/compiler.py" in execute_sql
735. cursor.execute(sql, params)
File "/usr/local/lib/python2.6/dist-packages/django/db/backends/util.py" in execute
34. return self.cursor.execute(sql, params)
File "/usr/local/lib/python2.6/dist-packages/django/db/backends/mysql/base.py" in execute
86. return self.cursor.execute(query, args)
File "/usr/lib/pymodules/python2.6/MySQLdb/cursors.py" in execute
166. self.errorhandler(self, exc, value)
File "/usr/lib/pymodules/python2.6/MySQLdb/connections.py" in defaulterrorhandler
35. raise errorclass, errorvalue
Exception Type: IntegrityError at /app/address/add/
Exception Value: (1048, "Column 'createdBy_id' cannot be null"

You specifically defined logic to add the request to the form, but are not using it.
You need to instantiate your form with request as a keyword argument (according to your code).
form = addForm(request.POST, request=request)
save(request) does nothing with the request.
Most people prefer just accepting a new argument in save().
def save(self, request):
obj = super(AddressForm, self).save(commit=False)
obj.createdBy = request.user
obj.save()
Finally, there's no point in the if block in the save method if createdBy is not nullable: it's required. There's no "if" about it.

You excluded the createdBy field in your form and according to your Model definition, it's a required field since you're using a ModelForm.

Related

How to set initial value of a field using foreign field of a model in django?

I wish to set initial value in profile form.
Profile model has a OneToOne relation with User model.
I get the following error when I set initial field in init method,
'ForwardOneToOneDescriptor' object has no attribute 'email'
Traceback
File
"/home/drogon/Crowdsocial_project/venv_ubuntu/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
34. response = get_response(request)
File
"/home/drogon/Crowdsocial_project/venv_ubuntu/lib/python3.6/site-packages/django/core/handlers/base.py"
in _get_response
126. response = self.process_exception_by_middleware(e, request)
File
"/home/drogon/Crowdsocial_project/venv_ubuntu/lib/python3.6/site-packages/django/core/handlers/base.py"
in _get_response
124. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File
"/home/drogon/Crowdsocial_project/venv_ubuntu/lib/python3.6/site-packages/django/views/generic/base.py"
in view
68. return self.dispatch(request, *args, **kwargs)
File
"/home/drogon/Crowdsocial_project/venv_ubuntu/lib/python3.6/site-packages/django/views/generic/base.py"
in dispatch
88. return handler(request, *args, **kwargs)
File
"/home/drogon/Crowdsocial_project/venv_ubuntu/lib/python3.6/site-packages/django/views/generic/edit.py"
in get
190. return super().get(request, *args, **kwargs)
File
"/home/drogon/Crowdsocial_project/venv_ubuntu/lib/python3.6/site-packages/django/views/generic/edit.py"
in get
133. return self.render_to_response(self.get_context_data())
File "/home/drogon/Crowdsocial_project/users/views.py" in
get_context_data
90. context = super(ProfileSettingsView, self).get_context_data(**kwargs)
File
"/home/drogon/Crowdsocial_project/venv_ubuntu/lib/python3.6/site-packages/django/views/generic/edit.py"
in get_context_data
66. kwargs['form'] = self.get_form()
File
"/home/drogon/Crowdsocial_project/venv_ubuntu/lib/python3.6/site-packages/django/views/generic/edit.py"
in get_form
33. return form_class(**self.get_form_kwargs())
File "/home/drogon/Crowdsocial_project/users/forms.py" in init
144. self.initial['profile_email'] = Profile.user.email
Exception Type: AttributeError at /users/12/profile/settings Exception
Value: 'ForwardOneToOneDescriptor' object has no attribute 'email'
Profile Model
class Profile(models.Model):
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE, null=True, blank=True)
full_name = models.CharField(max_length=30, null=True, blank=True)
Profile Form
class ProfileSettingsForm(forms.ModelForm):
full_name = forms.CharField(required=False,
widget=forms.TextInput(attrs={'readonly': 'readonly'}))
profile_email = forms.CharField(required=False,
widget=forms.TextInput(attrs={'readonly': 'readonly'}))
def __init__(self, *args, **kwargs):
super(ProfileSettingsForm, self).__init__(*args, **kwargs)
self.initial['profile_email'] = Profile.user.email
self.initial['full_name'] = Profile.user.name
class Meta:
model = Profile
fields = ['image','full_name','biography','profile_email','linked_in','facebook',
'twitter','phone','education']

Model form foreign key field to duration field not working

I have the following form where the user selects a value which corresponds to a duration field of the name value in a model called Duration.
When the form is submitted I'm getting this error
return (24 * 60 * 60 * delta.days + delta.seconds) * 1000000 + delta.microseconds
Attribute Error - 'str' object has no attribute days.
Clearly Django expects the argument to be a timedelta object when this method is called and it is getting a string instead. Where am I at fault ?
The form :
class AuctionCreateForm(forms.ModelForm):
class Meta:
model = Auction
fields = ['title', 'reserve']
exclude = ('duration',)
labels = {'reserve': _('Reserve')}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["duration_value"] = forms.ModelChoiceField(
queryset=Duration.objects.all(),
empty_label=None,
to_field_name="value",
)
The view :
class AuctionCreate(CreateView):
""" View function for creating an auction """
form_class = AuctionCreateForm
template_name = "auction/auction_form.html"
def form_valid(self, form):
form.instance.start = timezone.now()
duration_value = form.cleaned_data.get('duration_value')
form.instance.duration = Duration.objects.get(value=duration_value)
form.instance.creator = self.request.user
return super().form_valid(form)
And here are the two models if it helps.
class Auction(models.Model):
""" Model for an auction """
uuid = models.UUIDField(
db_index=True,
default=uuid.uuid4,
editable=False,
)
title = models.CharField(max_length=10)
valid_from = models.DateTimeField(auto_now_add=True)
duration = models.ForeignKey(
Duration,
on_delete=models.SET_NULL,
null=True
)
reserve = models.PositiveIntegerField(default=0)
creator = models.ForeignKey(
get_user_model(),
on_delete=models.SET_NULL,
null=True,
)
winning_bid = models.ForeignKey(
'Bid',
related_name='highest_bid',
on_delete=models.SET_NULL,
null=True,
blank=True,
)
class Duration(models.Model):
""" Choice durations for auction """
value = models.DurationField()
def __str__(self):
return humanfriendly.format_timespan(self.value)
I know there is nothing wrong with the duration objects I have. I created them through the admin interface successfully where it provides a text field and entered a value in seconds. Furthermore, in another part of the application, where i list the auction, i can retrieve the values and do arithmetic on them.
Full Traceback -
[22/Apr/2019 13:08:54] "GET /auction/create/ HTTP/1.1" 200 3234
Internal Server Error: /auction/create/
Traceback (most recent call last):
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/views/generic/base.py", line 71, in view
return self.dispatch(request, *args, **kwargs)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/views/generic/base.py", line 97, in dispatch
return handler(request, *args, **kwargs)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/views/generic/edit.py", line 172, in post
return super().post(request, *args, **kwargs)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/views/generic/edit.py", line 141, in post
if form.is_valid():
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/forms/forms.py", line 185, in is_valid
return self.is_bound and not self.errors
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/forms/forms.py", line 180, in errors
self.full_clean()
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/forms/forms.py", line 381, in full_clean
self._clean_fields()
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/forms/forms.py", line 399, in _clean_fields
value = field.clean(value)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/forms/fields.py", line 148, in clean
value = self.to_python(value)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/forms/models.py", line 1248, in to_python
value = self.queryset.get(**{key: value})
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/db/models/query.py", line 402, in get
num = len(clone)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/db/models/query.py", line 256, in __len__
self._fetch_all()
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/db/models/query.py", line 1242, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/db/models/query.py", line 55, in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1084, in execute_sql
sql, params = self.as_sql()
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 486, in as_sql
where, w_params = self.compile(self.where) if self.where is not None else ("", [])
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 402, in compile
sql, params = node.as_sql(self, self.connection)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/db/models/sql/where.py", line 81, in as_sql
sql, params = compiler.compile(child)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 402, in compile
sql, params = node.as_sql(self, self.connection)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/db/models/lookups.py", line 163, in as_sql
rhs_sql, rhs_params = self.process_rhs(compiler, connection)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/db/models/lookups.py", line 260, in process_rhs
return super().process_rhs(compiler, connection)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/db/models/lookups.py", line 95, in process_rhs
return self.get_db_prep_lookup(value, connection)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/db/models/lookups.py", line 187, in get_db_prep_lookup
[get_db_prep_value(value, connection, prepared=True)]
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 1619, in get_db_prep_value
return duration_microseconds(value)
File "/home/ross/.local/share/virtualenvs/v4-MIvAvlKB/lib/python3.6/site-packages/django/utils/duration.py", line 44, in duration_microseconds
return (24 * 60 * 60 * delta.days + delta.seconds) * 1000000 + delta.microseconds
This is what the html for the select widget looks like -
<select name="duration_value" id="id_duration_value">
<option value="0:05:00">5 minutes</option>
<option value="0:10:00">10 minutes</option>
<option value="0:20:00">20 minutes</option>
<option value="0:40:00">40 minutes</option>
<option value="1:00:00">1 hour</option>
<option value="2:00:00">2 hours</option>
<option value="4:00:00">4 hours</option>
<option value="8:00:00">8 hours</option>
<option value="16:00:00">16 hours</option>
<option value="1 day, 0:00:00">1 day</option>
</select>
So, the problem is DurationField works on a timedelta object. So you need to convert your string to timedelta object and then perform the lookup
# views.py
from django.utils.dateparse import parse_duration
class AuctionCreate(CreateView):
""" View function for creating an auction """
form_class = AuctionCreateForm
template_name = "auction/auction_form.html"
def form_valid(self, form):
form.instance.start = timezone.now()
duration_value = form.cleaned_data.get('duration_value')
duration_obj = parse_duration(duration_value) # convert string to timedelta object
form.instance.duration = Duration.objects.get(value=duration_obj)
form.instance.creator = self.request.user
return super().form_valid(form)
In case it helps anyone...
Got it working like this for functions -
#login_required
def AuctionCreate(request):
if request.method == 'POST':
request.POST = request.POST.copy()
duration_value = request.POST["duration_value"]
duration_value = parse_duration(duration_value)
request.POST["duration_value"] = duration_value
print(request.POST)
form = AuctionCreateForm(request.POST)
if form.is_valid():
Auction.objects.create(
title=form.cleaned_data["title"],
valid_from=timezone.now(),
duration=Duration.objects.get(value=duration_value),
reserve=form.cleaned_data["reserve"],
creator=request.user,
winning_bid=None
)
return HttpResponse("Created auction")
else:
return HttpResponse("Something went wrong")
else:
form = AuctionCreateForm()
return render (
request,
'auction/auction_form.html',
{
'form': form
}
)
And like this for class based view -
""" View function for creating an auction """
form_class = AuctionCreateForm
template_name = "auction/auction_form.html"
def post(self, request, *args, **kwargs):
request.POST = request.POST.copy()
duration_value = request.POST["duration_value"]
duration_value = parse_duration(duration_value)
request.POST["duration_value"] = duration_value
return super().post(request, *args, **kwargs)
def form_valid(self, form):
form.instance.start = timezone.now()
duration_value = form.cleaned_data.get('duration_value')
form.instance.duration = duration_value
form.instance.creator = self.request.user
return super().form_valid(form)

Django 1.11 Invalid Literal for ManytoMany field when saving form

I have a model that has a many to many field. When I try to save it, it errors out with a invalid literal for int() with base 10: 'A' error. From other posts I've read it looks like it's something to do with the CharField in my forms.py. In my clean_states, I can print the value for self.cleaned_data['states'] and get back the two letter code of the state. I thought that was what was going to be saved to the database. I'm not sure why it thinks I'm trying to save an int.
models.py
class States(models.Model):
state = models.CharField(max_length=2, choices=US_STATES , null=True, blank=True)
def __str__(self):
return self.state
class Person(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
state = models.ManyToManyField(States)
views.py
class UserProfileUpdateView(LoginRequiredMixin, UpdateView):
model = Person
form_class = UserProfileChangeForm
template_name = 'accounts/profile-update-view.html'
def get_context_data(self, *args, **kwargs):
context = super(UserProfileUpdateView, self).get_context_data(*args, **kwargs)
context['states'] = States.objects.all()
return context
def get_object(self):
qs = Person.objects.filter(pk=self.request.user.person.user_id).first()
return qs
forms.py
class UserProfileChangeForm(forms.ModelForm):
state= forms.CharField(widget=USStateSelect(), initial='TX')
class Meta:
model = SkilledLaborer
fields = ['user','state']
def clean_user(self):
user = self.cleaned_data['user']
return user
def clean_state(self):
state= self.cleaned_data['state']
return state
def save(self, *args, **kwargs):
print('im saving')
print(self.cleaned_data['states'])
obj = super(UserProfileChangeForm, self).save(*args, **kwargs)
print('here2')
add_states = self.cleaned_data['states']
print(add_states)
print('here3')
if add_states:
for state in add_states.split(","):
state = States.objects.get(state=state)
obj.states.add(state)
return obj
stacktrace
Traceback:
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\core\handlers\exception.py" in inner
41. response = get_response(request)
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\core\handlers\base.py" in _get_response
187. response = self.process_exception_by_middleware(e, request)
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\core\handlers\base.py" in _get_response
185. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\views\generic\base.py" in view
68. return self.dispatch(request, *args, **kwargs)
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\contrib\auth\mixins.py" in dispatch
56. return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\views\generic\base.py" in dispatch
88. return handler(request, *args, **kwargs)
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\views\generic\edit.py" in post
240. return super(BaseUpdateView, self).post(request, *args, **kwargs)
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\views\generic\edit.py" in post
183. return self.form_valid(form)
File "C:\Users\Starlord\Dev\ecommerce\src\accounts\views.py" in form_valid
174. form.save()
File "C:\Users\Starlord\Dev\ecommerce\src\accounts\forms.py" in save
105. obj = super(UserProfileChangeForm, self).save(*args, **kwargs)
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\forms\models.py" in save
469. self._save_m2m()
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\forms\models.py" in _save_m2m
451. f.save_form_data(self.instance, cleaned_data[f.name])
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\db\models\fields\related.py" in save_form_data
1686. getattr(instance, self.attname).set(data)
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\db\models\fields\related_descriptors.py" in set
1007. self.add(*new_objs)
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\db\models\fields\related_descriptors.py" in add
934. self._add_items(self.source_field_name, self.target_field_name, *objs)
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\db\models\fields\related_descriptors.py" in _add_items
1083. '%s__in' % target_field_name: new_ids,
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\db\models\query.py" in filter
784. return self._filter_or_exclude(False, *args, **kwargs)
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\db\models\query.py" in _filter_or_exclude
802. clone.query.add_q(Q(*args, **kwargs))
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\db\models\sql\query.py" in add_q
1250. clause, _ = self._add_q(q_object, self.used_aliases)
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\db\models\sql\query.py" in _add_q
1276. allow_joins=allow_joins, split_subq=split_subq,
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\db\models\sql\query.py" in build_filter
1206. condition = lookup_class(lhs, value)
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\db\models\lookups.py" in __init__
24. self.rhs = self.get_prep_lookup()
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\db\models\fields\related_lookups.py" in get_prep_lookup
56. self.rhs = [target_field.get_prep_value(v) for v in self.rhs]
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\db\models\fields\related_lookups.py" in <listcomp>
56. self.rhs = [target_field.get_prep_value(v) for v in self.rhs]
File "C:\Users\Starlord\Dev\ecommerce\lib\site-packages\django\db\models\fields\__init__.py" in get_prep_value
966. return int(value)
Exception Type: ValueError at /account/profile/
Exception Value: invalid literal for int() with base 10: 'A'

Updating user information with extending fields on one page

I want to update current user profile. User has one-to-one UserExtend model, so I would like to update the extending fields on the same submit event as well.
class UserExtend(models.Model):
user = models.OneToOneField(User)
town = models.CharField(max_length=100, blank=True)
age = models.IntegerField(blank=True)
organization = models.CharField(max_length=100, blank=True)
tel = models.CharField(max_length=15, blank=True)
def __unicode__(self):
return unicode(self.user)
Here is my views.py
def ProfileUpdateView(request):
user = request.user
user_form = UserForm(request.POST or None, initial={
'first_name': user.first_name,
'last_name': user.last_name,
'email': user.email
})
user_extend_form = UserExtendForm(request.POST or None, initial={
'user': user,
})
contacts = Contact.objects.get(activity=True)
tels = contacts.tel.all()
bg = Background.objects.get(activity=True)
botlinks = Bottom_navigation.objects.all()
if user_form.is_valid() and user_extend_form.is_valid():
user_form.save()
user_extend_form.save()
c = {'form': user_form, 'extend_form': user_extend_form, 'contacts': contacts, 'tels': tels, 'bg': bg,
'botlinks': botlinks}
return render(request, 'posts/user_form.html', c)
and forms.py
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ['first_name', 'last_name', 'email']
class UserExtendForm(forms.ModelForm):
user = forms.ModelChoiceField(queryset=User.objects.all(),widget=forms.HiddenInput())
class Meta:
model = UserExtend
fields = '__all__'
As it can be seen, I decided not to rewrite my ModelForm def function, but to pass two forms in a template with one submit button. Everything is rendered as expected, however when I click the submit I get an error like this:
Traceback:
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
132. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
22. return view_func(request, *args, **kwargs)
File "/srv/webapps/saunaflame/core/posts/views.py" in ProfileUpdateView
89. user_form.save()
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/forms/models.py" in save
463. construct=False)
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/forms/models.py" in save_instance
105. instance.save()
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/db/models/base.py" in save
710. force_update=force_update, update_fields=update_fields)
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/db/models/base.py" in save_base
738. updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/db/models/base.py" in _save_table
822. result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/db/models/base.py" in _do_insert
861. using=using, raw=raw)
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/db/models/manager.py" in manager_method
127. return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/db/models/query.py" in _insert
920. return query.get_compiler(using=using).execute_sql(return_id)
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in execute_sql
974. cursor.execute(sql, params)
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/db/backends/utils.py" in execute
79. return super(CursorDebugWrapper, self).execute(sql, params)
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/db/backends/utils.py" in execute
64. return self.cursor.execute(sql, params)
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/db/utils.py" in __exit__
97. six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/db/backends/utils.py" in execute
64. return self.cursor.execute(sql, params)
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/django/db/backends/mysql/base.py" in execute
124. return self.cursor.execute(query, args)
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/MySQLdb/cursors.py" in execute
205. self.errorhandler(self, exc, value)
File "/srv/webapps/saunaflame/local/lib/python2.7/site-packages/MySQLdb/connections.py" in defaulterrorhandler
36. raise errorclass, errorvalue
Exception Type: IntegrityError at /posts/profile/update/
Exception Value: (1062, "Duplicate entry '' for key 'username'")
Why django is trying to overwrite the username field for my User instance if I do not pass it to the form?
And is there a better way to update user info with extending fields on a single page?
Thanx.
This has nothing to do with having two forms. It's because you're passing initial values, then saving the form, so it's naturally trying to create a new instance with those values, even though they conflict with existing data.
You should be using the instance parameter instead of initial, so that Django knows to update the existing instances.
user_form = UserForm(request.POST or None, instance=request.user)
user_extend_form = UserExtendForm(request.POST or None, instance=request.user.userextend)

Django & markdown issue: 'NoneType' object has no attribute 'strip'

I have a problem about markdown and django integration. After I installed markdown and change my model class to:
class Page(models.Model):
class Translation(multilingual.Translation):
title = models.CharField(verbose_name="Title", max_length=30,
help_text="Put a title (max. 30 chars) of your page -e.g. About, CEO, Contact etc...")
content_markdown = models.TextField(verbose_name="Markdown Content",
help_text="Use Markdown syntax here.")
content = models.TextField(verbose_name="Page content as HTML",
blank=True, null=True,
help_text="You don't have to touch here.")
slug = models.SlugField(verbose_name="Slug",
help_text="Put here the name of your page without space -e.g. research-development")
class Meta:
verbose_name_plural = "Pages"
ordering = ['id']
def __unicode__(self):
return self.title
def save(self):
import markdown
self.content = markdown.markdown(self.content_markdown)
super(Page, self).save()
def get_absolute_url(self):
# return "/%s/%s" % (self.menu.slug, self.slug)
return "/%s" % self.slug
I got these traceback:
Traceback:
File "/usr/local/lib/python2.6/dist-packages/django/core/handlers/base.py" in get_response
92. response = callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/contrib/admin/options.py" in wrapper
226. return self.admin_site.admin_view(view)(*args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/views/decorators/cache.py" in _wrapped_view_func
44. response = view_func(request, *args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/contrib/admin/sites.py" in inner
186. return view(request, *args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/django/db/transaction.py" in _commit_on_success
240. res = func(*args, **kw)
File "/usr/local/lib/python2.6/dist-packages/django/contrib/admin/options.py" in add_view
734. self.save_model(request, new_object, form, change=False)
File "/usr/local/lib/python2.6/dist-packages/django/contrib/admin/options.py" in save_model
557. obj.save()
File "/media/DATA/Programming/pyworkspace/djangoprojects/youngjin/../youngjin/archive/models.py" in save
37. self.content = markdown.markdown(self.content_markdown)
File "/usr/local/lib/python2.6/dist-packages/Markdown-2.0.1-py2.6.egg/markdown/__init__.py" in markdown
587. return md.convert(text)
File "/usr/local/lib/python2.6/dist-packages/Markdown-2.0.1-py2.6.egg/markdown/__init__.py" in convert
370. if not source.strip():
Exception Type: AttributeError at /admin/archive/page/add/
Exception Value: 'NoneType' object has no attribute 'strip'
I cannot really figure out what is the problem. Any idea?
I would guess that self.content_markdown might be null in some cases (but I am not sure why, because the default should be to return empty strings instead of null-values if not specified otherwise).
Anyway, can you try the following, just to be sure?
self.content = markdown.markdown(self.content_markdown or u'')