managing ManyToManyField to itself in Django - django

I have the following model:
class MyUser(User):
# some fields...
contact = models.ManyToManyField("self", through='Contact', symmetrical=False, related_name="contact_set" )
class Contact(models.Model):
user1 = models.ForeignKey( MyUser, related_name="contact_set1")
user2 = models.ForeignKey( MyUser, related_name="contact_set2")
confirmed = models.BooleanField()
and this view to create a contact
def add_contact( request, username=None ):
if username:
try:
user = MyUser.objects.get(username=username)
except User.DoesNotExist:
user = None
if user:
contact = Contact( user1 = MyUser.objects.get(pk=request.user.id), user2=user, confirmed=False )
contact.save()
return render_to_response( "accounts/add_contact.html", {'user': user,} )
else:
return HttpResponseRedirect("/home")
def list_contacts( request, username=None ):
if username:
try:
user = MyUser.objects.get(username=username)
except User.DoesNotExist:
user = None
else:
user = MyUser.objects.get(pk=request.user.id)
if user:
contacts = user.contacts.all()
return render_to_response("accounts/list_contacts.html", {'contacts': contacts,} )
else:
return HttpResponseRedirect("/home")
Ok now... the code should be verbose enough, so I'll explain it briefly: Social networking, users add others to their contacts ("friends", "buddies", however you call it). If user A adds user B, B is also in contact with A...
The code works... but only one-way. If I'm logged in as user A and want to add user B to my contacts, B will show up on my contact list, but not the other way around. But I want also to show up on B's contact list - it should make no difference, who added whom. How may I manage that?

Docs. Docs says to pass "self"(as string).
Also, see this question.
Good luck. I hope, you will succeed in development.

Related

DoesNotExist at /folder/ Userdata matching query does not exist. DJango Problem

