django override model save() method - django

I want to get request as a parameter in save() method.
models.py
class Profile(models.Model):
uuid = UUIDField(auto=True)
user = models.ForeignKey(User)
name = models.CharField(max_length=128)
dob = models.DateField()
class Meta:
db_table = 'profile'
def save(self,*args,**kwargs):
if not self.pk:
self.user_id = 2 #here i need request.user instead of 2
super(Profile,self).save(*args,**kwargs)
forms.py
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
exclude = ['uuid','user']
views.py
def add(request):
profile_form = ProfileForm(request.POST)
profile_form.save()
Instead of the value 2 i want to pass request.user. How can i do it. If question is not correct somebody please correct the question.

Don't do that in the model. Do it in the view.
profile_form = ProfileForm(request.POST)
if profile_form.is_valid():
profile = profile_form.save(commit=False)
profile.user = request.user
profile.save()

One way is to use crequest, like this:
# model
from crequest.middleware import CrequestMiddleware
class Profile(models.Model):
# Some fields
def save(self, *args, **kwargs):
crequest = CrequestMiddleware.get_request() #its the current request
if crequest.user.pk is 1:
# Do stuff
pass
super(Profile,self).save(*args,**kwargs)

You can use kwargs.
For example:
views.py
profile_form.save(your_arg = request)
models.py
your_var = kwargs.pop("your_arg", None) #Second argument of kwargs.pop is default value
In you case, pass request as keyword argument, and then use it in models save() method.

Related

How to Query a ForeignKey field pointing to another ForeignKey field in Django

I have a model (Letter) with a foreign key, pointing to another model (Company) with a foreign key. Below is a simple schema from models.py
from django.contrib.auth.models import User
class Company (models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, editable=False)
date_created = models.DateField(default=timezone.now, null=True)
company_name = models.CharField(max_length=100, null=True)
class Letter(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='letterhead_user', null=True)
company = models.ForeignKey(Company, related_name = "company_letter", on_delete=models.CASCADE, null=True)
subject = models.CharField(max_length=5000, null=True)
body = models.TextField()
I have created a form where users can create Letters with the model through ModelForm.
class LetterForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(LetterForm, self).__init__(*args, **kwargs)
self.fields['company'].widget.attrs = {'class': 'input',}
self.fields['subject'].widget.attrs = {'class': 'input', 'placeholder': 'RE: ...'}
self.fields['body'].widget.attrs = {'class': 'textarea',}
class Meta:
model = Letter
fields = ('company', 'subject', 'body',)
The View:
def letter_form (request):
form = LetterForm()
if request.method == 'POST':
form = LetterForm(request.POST, request.FILES)
form.instance.user = request.user
if form.is_valid():
form.save()
return redirect('letter')
Currently, when the user is presented with a form to create a Letter, on the Company field, all the companies from all the users appear. See the pic below:
Front end Form
I would like only the companies that the User has created to appear in the drop-down, not all companies from all users. Or to be able to select the first company that the User has created.
You can specify the logged in user in the form and filter accordingly. In the constructor of the form we thus limit the queryset with:
class LetterForm(forms.ModelForm):
def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
self.fields['company'].widget.attrs = {'class': 'input',}
self.fields['subject'].widget.attrs = {'class': 'input', 'placeholder': 'RE: …'}
self.fields['body'].widget.attrs = {'class': 'textarea',}
if user is not None:
self.fields['company'].queryset = Company.objects.filter(user=user)
# …
and in the view, we then pass the logged in user to the constructor of the form:
from django.contrib.auth.decorators import login_required
#login_required
def letter_form(request):
if request.method == 'POST':
form = LetterForm(request.POST, request.FILES, user=request.user)
form.instance.user = request.user
if form.is_valid():
form.save()
return redirect('letter')
else:
form = LetterForm(user=request.user)
# …
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
If you use a ModelForm for Letterit may look like this:
class LetterForm(forms.ModelForm):
class Meta:
model = Letter
fields = ["company", "subject", "body"]
# you need to init the form with the right user instance
def __init__(self, user=None, *args, **kwargs):
# call the default __init__ behavior
super().__init__(*args, **kwargs)
# this is the trick, you will filter the companies queryset here
if user:
self.fields['company'].queryset = Company.objects.filter(user=user)
So you need to pass down the user in the form from your view:
something like:
def my_view(request):
# assuming the user follow the standard Django user implementation
# and you user is logged in
form = LetterForm(request.POST or None, user=request.user)
if form.is_valid():
form.save()
# then redirect the user to whatever success page
# render the form
return render(request, "your_template.html", {"form": form})

