I ran into a situation where I had developed a method called edit and passed both the profile and user forms into it when I wanted to modify a profile.
#login_required
def edit(request):
if request.method == 'POST':
user_form = UserEditForm(instance=request.user,data=request.POST)
profile_form = ProfileEditForm(instance=request.user.profile,data=request.POST,files=request.FILES)
if user_form.is_valid() and profile_form.is_valid():
user_form.save()
profile_form.save()
else:
user_form = UserEditForm(instance=request.user)
profile_form = ProfileEditForm(instance=request.user.profile)
return render(request,'users/edit.html',{'user_form':user_form,'profile_form':profile_form})
this is my views.py where i have written the logic
and coming to urls.py
path('edit/',views.edit,name='edit'),
and the edit.html code follows like this
{% extends 'users/base.html' %}
{% block body %}
<h2>Edit profile form</h2>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ user_form.as_p }}
{{ profile_form.as_p }}
<input type="submit"/>
</form>
{% endblock %}
This is my models.py file
from django.db import models
from django.conf import settings
# Create your models here.
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
photo = models.ImageField(upload_to='users/%Y/%m/%d',blank=True)
def __str__(self):
return self.user.username
The main project urls.py
from django.contrib import admin
from django.urls import path,include
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
path('admin/', admin.site.urls),
path('users/',include('users.urls'))
]
urlpatterns += static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
the output shows me like this
I am expecting a better solution to resolve this issue
This means that there is no Profile model instance for that user. You may want to use django postsave signals to create a Profile model instance for any user that has been created.
To test this, use the admin page to create a Profile model instance for that user and check if it still generates the error.
I hope this helps.
Related
trying to create an edit profile for users and i keep getting this error what should i add or change ? is my models right for UserEditView
this is my views.py (all of it edited)
maybe the vendor its not compatitable with User edit view
anything elses needs to be added or should i just change something
all imports are for vendor and UserEditView
from tkinter import Entry
from django.contrib.auth.models import User
from xml.dom.minidom import Entity
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
from django.urls import reverse_lazy
from django.views import generic
from django.contrib.auth.forms import UserCreationForm , UserChangeForm
from django.utils.text import slugify
from django.shortcuts import render, redirect
from .models import Profile, Vendor
from products.models import Product
from .forms import ProductForm
# Create your views here.
def become_vendor(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
vendor = Vendor.objects.create(name=user.username, created_by=user)
return redirect('home')
else:
form = UserCreationForm()
return render(request, 'vendor/become_vendor.html', {'form': form})
#login_required
def vendor_admin(request):
context = {
'user':request.user
}
vendor = request.user.vendor
products = vendor.products.all()
return render(request,'vendor/vendor_admin.html',{'vendor': vendor , 'products': products ,'context':context})
#login_required
def add_house(request):
if request.method == 'POST':
form = ProductForm (request.POST, request.FILES)
if form.is_valid():
product = form.save(commit=False)
product.vendor = request.user.vendor
product.slug = slugify(product.عنوان)
product.save()
return redirect('vendor_admin')
else:
form = ProductForm()
return render(request,'vendor/add_house.html',{'form': form})
class UserEditView(generic.UpdateView):
models = User
form_class = UserChangeForm
template_name = 'vendor/edit_profile.html'
seccess_url = reverse_lazy('vendor_admin')
def get_object(self):
return self.request.user
urls.py
from django.urls import path
from .import views
from .views import UserEditView
from django.contrib import admin
from django.contrib.auth import views as auth_views
urlpattern =[
path('signup/', views.become_vendor, name='become_vendor'),
path('profile/', views.vendor_admin, name='vendor_admin'),
path("logout/", auth_views.LogoutView.as_view(), name="logout"),
path('login/', auth_views.LoginView.as_view(template_name='vendor/login.html'), name='login'),
path('edit_profile/', UserEditView.as_view(template_name='vendor/edit_profile.html'), name='edit_profile'),
]
edit_profile.html
(where the error pops up)
{% extends "base.html"%}
{% load static %}
{% block content %}
<title>title</title>
<div class="section pt-9 pb-9">
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="section-title">
<div class="wrap-title">
<h3 class="title">
<span class="first-word"></span>
</h3>
<br>
<form method="post" >
{% csrf_token %}
<table>
{{ form.as_p }}
</table>
<button class='button'>Update</button>
</form>
</div>
<hr>
{% endblock content %}
I think that you didn't declare your model correctly:
class UserEditView(generic.UpdateView):
# models = UserChangeForm #That has no sense.
model = User #The name of your model (Probably the default one: User).
form_class = UserChangeForm
template_name = 'vendor/edit_profile.html'
success_url = reverse_lazy('vendor_admin')
def get_object(self):
return self.request.user
Other thing. You have declared your template name twice. According to your views.py you can delete the template_name on your urls.py:
path('edit_profile/', UserEditView.as_view(), name='edit_profile'),
I using Django with widgets to get some user input but I can't seem to get it to display even thou the code seems almost identical to examples online.
forms.py
from django import forms
class PickerIDForm(forms.Form):
pickeID = forms.NumberInput()
views.py
def get_id(request):
template = loader.get_template('metrics/lance1.html')
def get(self, request):
form = PickerIDForm()
return render(request, 'self.template', {'form': form})
context ={
}
return HttpResponse(template.render(context,request))
urls.py
from django.urls import path
from . import views
from . import mark_views
app_name = 'metrics'
urlpatterns = [
path('', views.index, name='index'),
path('test/', views.get_id, name='get_id'),
]
test.html
{% extends 'base.html' %}
{% block content %}
<p>User Input</p>
<form method = "post" >
{% csrf_token %}
{{form.as_p}}
<button type="submit"> Submit </button>
</form>
{% endblock %}
I'm never directly calling the get function as defined in views.py that to me seems to be a possible source of the input fields not showing up when I load up test.html
At what point do you link the disparate parts together? Because it seems I'm missing something.
You have defined the widget instead of the field in your form.
To fix that replace pickeID = forms.NumberInput() with pickeID = forms.IntegerField()
And also write your view like this:
def get_id(request):
form = PickerIDForm()
return render(request, 'metrics/lance1.html', {'form': form})
Ive been Playing around with django to create an asset management app and have hit a wall on the file upload to model instance behaviour.
I am attempting to use the ModelForm class in Forms.py
Basically im pretty certain that form.save() is not writing my uploaded file to disk to update my model instance.
Do I have to write a form.save definition into my AssetForm ? or have I missed something else.
Appreciate any help.
My project is built around the Polls tutorial https://docs.djangoproject.com/en/1.8/intro/tutorial01/ and the minimal file upload tutorial at Need a minimal Django file upload example.
Here is my model .py
class Category(models.Model):
category_text = models.CharField(max_length=200)
def __str__(self): # __unicode__ on Python 2
return self.category_text
class Asset(models.Model):
asset_text = models.CharField(max_length=200)
asset_tag = models.CharField(max_length=200)
asset_category = models.ForeignKey(Category)
cert_date = models.DateTimeField('cert published')
def __str__(self): # __unicode__ on Python 2
return self.asset_text
def was_certed_recently(self):
return self.cert_date >= timezone.now() - datetime.timedelta(days=365)
was_certed_recently.admin_order_field = 'cert_date'
was_certed_recently.boolean = True
was_certed_recently.short_description = 'Certified recently?'
docfile = models.FileField(upload_to='documents')
Here is my forms.py
from django import forms
from django.forms import ModelForm
from polls.models import Asset
class AssetForm(ModelForm):
class Meta:
model = Asset
fields = '__all__'
Here is my views.py
# -*- coding: utf-8 -*-
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.http import HttpResponse
#from django.template import RequestContext, loader
from django.shortcuts import get_object_or_404, render
from django.http import Http404
from polls.models import Asset
from polls.forms import AssetForm
def list(request, asset_id):
# Handle file upload
ID = asset_id
p = get_object_or_404(Asset, pk = asset_id)
if request.method == 'POST':
form = AssetForm(request.POST, request.FILES, instance= p )
if form.is_valid():
form.save()
# Redirect to the document list after POST
return HttpResponseRedirect(reverse('list', args=(p.id,)))
else:
form = AssetForm() # A empty, unbound form
# Load documents for the list page
documents = p
# Render list page with the documents and the form
return render_to_response(
'polls/list.html',
{'documents': documents, 'ID': ID, 'form': form},
context_instance=RequestContext(request )
)
def index(request):
latest_asset_list = Asset.objects.order_by('-cert_date')[:]
context = {'latest_asset_list': latest_asset_list}
return render(request, 'polls/index.html', context)
url.py
from django.conf.urls import url
from . import views
urlpatterns = [
#url(r'^/list/$', 'list', name='list'),
url(r'^$', views.index, name='index'),
# ex: /polls/5/
url(r'^(?P<asset_id>[0-9]+)/$', views.list, name='list'),
# ex: /polls/5/results/
url(r'^(?P<asset_id>[0-9]+)/results/$', views.results, name='results'),
# ex: /polls/5/vote/
url(r'^(?P<asset_id>[0-9]+)/vote/$', views.vote, name='vote'),
]
Finally my list.html template
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Minimal Django File Upload Example</title>
</head>
<body>
<!-- List of uploaded documents -->
{% if documents %}
<ul>
<p>Current Doc.</p>
<li>{{ documents.docfile.name }}</li>
</ul>
{% else %}
<p>No documents.</p>
{% endif %}
<ul>
{{ ID }}
<!-- Upload form. Note enctype attribute! -->
<form action="{% url 'list' ID %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.non_field_errors }}</p>
<p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
<p>
{{ form.docfile.errors }}
{{ form.docfile }}
</p>
<p><input type="submit" value="Upload" /></p>
</form>
</body>
</html>
You're doing various things twice. For example, at the start of your function, you get an Asset into p and then you get the same one into a. Why?
More significantly, in the is_valid() block you create a new Asset object just from the uploaded file, with no other data from the form, but then you save the form itself which should update the existing Asset. This might be the cause of your problem - you should remove the lines with docfile and just save the form.
I tried to make simple request form. And I need to redirect user to "thank you" page after successful form sent. But after user hit "send" button - nothing happens. Just reload form page without form cleaning also.
Form is on "call" page, redirect needs "confirm" page...
So, task is: user fill the form on page "call" and after hitting "send" button, goes to "confirm" page.
My model:
# -*- coding: utf-8 -*-
from django.db import models
from django.forms import ModelForm
# Create your models here.
class Join(models.Model):
class Meta():
db_table = 'expert_request'
user_expert = models.CharField(max_length=100)
user_name = models.CharField(max_length=100)
user_cost = models.CharField(max_length=100)
user_email = models.EmailField()
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
def __unicode__(self):
return self.user_email
my "forms.py":
from django import forms
from userform.models import Join
class JoinForm(forms.ModelForm):
class Meta:
model = Join
This is my "views.py":
from django.shortcuts import render
from django.shortcuts import HttpResponseRedirect, Http404
# Create your views here.
from userform.forms import JoinForm
from userform.models import Join
def userform(request):
form = JoinForm(request.POST or None)
if form.is_valid():
new_join = form.save(commit=False)
new_join.save()
HttpResponseRedirect('/confirm/')
context = {"form": form}
template = "userform.html"
return render(request, template, context)
def confirm(request):
return render(request, 'confirm.html')
This is my URL's:
from django.conf.urls import patterns, include, url
from django.contrib import admin
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
(r'^tinymce/', include('tinymce.urls')),
url(r'^$', 'expert.views.index', name='index'),
url(r'^(\d+)/?$', 'expert.views.index'),
url(r'^call/$', 'userform.views.userform', name='call'),
url(r'^confirm/$', 'userform.views.confirm', name='confirm'),
)
My template "userform.html":
{% load staticfiles %}
<form style="position:relative" method="POST" action="">{% csrf_token %}
{{ form.user_expert }}
<p style="position:absolute; top:50px; left:20px; color:#FF0000;">{{ form.user_expert.errors.as_text }}</p>
{{ form.user_name }}
<p style="position:absolute; top:182px; left:20px; color:#FF0000;">{{ form.user_name.errors.as_text }}</p>
{{ form.user_cost }}
<p style="position:absolute; top:50px; left:380px; color:#FF0000;">{{ form.user_cost.errors.as_text }}</p>
{{ form.user_email }}
<p style="position:absolute; top:182px; left:380px; color:#FF0000;">{{ form.user_email.errors.as_text }}</p>
<button type="submit">Send</button>
<div class="clear"></div>
</form>
Maybe you forgot the return statement in userform view function? Fix its beginning like this:
def userform(request):
form = JoinForm(request.POST or None)
if form.is_valid():
new_join = form.save(commit=False)
new_join.save()
return HttpResponseRedirect('/confirm/')
Could you please help me with Django and custom user model? I'm a new in Django world, so I started to learn from newest version 1.7. In my project I'm using django-allauth package and I want to create OneToOne relationship between standard user class from contrib.auth and my custom model "users".
#models.py
import datetime
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user=models.OneToOneField(User)
f_name=models.CharField(null=True, blank=True, max_length='30')
l_name=models.CharField(null=True, blank=True, max_length='30')
birth_date=models.DateField(null=True, blank=True)
company=models.CharField(null=True, blank=True, max_length='30')
rate=models.FloatField(null=True, blank=True, default=0.0)
skills=models.CharField(null=True, blank=True, max_length='255')
bill_rate=models.CharField(null=True, blank=True, max_length='255')
contacts=models.CharField(null=True, blank=True, max_length='255')
portfolio=models.CharField(null=True, blank=True, max_length='127')
avatar = models.ImageField(upload_to='/static/img/%Y/%m/%d', blank=True, null=True)
def __unicode__(self):
return self.user.username
This is forms.py
#forms.py
from django.forms import ModelForm
from users.models import Profile
class ProfileForm(ModelForm):
class Meta:
model = Profile
fields = ('f_name', 'l_name', 'company', )
This is a template:
{% extends "base_.html" %}
{% block main_content%}
<div>
{% if user.is_authenticated %}
<p>Welcome, {{ request.user.id }}!</p>
<form id="profile_form" method="POST" action="/accounts/profile" enctype="multipart/form-data">
{% csrf_token %}
{{ profile_form.as_p }}
<input type="submit" name="submit" value="Save" />
</form>
{% endif %}
</div>
{% endblock%}
And views.py:
from django.http import HttpResponse
from django.template import RequestContext
from django.conf import settings
from django.shortcuts import render, render_to_response
from models import Profile
from forms import ProfileForm
def edit(request):
profile_form = ProfileForm()
user = request.user
if request.method == 'POST':
profile_form = ProfileForm(data=request.POST, instance=user)
if profile_form.is_valid():
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
return render_to_response("profile.html", RequestContext(request))
return render_to_response('profile_edit.html', RequestContext(request, {'profile_form' : profile_form}))
I built all of this files according by this tutorial:
http://www.tangowithdjango.com/book/chapters/login.html
And finally, all of this works fine, but when I push Save button, POST form doesn't work. I can't see any changes in database. Redirecting works good, actually it seems that all works fine, but I don't have any data in table (I'm using postgres by the way).
I spent a lot to find the answer and tried almost everything in the internet, but I still have this issue. Maybe I can't understand how it works from django documentation, but I tried the same method and still have a problem.
Thank you in advance!
UPDATE:
My urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
urlpatterns = patterns('',
# Examples:
url(r'^$', 'laniakea.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
url(r'^admin/', include(admin.site.urls)),
url(r'^accounts/', include('allauth.urls')),
url('accounts/profile', 'laniakea.views.prof', name='prof'),
url(r'^edit', 'users.views.edit', name='edit'),
)
I found a solution! As Daniel said, I changed "action" attribute to transfer POST request to the same form. And as I discovered, I not created a right instance of User parent class. Actually, I don't need to use them.
#views.py
from django.template import RequestContext
from django.shortcuts import render
from models import Profile
from forms import ProfileForm
def edit(request):
user = request.user
if request.method == 'POST':
profile_form = ProfileForm(request.POST)
if profile_form.is_valid():
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
return HttpResponseRedirect('accounts/profile')
else:
profile_form = ProfileForm()
return render(request, 'profile_edit.html', {'profile_form' : profile_form})
and
#profile_edit.html
{% extends "base_.html" %}
{% block main_content%}
<div>
{% if user.is_authenticated %}
<p>Welcome, {{ request.user.id }}!</p>
<form id="profile_form" method="POST" action="" enctype="multipart/form-data">
{% csrf_token %}
{{ profile_form.as_p }}
<input type="submit" name="submit" value="Save" />
</form>
{% endif %}
</div>
{% endblock%}
Thank you very much for help and good luck!