Django - how add User specific Items? - python

Good day Stackoverflow,
a user should be able to add multiple titles instead of always overwriting the one added title.
\\ views.py
def edit_profile(request):
try:
profile = request.user.userprofile
except UserProfile.DoesNotExist:
profile = UserProfile(user=request.user)
if request.method == 'POST':
form = UserProfileForm(request.POST, instance=profile)
if form.is_valid():
form.save()
return redirect('/test')
else:
form = UserProfileForm(instance=profile)
return render(request, 'forms.html', {'form': form, 'profile': profile})
\\models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
title = models.CharField(max_length=1024)
def __str__(self):
return str(self.title)
\\forms.py
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('title',)
Then the user has a form on the website where he can add the specific title.
Until now, however, every time the user fills out the title form, the value in the database is overwritten.
As it should be:
When a new title is added in the form, it should simply be added to it.
At the end I should have the possibility, with a Foor loop in the HTML template, to display all the added titles of the respective user.
Do you know how to do this?

If you are using a relational database, this functionality isn't really supported for a single field. Though, if you really wanted to, you could use a JSON field to make this work.
However, it is probably a better idea to use a separate table for titles.
To do this, you need to create a new Title object like:
class Title(models.Model):
Then, create a many-to-one relationship using ForeignKey:
class Title(models.Model):
text = models.CharField(max_length=1024)
user_profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE)
The on_delete method is required. This particular one will delete all Titles associated with a UserProfile if a UserProfile is deleted.
Now, if you want to associate a title object with a UserProfile, you would do it like this:
profile = UserProfile(user=request.user)
title = Title.objects.create(text='My Very First Title', user_profile=profile)
For more info on many-to-one relationships in Django: https://docs.djangoproject.com/en/4.0/topics/db/examples/many_to_one/

You can create new model and assign new with the ForeignKey field.
models.py:
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
return ', '.join([title for title in self.titles.all()])
class UserTitle(models.Model):
title = models.CharField(max_length=1024)
userprofile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name='titles')
def __str__(self):
return self.title
views.py:
def edit_profile(request):
...
if request.method == 'POST':
...
if form.is_valid():
form.instance.userprofile = request.user.userprofile
form.save()
return redirect('/test')
...
admin.py:
from django.contrib import admin
from your_app.models import UserProfile
class UserProfileAdmin(admin.ModelAdmin):
list_display = ['id', 'user', '__str__']
admin.site.register(UserProfile, UserProfileAdmin)
settings.py:
INSTALLED_APPS = [
...
'your_app',
...
In template, to make for loop just use:
{% for title in user.userprofile.titles.all %}
{{ title }}
{% endfor %}
or if you need only User titles in single string:
{{ user.userprofile }}

Related

How to automatically get user in django admin through form

I have a form in my django website where the user requests coins and the information is sent to the admin for me to process. I want to automatically get the user who filled the form without them doing it themselves.
Here's the model.py file:
class Requestpayment (models.Model):
username= models.ForeignKey(User, on_delete= models.CASCADE, null=True)
useremail= models.CharField(max_length=100)
accountmail= models.CharField(max_length=100)
accountphonenumber=models.CharField(max_length=15)
coinsrequested=models.ForeignKey(Requestamount, on_delete= models.SET_NULL, null=True)
created= models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.accountmail
the forms.py:
class Requestpaymentform (ModelForm):
class Meta:
model = Requestpayment
fields = '__all__'
and the views.py:
#login_required(login_url='login')
def redeemcoins (request):
form = Requestpaymentform
if request.method =='POST':
form = Requestpaymentform(request.POST)
if form.is_valid():
form = form.save(commit=False)
username = request.user
form.save()
return redirect ('home')
I am pretty sure something is wrong but i don't know what it is (I'm very new at django) anyway the form always shows all the users in the website for the current user to pick who they are.
redeem coins page
I also tried excluding that part of the form but it didn't work it just shows up empty in the admin.
thank you.
You need to assign it to the instance wrapped in the form, so:
#login_required(login_url='login')
def redeemcoins(request):
form = Requestpaymentform()
if request.method == 'POST':
form = Requestpaymentform(request.POST)
if form.is_valid():
form.instance.username = request.user
form.save()
return redirect('home')
# …
It makes more sense however to name this field user than username. In the model you can also make the username field non-editable, such that it does not appear in the form:
from django.conf import settings
class Requestpayment(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL, editable=False, on_delete=models.CASCADE
)
# …
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.
When you use username= models.ForeignKey(User, on_delete= models.CASCADE, null=True), Django add a field named user_id in your database which allow django to find User object for Requestpayment.
You can use user_id field to add a User object in Requestpayment.
You don't need to pass username field in your fields list if you want to get user in view.
class Requestpaymentform (ModelForm):
class Meta:
model = Requestpayment
#fields = '__all__'
fields = ['useremail',
'accountmail',
'accountphonenumber',
'coinsrequested',
'created']
Now do this to get user in your view.
#login_required(login_url='login')
def redeemcoins(request):
form = Requestpaymentform()
if request.method == 'POST':
form = Requestpaymentform(request.POST)
if form.is_valid():
requestpayment = form.save(commit=False)
requestpayment.user_id = request.user.id
requestpayment.save()
return redirect('home')
And it's great to use user instead username because it's a User object and not a simple field.
Please for my English !!!