Save form data to database

I am new in Django and I really need help,
I do not know how to save my form data to database. I have problem to views.py
I will user's id who filled the form added into the foreign key field.
If there is any link or example that help me I appreciate you.
# views.py
#login_required(login_url="home")
def melk_new(request):
form = MelkForm()
???
return render(request, 'melk_new.html',{'form': form})
# models.py
class Melk(models.Model):
category = models.CharField(max_length=50)
city = models.CharField(max_length=100)
person = models.ForeignKey('CustomUser', on\_delete=models.CASCADE)
def \_\_str\_\_(self):
return self.category
class CustomUser(AbstractUser):
def __str__(self):
return self.email
---------------------------------------------------------------------------
# forms.py
class MelkForm(forms.ModelForm):
class Meta:
model = Melk
fields = ('category', 'city')
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm):
model = CustomUser
fields = ('username', 'email')
To get the currently logged in user you'll find it within request.user object. but before you assume that there is a currently logged in user, you need to validate that so you have 2 widely known options:
request.user.is_authenticated()
#login_required() decorator used if you from django.contrib.auth.decorators import login_required
if request.user.is_authenticated():
Car.objects.create(model_id=some_id, person=request.user)
Note:
The #login_required() is added above the function
#login_required(login_url="home")
def melk_new(request):
form = MelkForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.user_id = request.user.id
instance.save()
return render(request,'melk_new.html', { 'form': form})

How To Update Existing Profile Django Model Form

