Django - save form into database - django-models

Hey guy I need your help
so I have this model:
class PreferedShops(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
shop = models.ForeignKey(Shops, on_delete=models.CASCADE)
date_posted = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.user.username, self.shop.name
and this is the form:
class LikeShopForm(forms.ModelForm):
class Meta:
model = PreferedShops
fields = ['date_posted']
and this is the view:
def shops(request):
if request.method == 'POST':
form = LikeShopForm(request.POST)
if form.is_valid():
u = form.save(commit=False)
u.user = request.user
u.shop = request.shop
u.save()
return redirect('shops')
else:
form = LikeShopForm()
return render(request, "shops.html", {'form': form})
the probleme that I have is when I click on Like Button, I want that the form takes automatically the user and the name of the shop, and then save them into the DB
the user and the shop's name should be hidden
when I click submit I have this error 'WSGIRequest' object has no attribute 'shop'
please help me to take the shop's name automatically and save it in the db

Well the shop is not part of the request (strictly speaking, user is not either, but it is frequently added to the request object in the middelware by looking at the session).
You thus need to encode it into the URL, or in the POST parameters. For example with:
# app/urls.py
from django.urls import path
from app.views import like_shop
urlpatterns = [
path('shop/<int:shop_id>/like', like_shop, name='like_shop'),
]
Then in the view we obtain a parameter shop_id that contains the id of the related Shops object:
from django.shortcuts import get_object_or_404
from app.models import Shops
def like_shop(request, shop_id):
if request.method == 'POST':
shop = get_object_or_404(Shops, id=shop_id)
form = LikeShopForm(request.POST)
if form.is_valid():
u = form.save(commit=False)
u.user = request.user
u.shop = shop
u.save()
return redirect('shops')
else:
form = LikeShopForm()
return render(request, "shops.html", {'form': form, 'shop_id': shop_id})
Then the request in the POST should point to:
<!-- shops.html -->
<form action="{% url 'like_shop' shop_id=shop_id %}" method="post">
<!-- ... -->
</form>
The URL to this page then thus looks like /shops/123/like with 123 the id of the shop. If you thus want to pass the shop "implicitly", you need to encode it in the URL. Otherwise, you should make it a field of the form, such that the user can pick an option. Personally I find it very strange that you use date_posted as a form field, since typically this is an field that I would expect to be filled in with the timestamp when the user likes the shop.
Note: the name of the models is normally singular, so Shop instead of Shops.

Related

Django: Use ImageField in Modelforms

So I have this model forms:
User = get_user_model()
class UserRegisterForm(forms.ModelForm):
username = forms.CharField(label='', widget=forms.TextInput(attrs={'placeholder': 'Username'}))
email = forms.EmailField(label='', widget=forms.TextInput(attrs={'placeholder': 'Email Address'}))
email2 = forms.EmailField(label='', widget=forms.TextInput(attrs={'placeholder': 'Confirm Email'}))
password = forms.CharField(label='', widget=forms.PasswordInput(attrs={'placeholder': 'Password'}))
avatar = forms.ImageField(upload_to='profile_images')
class Meta:
model = User
fields = [
'username',
'email',
'email2',
'password'
]
But this appear
TypeError: __init__() got an unexpected keyword argument 'upload_to'
The problem is that I think it will works if I add the ImageField object to the model, but I dont have a model, As you can see I am using the get_user_model(), is there a way to use upload_to in model forms, or how can I add to the default 'get_user_model' the ImageField object?
You should make an extra model then to store the avatar, or you can make a custom user model.
If you make an extra model, for example Profile, you can define this as:
# app/models.py
from django.conf import settings
from django.db import models
class Profile(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
editable=False
)
avatar = models.ImageField(upload_to='profile_images/')
Then you can make two ModelForms for example. In fact for the User, you better use the UserCreationForm [Django-doc], since this already implements logic to validate if the passwords match, and it will also transparently hash the password.
You thus can define a ModelForm for the Profile, and work with:
# app/forms.py
from django import forms
from app.models import Profile
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['avatar']
In the view, you then work with two forms:
# app/views.py
from app.forms import ProfileForm
from django.contrib.auth.forms import UserCreationForm
def some_view(request):
if request.method == 'POST':
form = UserCreationForm(request.POST, request.FILES)
form2 = ProfileForm(request.POST, request.FILES)
if form.is_valid() and form2.is_valid():
user = form.save()
form2.instance.user = user
form2.save()
return redirect('name-of-some-other-view')
else:
form = UserCreationForm()
form2 = ProfileForm()
return render(request, 'name-of-some-template.html', {'form': form, 'form2': form2})
and you thus render both forms in the same <form> tag:
<form action="{% url 'some_view' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
{{ form2 }}
</form>

How to retrieve and assign current user object to a field in Wagtail admin?

I have a few Django models that I display in the admin using wagtail’s modelAdmin. few of the fields in the models are referencing the user model. Since I’m not creating the form/page and it’s handled by wagtail, how do I pass the current user object to the field when it’s saved? That is, the created and updated by fields should have the current user object assigned to them.
See code snippet below, currently I'm assigning the user manually by querying, instead I'd like to get the current user.
from django.db import models
from django.conf import settings
from django.contrib.auth import get_user_model
from wagtail.admin.forms import WagtailAdminPageForm
STATUS_CHOICES = (
(1, 'Active'),
(2, 'Inactive')
)
class BasePageForm(WagtailAdminPageForm):
def save(self, commit=True):
auth_user_model = get_user_model()
default_user = auth_user_model.objects.get(username='admin')
page = super().save(commit=False)
if not page.pk:
page.created_by = default_user
page.updated_by = default_user
else:
page.updated_by = default_user
if commit:
page.save()
return page
class BaseModel(models.Model):
created_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='created%(app_label)s_%(class)s_related'
)
created_at = models.DateTimeField(auto_now_add=True)
updated_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='updated%(app_label)s_%(class)s_related'
)
updated_at = models.DateTimeField(auto_now=True)
status = models.IntegerField(choices=STATUS_CHOICES, default=1)
class Meta:
abstract = True # Set this model as Abstract
base_form_class = BasePageForm