Django, link a model field with an admin model field with ForeignKey

I'm trying to link a "normal" model field with an admin model field, for example I have a table "Post" and I want to add the admin username as a ForeignKey to the field "Author" of the table Post.
I mean :
class Post(models.Model):
title = models.CharField(max_length=50)
body = RichTextField(blank=True, null=True)
date = models.DateTimeField('date_posted')
username = models.ForeignKey(admin.username, on_delete=models.CASCADE)
Where admin.username refers the username of auth_user admin model
Thanks for your help
As the referencing the user model section of the documentation says, you can make use of settings.AUTH_USER_MODEL to obtain a reference to the user model that is used. You can use the to_field=… [Django-doc] to specify to what field of the model it should refer, so:
from django.conf import settings
class Post(models.Model):
title = models.CharField(max_length=50)
body = RichTextField(blank=True, null=True)
date = models.DateTimeField('date_posted')
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
to_field='username'
on_delete=models.CASCADE,
editable=False
)
By specifying editable=False [Django-doc] it will not automatically show up in ModelForms.
In views, you can then set the logged in user as author by specifing the author attribute. For example:
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
#login_required
def some_view(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.instance.author = request.user
form.save()
return redirect('name-of-some-view')
else:
form = PostForm()
return render(request, 'some_template.html', {'form': form})
Note: A ForeignKey does not store the string representation (or name) of the
referenced object in the column, it stores the primary key of the record it
references in a column with an _id suffix to a ForeignKey field. Therefore
ForeignKeys usually do not end with a _name suffix. You might want to
consider renaming the username field to author.
How about something like this?
class Post(models.Model):
title = models.CharField(max_length=50)
body = RichTextField(blank=True, null=True)
date = models.DateTimeField('date_posted')
user = models.ForeignKey(auth_user, on_delete=models.CASCADE)
#property
def username(self): return self.user.username
Usage:
some_post = Post.objects.get(id='the_post_id')
print(some_post.username) # prints some_post.user.username

Django: form is not displaying

After the user registers, I am using signals to create a user profile, so they can fill in additional details (like country or website) that the standard registration form can't offer. The problem is the form is not displaying the contents. However I can fill in the same form on admin site easily, but I want to allow users to do it by themselves.
On Chrome I tried to inspect the problem, and where there is a form it says input='hidden'. What might be the problem?
Thank you in advance.
my views:
def edit_profile(request):
if request.method == 'POST':
edit_form = EditProfileForm(request.POST,
instance=request.user.profile)
if edit_form.is_valid():
edit_form.save()
messages.success(request, 'Your account has been updated!')
return redirect(profile)
else:
edit_form = EditProfileForm(instance=request.user.profile)
context = {'edit_form': edit_form}
return render(request, 'profile.html', context)
my profile.html:
<form method='POST'>
{% csrf_token %}
{{ edit_form }}
<button type="submit">Update</button>
</form>
models:
class Profile(models.Model):
user = models.OneToOneField(User)
description = models.CharField(max_length=100, default='')
country = models.CharField(max_length=100, default='')
website = models.URLField(default='')
image = models.ImageField(default='images/profile.jpg',
upload_to='images')
def __str__(self):
return self.user.username
def create_profile(sender, **kwargs):
if kwargs['created']:
profile = Profile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender=User)
forms.py:
class EditProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('status', 'website', 'description', 'country', 'user', )
Do you get an indentation error when you run your code?
If not can you please update your question with the correct indentation so that the SO people can help you troubleshoot.
Next up, do you have any group permissions in place for standard users vs non-standard user(admin)? I would check to see if they have the capability to modify their User objects freely.
Errors for the form are usually displayed by <ul class="errorlist"> FormsAPI, I would check for those. If none, then I would double check that the form being returned isn't actually blank by debugging it and looking at the __dict__ definition of that object. I can't give you any more suggestions until the indentation part is fixed so I can rule out any logic errors.
Found the problem: edit_form = EditProfileForm(instance=request.user.profile)
What you want to do is query the Profile object that belongs to the user, bold then pass it in as an instance to your EditProfileForm.
class EditProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('status', 'website', 'description', 'country', 'user', )
Your form's Meta is the Profile object not the User object.
Hope that helps, good luck!