When i use my super acc, this error does not shows up, but when I tried to use other acc. this error shows up. where did I do wrong?
The error : DoesNotExist at /voting/
Userdata matching query does not exist.
My Model :
class Userdata(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
faculty = models.ForeignKey(Fakultas, on_delete=models.CASCADE, default=1)
is_voted = models.BooleanField(default=False)
def __str__(self): return self.user.username
My views :
#login_required
def voted(response):
user = Userdata.objects.get(id=response.user.id) # get the username
if user.is_voted:
return render(response, 'Main/voting.html', {'calon': Voting.objects.order_by('id'), 'hasil': 'You Have Voted'})
if response.method == 'POST':
id = response.POST['idcalon']
calon2 = Voting.objects.get(id=id) # get user selection in html
user.is_voted = True
calon2.voters += 1
user.save()
calon2.save()
return render(response, 'Main/voting.html', {'calon': Voting.objects.order_by('id')}) # balik ke sendiri
User and UserData don't have the same primary key. So Userdata.objects.get(id=response.user.id) will not work because there is no such Userdata with the given user's id. But you do not need that, because User and Userdata have OneToOne relation. So simply use this:
user = response.user.userdata

Auto fill ForeignKey(User) with current signed in user

I have this model called business I want the foreinkey field owner to get the logged in user name automatically without bringing the dropdown button of all users, I have tried some methods, but it doesn't work. How can I autofill the owner field with the logged in user
models.py
class User(AbstractUser):
phone_number = models.CharField(('phone number'), max_length=15,default='+234',
help_text=('Field to save the phone number of the user.'),unique=True)
fullname=models.CharField(max_length=50)
Affidavit=models.ImageField(upload_to='media/')
class Business(models.Model):
owner = models.ForeignKey(User,on_delete=models.CASCADE,default=1)
Phone_Number=models.IntegerField(default='086878432',unique=True)
Figi_ID=models.IntegerField(blank=True)
views.py
def details_business(request):
if request.user.is_authenticated:
business_form=Business()
if request.method=='POST':
business_form=Business_owner_form(request.POST,request.FILES)
if business_form.is_valid():
bform=business_form
bform.owner=request.user
bform.save()
def dashboard(request):
if request.user.is_authenticated:
context = RequestContext(request)
data = Business.objects.all()
current=request.user
print(current)
context={"obj":img}
return render(request,'dashboard.html',context)
You were supposed to call the forms save method.
if business_form.is_valid():
business = business_form.save()
business.owner = request.user
business.save()

Redirect and 'field' keyword issues when retriving objects from database

I have 3 models Account,Company, and Products.
Company can have multiple products, Account can have multiple Companies.
class Product(Meta):
company = models.ForeignKey(Company, related_name='products', on_delete=models.CASCADE)
class Company(Meta):
account = models.ForeignKey(Account, related_name='account', on_delete=models.CASCADE)
I'm using Django 2.0 new url patterns, and I defined the urls:
path('dashboard/', include('accounts.urls', namespace='accounts')),
in accounts urls.py
path('companies/<int:pk>/', AccountCompanyDetailView.as_view(), name='detail_company'),
In a CBV I'm trying to get a Product instance, if the Product doesn't exist, check if Company doesn't exist and base on the above results do a redirect.
I overwrite the def get_object(self):
class AccountCProduct(DetailView):
model = Product
template_name_suffix = '_account_detail'
def get_object(self):
company_pk = self.kwargs.get('pk1')
product_pk = self.kwargs.get('pk2')
account = self.request.user.account
if not account:
raise Http404
try:
product = Product.objects.get(company__account=account, company__pk=company_pk, pk=product_pk)
except Product.DoesNotExist:
try:
company = Company.objects.get(account=account, pk=company_pk)
print(company)
except Company.DoesNotExist:
return redirect('accounts')
print('redirect 1')
return redirect('accounts:detail_company', pk=company_pk)
return product
If I use it as above (with Company code commented) when a product is wrong there is no error but redirect doesn't happen.
If I un-comment the company part, I receive field error:
Cannot resolve keyword 'company' into field.
company is the ForeignKey on the Product Model to the Company Model.
I'm doing the Company lookup after, and not before, Product lookup not to do two lookup(s) if is not necessary.
What I want to achieve, example:
Account has 2 Companies with ids 1 and 2 and Company 1 has Product with id 1
http://127.0.0.1:8000/dashboard/companies/1/products/1/
will go to the product of Company 1
http://127.0.0.1:8000/dashboard/companies/1/products/2/
will fail because company 1 doesn't have a Product with id 2 and redirect to company 1 detail page
http://127.0.0.1:8000/dashboard/companies/3/products/2/
will fail because first doesn't found the product and then doesn't found a Company with id 3 in the account and returns to account dashboard
You cannot do a redirect from inside the get_object() method. That method must return a model object - you cannot return responses from there.
You need to do this logic in the get() method instead. I think it's easiest just to replace the whole method:
def get(self, request, *args, **kwargs):
company_pk = kwargs.get('pk1')
product_pk = kwargs.get('pk2')
account = request.user.account
if not account:
raise Http404()
try:
self.object = Product.objects.get(company__account=account, company__pk=company_pk, pk=product_pk)
except Product.DoesNotExist:
try:
company = Company.objects.get(account=account, pk=company_pk)
except Company.DoesNotExist:
return redirect('accounts')
return redirect('accounts:detail_company', pk=company_pk)
context = self.get_context_data(object=self.object)
return self.render_to_response(context)
Note that you are setting self.object directly here, and no longer using get_object() at all.

Django 1.4 Modifying Custom Account Model for Uniqueness of E-mail Addresses

I've already defined a custom user account that utilizes several built in's from the auth User model and, using the user link, links these with some additional fields that I needed to register a user on the database.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
relevant from my models.py
# additional model to incorporate our custom fields to the auth user model
class Account(models.Model):
user = models.OneToOneField(User) #link (pointer) to the users other information in User model
birthdate = models.DateField(blank = True, ) # True makes this field optional
gender = models.CharField(max_length = 1, choices = GENDER_CHOICE, null = True, blank = True)
def __unicode__(self): # define a unicode for the user to access
return u'%s %s' % (self.user.first_name, self.user.last_name) # return first and last name in shell
# custom form to gather information from the user for a new account
class UserRegistration(UserCreationForm):
#class RegistrationForm(forms.ModelForm):
class Meta:
model = User
fields = ("first_name", "last_name", "email", "username", "password1", "password2",)
# ensures uniqueness of user email addresses when registering
def clean_email(self):
print "In custom creation"
email = self.cleaned_data.get(email = 'email')
username = self.cleaned_data.get(username = 'username')
# checks if email address already exists
if User.objects.filter(email__iexact = self.cleaned_data['email']):
print "Email exists"
# if email and User.objects.filter(email__iexact = email).exclude(username=username).exists():
raise forms.ValidationError(u'Email Address is currently used by another user.')
return email
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
relevant from views.py
def Main(request):
if request.user.is_authenticated():
latest_events = Event.objects.all().order_by('-created')[:10] # Returns latest 10 events
my_events = Event.objects.filter(creator=request.user)[:10] # Returns up to 10 events created by current User
my_calendars = Calendar.objects.filter(creator=request.user) # Returns all calendars created by the user
authForm = None
loginForm = None
headerType = "header.html"
else:
latest_events = None
my_events = None
my_calendars = None
headerType = "header_main.html"
authForm = UserRegistration(request.POST or None)
print "Creating account UserRegistration" # TESTING PRINT
print "User email = %s " %(User._meta.get_field('email'))
if request.method == 'POST':
if authForm.is_valid():
newUser = authForm.save(commit=False)
newUser.save()
newUser = authenticate(username=request.POST['username'], password=request.POST['password1'])
login(request, newUser)
return HttpResponseRedirect('/signup/')
....
....
more code on success redirection
....
....
~~~~~~~~~~~~~~~~~~~~~~~~~~~
(I hope I didn't post too much code, just wanted to be thorough)
As you can see there are a few commented out attempts I've made recently. I tried using thee built in RegistrationFormUniqueForm() by downloading 'registration' but I don't actually want to make a new registration form since I already have a working one.
I moved on to trying another suggestion, the code under the comment
# custom form to display additional sign up information
When I tried registering a new user with an already registered email it did not throw any error and allowed the registration. I also tried changing the users email and it allowed the change to an already taken email with no objection.
Can anyone suggest a method for making user registration maintain a unique lock on each individual attempting to register with an email address that may already be taken? As well as preventing them from changing their email to one that is taken by a current user?
Thanks in advance.
EDIT: I made changes to the Models registration form def clean_email() and the def in views to reflect what I currently have that still does not work.
The indentation of your clean_email methods is wrong for both forms. At the moment, they are methods of the Meta class, so will never be called. For example, the registration form should be:
class RegistrationForm(UserCreationForm):
#class RegistrationForm(forms.ModelForm):
class Meta:
model = User
fields = ("first_name", "last_name", "email", "username", "password1", "password2",)
def clean_email(self):
"""ensures uniqueness of user email addresses when registering"""
email = self.cleaned_data.get('email')
This might not be the real problem -- it's easy to get the indentation wrong when pasting code into stack overflow. If that's the case, I'll delete the answer.

how to overide in forms queryset none() attribute and somehow allow to save the field?

I have models.py
class Visit(Model):
reference_visit = models.ForeignKey('self',
help_text="Visit needs a refrence to Prior Visits",
null=True, blank=True)
show_prior_responses = models.BooleanField(default=False,
help_text="Show PriorResponses")
# has many field but i am making it short.
def __unicode__(self):
result = """Visit id:%s pt:%s""" % (self.id, self.patient.id)
return result
forms.py
class VisitSetupForm(Form):
list_visit_ids = ModelChoiceField(
queryset=Visit.objects.none(),
empty_label='Select Revisit ID',required=False)
show_prior_visit = ModelChoiceField(
queryset=User.objects.all(),
empty_label="Select User for Revisit",required = False)
has many but question is on list_visit_ids.
views.py
def setup(request):
"""
Allow an Admin user the ability to setup a patient & visit all at once.
"""
if request.user.is_superuser:
form_class = AdminVisitSetupForm
all_topics = True
else:
form_class = VisitSetupForm
all_topics = False
f = form_class()
# Get a list of topics for each report.
report_topics = {}
for r in Interview.objects.all():
report_topics[r.id] = [t['ad'] for t in r.topics.values('ad')]
data = {
'superuser':request.user.is_superuser,
'report_topics':simplejson.dumps(report_topics)
}
try:
request.user.reviewer
data['reviewer'] = True
except:
pass
if request.method == "POST":
f = form_class(request.POST)
if f.is_valid():
# Create the patient, generate a password, and send them on their way.
cd = f.cleaned_data
patient = None
if cd['revisit']:
# Check for an existing user first.
try:
patient = Patient.objects.get(username=cd['username'])
except Patient.DoesNotExist, e:
data['form'] = f
data['msg'] = 'There is no user with this username.'
return render_to_response('visit/setup.html', data, context_instance=RequestContext(request))
admin_user = get_user(request)
organization = None
if admin_user:
organization = admin_user.organization
if patient and not request.user.is_superuser:
# Make sure the patient they've selected is one of their own.
if patient.organization != organization:
return HttpResponseForbidden('You are not allowed to see this page.')
if not patient:
password = generate_password()
user = User.objects.create_user(cd['username'], cd['contact_email'], password)
user.first_name = cd['first_name']
user.last_name = cd['last_name']
user.save()
patient = Patient(
user=user,
username=user.username,
contact_phone=cd['contact_phone'],
date_of_birth=cd['date_of_birth'],
email=user.email,
first_name=user.first_name,
gender=cd['gender'],
last_name=user.last_name,
maiden_name=cd['maiden_name'],
organization=organization,
patient_type=cd['patient_type'],
security_answer=cd['security_answer'],
security_question=cd['security_question'],
)
patient.save()
# Send them an email.
t = loader.get_template('www/new_account.txt')
c = Context({
'password':'%s-%s-%s' % (password[:3], password[3:5], password[5:]),
'patient':patient
})
msg = t.render(c)
try:
send_mail(
'A request by your physician to do an online medical history before your appointment.',
msg,
'support#careprep.com',
[user.email]
)
except Exception, e:
log.error('Could not send email for new account %s because: [%s]' % (user.username, e))
request.session['password'] = password
# Create the Visit, too.
interview = cd['interview']
list_visit_ids = cd['list_visit_ids']
print list_visit_ids
visit = Visit(
reference_visit = cd['list_visit_ids'],
show_prior_responses = cd['show_prior_responses'],
patient=patient
)
if request.user.is_superuser:
topics = cd['topics']
else:
topics = set(list(interview.topics.all()) + list(cd['topics']))
reviewer_mode = cd.get('reviewer_mode') or patient.patient_type == 'Reviewer'
url, visit = initialize_visit(
request,
patient=patient,
starting_section=interview.starting_section,
visit_title='%s %s' % (patient, interview.title),
topics=topics,
reviewer_mode=reviewer_mode,
chief_complaint=cd['chief_complaint'],
location=cd['interview_site'],
reference_visit = cd['list_visit_ids'],
show_prior_responses = cd['show_prior_responses'],
)
next_url = "/visit/confirmation/%s/%s/?next=%s" % (patient.user.id, interview.id, url)
else:
v = Visit.objects.get(pk=request.POST['list_visit_ids'])
print v
return HttpResponseRedirect(next_url)
# all the fields that are not given pls ignore.
The template is fine.
Now watch forms.py when i do list_visit_ids = ModelChoiceField(queryset=Visit.objects.all(), empty_label='Select Revisit ID',required=False) It works perfectly fine on my local machine.But on my server it has around 6000 visit objects so this page hangs or i should say keep on loading.
So initially i changed it to list_visit_ids = ModelChoiceField(queryset=Visit.objects.none(), empty_label='Select Revisit ID',required=False)
Now i know that by this the form becomes invalid and should go to the else part Now my question how do i make reference_visit=cd['list_visit_ids'] in else (form is invalid)
case save().How do i override the none() attribute.
Thanks in advance i will really appreciate.
If your goal is to save your html page load by removing the 6000 choices (which I've done too: 10000+ <option> fields wrapped by misc html will absolutely choke a page), you shouldn't be using a ChoiceField at all. By setting queryset=Visit.objects.none() you're allowing zero choices and nothing passed in will validate.
You either show 6000 select item drop downs, radio boxes, etc., or find a way to /not/ have a giant select drop down (such as a hidden input or charfield), not fake around a ModelChoiceField who's main purpose is to populate that select drop down and validate.
In short: don't use a ModelChoiceField if you're not going to be using the html choices generated by it. Use something else and do the validation / model pulling yourself via the clean_FOO methods.
class MyForm(forms.Form):
my_input = forms.CharField()
def clean_my_input(self):
input = self.cleaned_data.get('my_input')
try:
return MyModel.objects.get(pk=input) # add a filter here if you want
# (whatever filters you were using in the queryset argument)
except MyModel.DoesNotExist:
raise forms.ValidationError("Doesn't exist / is invalid")
return input