Django modelformset form is not blank when I return

If the database is empty and I go to my form it looks the way it is supposed to. There is two spots for parent information and two spots for child information. If I fill the form out and submit it I get no errors and I get taken to the thank you page. When I go back to the page with the form there are now four spots for parent information and four spots for child information. Two of the spots for child and parent information are filled out with the data that is now in the database. If you fill in the blank fields new data will get added to the database but if you change any information in the already populated fields it will change the information of the data already in the database. I have even tried manually inputing the data through the admin portal but when I go to the form the information I put in still shows up. It's like the formset is pulling information out of the database. How do I get this form so that when I go back to it after submitting data the form is blank again?
Form after data submission part 1
Form after data submission part 2
models.py
from django.db import models
class Child(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
birthday = models.DateField()
allergies = models.CharField(max_length=30)
def __str__(self):
return self.first_name + ' ' + self.last_name
class Parent(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
child = models.ManyToManyField(Child)
def __str__(self):
return self.first_name + ' ' + self.last_name
class Household(models.Model):
household_name = models.CharField(max_length=30)
parent = models.ManyToManyField(Parent)
def __str__(self):
return self.household_name
forms.py
from django import forms
from .models import Child, Household, Parent
class HouseholdForm(forms.ModelForm):
class Meta:
model = Household
fields = ('household_name',)
class ParentForm(forms.ModelForm):
class Meta:
model = Parent
fields = ('first_name', 'last_name',)
class ChildForm(forms.ModelForm):
class Meta:
model = Child
fields = ('first_name', 'last_name', 'birthday', 'allergies',)
views.py
from django.forms import modelformset_factory
from django.shortcuts import get_object_or_404, render, redirect
from .forms import ChildForm, HouseholdForm, ParentForm
from .models import Child, Parent, Household
def register(request):
ParentFormSet = modelformset_factory(Parent, form=ParentForm, extra=2)
ChildFormSet = modelformset_factory(Child, form=ChildForm, extra=2)
if request.method == "POST":
formset1 = ParentFormSet(request.POST, prefix="parent",)
formset2 = ChildFormSet(request.POST, prefix="child",)
if formset1.is_valid() and formset2.is_valid():
formset1.save()
formset2.save()
return redirect('thanks',)
else:
formset1 = ParentFormSet(prefix="parent",)
formset2 = ChildFormSet(prefix="child",)
return render(request, 'register.html', {'formset1': formset1, 'formset2': formset2,})
def thanks(request):
return render(request, 'thanks.html')

Django ImageField Upload

I am trying to use Django ImageField to allow a user to upload a profile picture. However, after browsing for the image, when I attempt to update the profile, the picture upload changes from the file name to "No file selected" and I receive "This file is required" error.
If it helps, I was following along with this tutorial. I do understand that he uses two character fields, but I was attempting to change it to handle FileFields. From other questions such as this one on stack overflow, I know that the form requires a request.FILES as well.
Here is my Views.py.
#login_required
def user_profile(request):
if request.method == 'POST':
form = UserProfileForm(request.POST, request.FILES, instance=request.user.profile)
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/loggedin')
else:
user = request.user
profile = user.profile
form = UserProfileForm(instance=profile)
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('profile.html', args)
Additionally, I have these two lines in my settings.
AUTH_PROFILE_MODULE = 'userprofile.UserProfile'
MEDIA_ROOT = 'E:\Pictures\django_stuff'
Let me know if there is anything else that is required.
As requested by Erny
Forms.py
from django import forms
from models import UserProfile
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('logo', 'description')
Models.py
class UserProfile(models.Model):
user = models.OneToOneField(User)
logo = models.ImageField(upload_to = 'photos')
description = models.TextField()
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])

Django: error with "username" in my custom user model - 'UserProfile' object has no attribute 'username'

I'm new with Django and I'm having some problems creating a custom user model. I followed every steps from the django documentation. Here is my model :
class UserProfile(models.Model):
user = models.OneToOneField(User)
comment = models.BooleanField()
score = models.IntegerField(null=True)
profilpic = models.ImageField(upload_to="/profilepics")
bio = models.CharField(max_length=140)
Then I created several users with django-registration. But when I go to the admin and I try to delete a user I created or when I just try to click on the username, I get this error:
AttributeError at /admin/auth/user/3/
'UserProfile' object has no attribute 'username'
Exception Value:
'UserProfile' object has no attribute 'username'
Exception Location: /Users/marc-antoinelacroix/Desktop/Site/sportdub/projet/models.py in __unicode__, line 14
So I think I have to create a "username" in my UserProfile model, and associate it to the username of the django's User, but I have no idea how to do it...
Any help would be welcome.
Thanks!
It seems like you're trying to access
def __unicode__(self):
return self.username
but it has to be
def __unicode__(self):
return self.user
Here's a demo
project/account/models.py
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
homepage = models.URLField(verify_exists=False)
#...
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
project/account/admin.py
from django.contrib import admin
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from account.models import UserProfile
admin.site.unregister(User)
class UserProfileInline(admin.StackedInline):
model = UserProfile
class UserProfileAdmin(UserAdmin):
inlines = [UserProfileInline]
admin.site.register(User, UserProfileAdmin)
project/settings.py
AUTH_PROFILE_MODULE = "account.userprofile"
No, you need to define UserProfile.__unicode__() properly. It needs to get the username from the related User model.

Resources