I am trying to allow users to be able to create and edit their profiles once they have registered. I am using a model form. What I need to do is have the employer model field be filled with the current user.
Here is my view:
def update_profile(request, username):
if request.method == 'POST':
edit_profile_form=EditProfileForm(request.POST)
if edit_profile_form.is_valid():
editprofile = edit_profile_form.save(commit=False)
editprofile.employer = request.user.get_profile()
editprofile.save()
edit_profile_form = EditProfileForm()
context = {'edit_profile_form':edit_profile_form,}
return render(request, 'pandaboard/editprofile.html', context)
Here is my model:
class Profile(models.Model):
employer = models.ForeignKey(User)
company_name = models.CharField(max_length=100)
company_description = models.TextField()
company_website = models.URLField(max_length=200, blank=True)
contact_email = models.EmailField(max_length=100)
contact_name = models.CharField(max_length=100)
def __unicode__(self):
return self.company_name
Here is my Model Form
from django.forms import ModelForm
from pandaboard.models import JobPost, Profile
from django.contrib.auth.models import User
class EditProfileForm(ModelForm):
class Meta:
model = Profile
fields = ['company_name','company_description','company_website','contact_email','contact_name']
To hydrate your form with values from your existing model instance, you need to use the instance argument on the model form:
def update_profile(request, username):
profile = request.user.get_profile()
edit_profile_form = EditProfileForm(request.POST or None,
current_user=request.user, instance=profile)
if request.method == 'POST':
if edit_profile_form.is_valid():
editprofile.save()
context = {'edit_profile_form': edit_profile_form}
return render(request, 'pandaboard/editprofile.html', context)
To inject the current request.user, you can override the __init__ of EditProfileForm, passing in an extra keyword argument (or arg, it doesn't really matter), and the popping it out of the kwargs before calling super so you aren't passing the ModelForm a keyword argument it isn't expecting:
class EditProfileForm(ModelForm):
class Meta:
model = Profile
def __init__(self, *args, **kwargs):
current_user = kwargs.pop('current_user')
super(EditProfileForm, self).__init__(*args, **kwargs)
self.fields['employer'] = current_user
Now you don't have to pass commit=False and manually set the value of employer in the view.

Extend UserCreationForm for extended User in Django

I extended my django user and need to create a registration form now.
I got most of it figured out but I don't know how to exclude fields I don't need during registration. Right know I see all fields in the registration form.
Here is the code:
models.py
class Artist(Model):
user = OneToOneField(User, unique=True)
address = CharField(max_length=50)
city = CharField(max_length=30)
ustid = CharField(max_length=14)
date_of_birth = DateField()
bio = CharField(max_length=500)
def __unicode__(self):
return self.user.get_full_name()
User.profile = property(lambda u: Artist.objects.get_or_create(user=u)[0])
forms.py
class RegistrationForm(UserCreationForm):
class Meta:
model = User
def __init__(self, *args, **kwargs):
super(RegistrationForm, self).__init__(*args, **kwargs)
artist_kwargs = kwargs.copy()
if kwargs.has_key('instance'):
self.artist = kwargs['instance'].artist
artist_kwargs['instance'] = self.artist
self.artist_form = ArtistForm(*args, **artist_kwargs)
self.fields.update(self.artist_form.fields)
self.initial.update(self.artist_form.initial)
def clean(self):
cleaned_data = super(RegistrationForm, self).clean()
self.errors.update(self.artist_form.errors)
return cleaned_data
def save(self, commit=True):
self.artist_form.save(commit)
return super(RegistrationForm, self).save(commit)
How do I exclude fields?
class Meta:
model = User
exclude = ('bio',)
You can't include or exclude fields that are not a member of the meta model.
What you can do is doing that in each form. In this case the UserCreationForm is extended by the ArtistForm. Just restrict the fields in the form that belong to the right meta model.

Setting user_id when saving in view - Django

I need to set the user that is creating the post in the add view:
#login_required
def add(request):
if request.method == 'POST':
form = BusinessForm(request.POST)
form.user_id = request.user.id
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('listing.views.detail'), args=(f.id))
else:
form = BusinessForm()
return render_to_response('business/add.html', {'form':form},
context_instance=RequestContext(request))
I assign the user id form.user_id = request.user.id but when saving, it still gives me an error Column user_id cannot be null
Am I doing something wrong? Thanks
EDIT:
I am excluding the user from the form in the model:
class BusinessForm(ModelForm):
class Meta:
model = Business
exclude = ('user',)
Could that be causing the problem?? How can I work around this?
EDIT 2:
Edited my BusinessForm() class as suggested but did not work:
class BusinessForm(ModelForm):
class Meta:
model = Business
exclude = ('user',)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
return super(BusinessForm, self).__init__(*args, **kwargs)
def save(self, *args, **kwargs):
kwargs['commit']=False
obj = super(BusinessForm, self).save(*args, **kwargs)
if self.request:
obj.user = self.request.user
obj.save()
Business model
class Business(models.Model):
name = models.CharField(max_length=200)
user = models.ForeignKey(User, unique=False)
description = models.TextField()
category = models.ForeignKey(Category)
address = models.CharField(max_length=200)
phone_number = models.CharField(max_length=10)
website = models.URLField()
image = models.ImageField(upload_to='business_pictures',blank=True)
You don't have to use init or save overrides for this.
You're just setting an attribute on your form and the form doesn't do anything with it. It doesn't magically behave like a model instance (your form wouldn't have a user_id attribute).
Since your form is a ModelForm, you can simply call save on it with commit=False to get the unsaved instance, set the user, then call save on the instance.
if request.method == 'POST':
form = BusinessForm(request.POST)
if form.is_valid():
business = form.save(commit=False)
business.user = request.user
business.save()
this seems to be exactly what your looking for.