Hi I have a post save signal which saves a user_profile object when a new User object is created:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
class UserProfile(models.Model):
user = models.OneToOneField(User)
...
def __unicode__(self):
return self.user.username
def _create_user_profile(sender, instance, created, **kwargs):
UserProfile.objects.create(user=instance)
post_save.connect(_create_user_profile, sender=User)
However, this is causing me the following problem:
If I create a new user in the admin, all good. If I then try and edit then change the User permission to staff status I get a "Duplicate entry '6' for key 'user_id'" error. I guess the UserProfile object is trying to re-save the object?
How can I avoid this conflict?
Any help much appreciated.
OK, so this helped a lot:
https://sqa.stackexchange.com/questions/1355/what-is-the-correct-way-to-select-an-option-using-seleniums-python-webdriver
Basically I needed to find the <select> and the <option> I wanted using the xpath directly. After that I could just simulate a click event:
self.browser.find_element_by_xpath(
"//select[#id='my_select_id']/option[text()='my_option_text']"
).click()
I could have also selected by option index if the text string was unkown:
self.browser.find_element_by_xpath(
"//select[#id='id_module']/option[2]"
).click()
Hope this helps anyone who has a similar problem.
Related
I am using classed based views with django 1.3 and am trying to figure out how to create an object without using the form. I do not need any user input to create the object but I am still getting an error message that the template is missing. Below is my current view where I have tried to subclass the form_valid method but its not working. Any help would be appreciated.
class ReviewerCreateView(CreateView):
model = Reviewer
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.user = self.request.user
self.object.role = 2
self.object.save()
return HttpResponseRedirect(self.get_success_url())
A CreateView is a specialized view whose purpose is to display a form on GET and validate the form data and create a new object based on the form data on POST.
Since you don't need to display a form and process the form data, a CreateView is not the tool for your job.
You either need a plain old function-based view, or, if you prefer to use a class-based view, derive from View and override get() or post(). For example, adapting your sample code:
class ReviewerCreator(View):
def get(self, request, *args, **kwargs):
Reviewer(user=request.user, role=2).save()
return HttpResponseRedirect('/your_success_url/')
I don't believe a view needs to do anything explicit with a form if it does not need one.
You can instantiate a Reviewer object. It's just a python object.
class ReviewerCreateView(CreateView):
model = Reviewer
self.object.user = self.request.user
self.object.role = 2
self.object.save()
return HttpResponseRedirect(self.get_success_url())
I have the following
class Employee(User):
emplorateID=models.OneToOneField(Code)
business=models.ForeignKey(Business)
but I have existing Users that I'd like to select in the EmployeeAdmin and enter the additional field data for. I don't see how I would customize the ModelAdmin to handle creating a new Employee from an existing User (effectively a new row in the Employee table for referencing the existing User entry)
Inheritance isn't what you want in this case; you just need another model with a OneToOneField pointing back.
Try this:
from django.contrib.auth.models import User
from django.db import models
class Employee(models.Model):
user = models.OneToOneField(User, related_name='employee')
emplorateID = models.OneToOneField(Code)
business = models.ForeignKey(Business)
It should JustWork™.
I don't know the form answer, but here is the code answer:
employee = Employee(user_ptr=existing_user,
emplorateID=something,
business=somebusiness)
employee.save_base(raw=True)
Given the code:
from django.contrib.auth.models import User
class UserProfile(models.Model):
# project userprofile, also set as AUTH_PROFILE_MODULE
user = models.ForeignKey(User, unique=True)
class AppUserProfile(UserProfile):
# some app specific extension
and the test:
user = User.objects.create()
profile = UserProfile.objects.get_or_create(user=user)
AppUserProfile.objects.create(user=user)
it fails on the last line, saying:
IntegrityError: column user_id is not unique
What I suspect is that Django uses the same table for user-userprofile and user-anotheruserprofile relationship defined by ForeignKey.
How can I solve this problem?
The cause of the error is the fact that you are creating two UserProfile-s with the same user_id. You are using "multi-table inheritance", so you only have to call AppUserProfile.objects.get_or_create(user=user) and it will work as expected.
Documentation for Django Models explains it pretty good.
I am trying to build an example app in Google App Engine using django-nonrel. and am having problems implementing ListField attribute into a model.
I have created an app test_model and have included it as an installed app in my settings. The model.py is:
from django.db import models
from djangotoolbox import *
from dbindexer import *
# Create your models here.
class Example(models.Model):
some_choices = models.ListField('Choice_examples')
notes = models.CharField(max_length='20')
updated_at = models.DateTimeField(auto_now=True)
def __unicode__(self):
return u'%s' % (self.notes)
class Choice_examples(models.Model):
name = models.CharField(max_length='30')
def __unicode__(self):
return u'%s' % (self.name)
The above example gives me:
AttributeError:'module' object has no attribute 'Model'
If I comment out the djangotoolbox import, I get the following :
AttributeError: 'module' object has no attribute 'ListField'
What am I doing wrong here? I can't seem to find any documention as to how to go about using ListField in django-nonrel. Is that because it is supposed to really obvious?
Your imports are smashing each other:
from django.db import models
from djangotoolbox import *
The second import will replace the django.db models with djangotoolbox' empty models module. Using from X import * is a terrible idea in general in Python and produces confusing results like these.
If you're looking to use ListField from djangotoolbox, use:
from djangotoolbox import fields
and refer to the ListField class as fields.ListField.
OK, here is what I did to be able to use ListFields. MyClass the equivalent to your Example class and AnotherClass is the same as your Choice_examples. What I describe will allow you to use ListFields in the admin interface and your self implemented views.
I'll start from the beginning
This is what what my model looks like
class MyClass(models.Model):
field = ListField(models.ForeignKey(AnotherClass))
I wanted to be able to use the admin interface to create/edit instances of this model using a multiple select widget for the list field. Therefore, I created some custom classes as follows
class ModelListField(ListField):
def formfield(self, **kwargs):
return FormListField(**kwargs)
class ListFieldWidget(SelectMultiple):
pass
class FormListField(MultipleChoiceField):
"""
This is a custom form field that can display a ModelListField as a Multiple Select GUI element.
"""
widget = ListFieldWidget
def clean(self, value):
#TODO: clean your data in whatever way is correct in your case and return cleaned data instead of just the value
return value
These classes allow the listfield to be used in the admin. Then I created a form to use in the admin site
class MyClassForm(ModelForm):
def __init__(self, *args, **kwargs):
super(MyClasstForm,self).__init__(*args, **kwargs)
self.fields['field'].widget.choices = [(i.pk, i) for i in AnotherClass.objects.all()]
if self.instance.pk:
self.fields['field'].initial = self.instance.field
class Meta:
model = MyClass
After having done this I created a admin model and registered it with the admin site
class MyClassAdmin(admin.ModelAdmin):
form = MyClassForm
def __init__(self, model, admin_site):
super(MyClassAdmin,self).__init__(model, admin_site)
admin.site.register(MyClass, MyClassAdmin)
This is now working in my code. Keep in mind that this approach might not at all be well suited for google_appengine as I am not very adept at how it works and it might create inefficient queries an such.
I don't know, but try with:
class Choice_examples(models.Model):
name = models.CharField(max_length='30')
def __unicode__(self):
return u'%s' % (self.name)
class Example(models.Model):
some_choices = models.ListField(Choice_examples)
notes = models.CharField(max_length='20')
updated_at = models.DateTimeField(auto_now=True)
def __unicode__(self):
return u'%s' % (self.notes)
Looks like the answer is that you cannot pass an object into fields.ListField.
I have ditched trying to work with ListField as documentation is limited and my coding skills aren't at a level for me to work it out.
Anyone else coming across a similar problem, you should consider create a new model to map the ManyToMany relationships. And if the admin view is important, you should look into the following to display the ManyToMany table inline with any given admin view:
http://docs.djangoproject.com/en/1.2/ref/contrib/admin/#s-working-with-many-to-many-models
I'm new to django, so please feel free to tell me if I'm doing this incorrectly. I am trying to create a django ordering system. My order model:
class Order(models.Model):
ordered_by = models.ForeignKey(User, limit_choices_to = {'groups__name': "Managers", 'is_active': 1})
in my admin ANY user can enter an order, but ordered_by must be someone in the group "managers" (this is the behavior I want).
Now, if the logged in user happens to be a manager I want it to automatically fill in the field with that logged in user. I have accomplished this by:
class OrderAdmin(admin.ModelAdmin):
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "ordered_by":
if request.user in User.objects.filter(groups__name='Managers', is_active=1):
kwargs["initial"] = request.user.id
kwargs["empty_label"] = "-------------"
return db_field.formfield(**kwargs)
return super(OrderAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
This also works, but the admin puts the username as the display for the select box by default. It would be nice to have the user's real name listed. I was able to do it with this:
class UserModelMultipleChoiceField(forms.ModelMultipleChoiceField):
def label_from_instance(self, obj):
return obj.first_name + " " + obj.last_name
class OrderForm(forms.ModelForm):
ordered_by = UserModelChoiceField(queryset=User.objects.all().filter(groups__name='Managers', is_active=1))
class OrderAdmin(admin.ModelAdmin):
form = OrderForm
My problem: I can't to both of these. If I put in the formfield_for_foreignkey function and add form = OrderForm to use my custom "UserModelChoiceField", it puts the nice name display but it won't select the currently logged in user. I'm new to this, but my guess is that when I use UserModelChoiceField it "erases" the info passed in via formfield_for_foreignkey. Do I need to use the super() function somehow to pass on this info? or something completely different?
Eliminate the ModelChoiceField/ModelMultipleChoiceField subclass completely and work off the formfield_for_foreignkey method. The request argument isn't available in the subclass, and so you can't get the current user.
Then use label_from_instance method inside formfield_for_foreignkey. You can write this yourself, but a robust Django snippet is available at http://djangosnippets.org/snippets/1642/. Just subclass the class from that snippet. You can put it in a different file and import it, or just write it above the OrderAdmin class as OrderAdmin(NiceUserModelAdmin).
Lastly, rewrite the formfield_for_foreignkey method to take the kwargs["initial"] = request.user.id outside the if statement. I don't think that's necessary and I too had trouble making it work that way.
# admin.py
from django.contrib import admin
from django.contrib.auth.models import User
from (...) import Order
class NiceUserModelAdmin(admin.ModelAdmin):
# ...
class OrderAdmin(NiceUserModelAdmin):
# ...
def formfield_for_foreignkey(self, db_field, request, **kwargs):
kwargs["initial"] = request.user.id
if db_field.name == "ordered_by":
kwargs["empty_label"] = "-------------"
return db_field.formfield(**kwargs)
return super(OrderAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)