Django : How to associate a user to a created post when post is created through a ModelForm

I've created a normal Django posts app, which basically let's users create posts and it's content.
Now the thing is that I implemented the create post form as a ModelForm in forms.py. Now if it wasn't a ModelForm and just a html-form, I would have used request.POST.get('data')
But now I use
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = (
'title',
'content',
'image',
)
Models.py
class Post(models.Model):
title = models.CharField(max_length=100)
image = models.ImageField(null=True,blank=True)
content = models.TextField()
user = models.ForeignKey(User,on_delete=models.CASCADE,null=True)
Views.py
def create(request):
form = PostForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return HttpResponseRedirect('/home')
return render(request,'create.html',{'form':form})
How can I relate a user to a created post?
You can simply assign the user to the instance in between the two save functions:
instance = form.save(commit=False)
instance.user = request.user
instance.save()

Django : Filter, limit and display file filed dynamicly with generic inlineformset

I need your help, because I'm stuck in a project with no idea about how to continue.
I need to implement a simple "generic" document management app to integrate it in my project. I can have many kind of documents that are defined by "utilisation_type" in "DocumentType" model.
At the end, I need to display a page with an inline form, with only one of each "DocumentType" with (in this case) "utilisation_type"= "USER".
Like this, the user will get, for exemple, a page with 3 buttons, each button corresponding to only one DocumentType with "utilisation_type"= "USER" and he will be able to upload only one of each requested document.
Here are my models :
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
UTILISATION_TYPE_CHOICES = (
("USER", _(u"User")),
("PROJECT", _(u"Project")),
("TEAM", _(u"Team")),
("ALL", _(u"All")),
)
class DocumentType(models.Model):
document_type = models.CharField(max_length=40, choices=DOCUMENT_TYPE_CHOICES)
title = models.CharField(_(u'Titre'), max_length=255, blank=False, null=True)
utilisation_type = models.CharField(max_length=15, choices=UTILISATION_TYPE_CHOICES)
class Document(models.Model):
document_type = models.ForeignKey(DocumentType)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
document = models.FileField(_(u"Document"), upload_to='upload/documents', null=True, blank=True)
class MyUserManager(BaseUserManager):
first_name = models.CharField(_(u'Firstname'), max_length=90, blank=False)
last_name = models.CharField(_(u'Lastname'), max_length=90, blank=False)
Here is my view :
#login_required
def documents(request):
"""
User's documents edition
"""
user = request.user
DocumentInlineFormSet = generic_inlineformset_factory(Document)
if request.method == 'POST':
formset = DocumentInlineFormSet(request.POST, request.FILES, instance=user)
if formset.is_valid():
formset.save()
messages.success(request, _(u'Profil updated'), fail_silently=True)
return redirect('users.views.documents')
else:
formset = DocumentInlineFormSet(instance=user)
return render_to_response('users/user_documents.html', {'formEditDocumentFormset': formset,}, context_instance=RequestContext(request))
I hope I've been clear enough in my explanation. Do not hesitate to ask more details if needed.
I think the most simple way is to check the type of every single document on it's saving. if you allow to save each doctype only once you will get only different doctypes for each user. In that case you do not need to use double filtering or whatever.
You can rewrite the save() method for each form in a formset by creating your CustomInlineFormSet. Here is the link: https://docs.djangoproject.com/en/1.8/topics/forms/modelforms/#overriding-methods-on-an-inlineformset.
It could be smth like this for example:
from django.forms.models import BaseInlineFormSet
class DocumentInlineFormSet(BaseInlineFormSet):
def clean(self):
super(DocumentInlineFormSet, self).clean()
for form in self.forms:
document = form.save(commit=False)
#check your document here
document.save()

Categories