Final FormWizard redirects to first step - python

I basically used the django-formtool form wizard to handle saving of my form.
User enters the "username" and "repository" on first step.
repository is cloned
User enters "inventory" and "user" on second step.
I'm expecting that after the final submit, it will just save the data
I'm having trouble when I try to save on the final step of the wizard,
I returns me to the first step. With the expected ValidationError that the repository exists, because on my views.py execute the clone_repository() method.
Below are the relevant code I currently have.
views.py
class PlaybookWizard(SessionWizardView):
def process_step(self, form):
if self.steps.current == '0':
form.clone_repository()
if self.steps.current == '1':
form.save()
return super(PlaybookWizard, self).process_step(form)
def done(self, form_list, form_dict, **kwargs):
return HttpResponseRedirect('/playbooks')
forms.py
def check_path_exists(repository, host_inventory=None):
if host_inventory:
os.chdir(settings.PLAYBOOK_DIR + repository)
current_dir = os.getcwd()
return os.path.exists(os.path.join(current_dir, host_inventory))
return os.path.exists(os.path.join(settings.PLAYBOOK_DIR, repository))
def get_dir_name(repository):
return os.path.join(settings.PLAYBOOK_DIR, repository)
def get_remote_repo_url(username, repository):
return "https://github.com/{0}/{1}.git".format(
username, repository
)
class AnsibleForm1(ModelForm):
class Meta:
model = Playbook
fields = ['repository', 'username']
def clean_repository(self):
if check_path_exists(self.cleaned_data['repository']):
raise ValidationError("Repository already exists")
return self.cleaned_data['repository']
def clone_repository(self):
repository = self.cleaned_data['repository']
username = self.cleaned_data['username']
dir_name = get_dir_name(repository)
remote_url = get_remote_repo_url(username, repository)
os.mkdir(os.path.join(dir_name))
repo = git.Repo.init(dir_name)
origin = repo.create_remote('origin', remote_url)
origin.fetch()
origin.pull(origin.refs[0].remote_head)
class AnsibleForm2(ModelForm):
class Meta:
model = Playbook
fields = ['inventory', 'user']
models.py
class Playbook(models.Model):
username = models.CharField(max_length=39, default="")
repository = models.CharField(max_length=100, default="")
inventory = models.CharField(max_length=200, default="hosts")
user = models.CharField(max_length=200, default="ubuntu")
directory = models.CharField(max_length=200, editable=False, default="dir")
def get_dir_name(self):
return os.path.join(settings.PLAYBOOK_DIR, self.repository)
def format_directory(self):
directory = self.repository.lower()
directory = directory.replace(" ","-")
return directory
def save(self, *args, **kwargs):
self.directory = self.format_directory()
super(Playbook, self).save(*args, **kwargs)

Related

Django Form saving

I would like to share with you my code in order to find a solution. I have a Django form. I would like to save data only if there is not another object with same data. In other words, objects should be unique.
If the object doesn't exist, I save it, else I display the form with an error message 'The object already exists with this features'.
This is my model:
def guide_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/guides/<guide_id>
new_filename = f'guides/{instance.site.id}'
if instance.profile_type:
new_filename += f'_{instance.profile_type}'
if instance.profile_level:
new_filename += f'_{instance.profile_level}'
if instance.language:
new_filename += f'_{instance.language}'
name, ext = os.path.splitext(filename)
if ext:
new_filename += ext
return new_filename
class UserGuide(models.Model):
""" A class for storing user guides depending on profiles """
objects = models.Manager()
site = models.ForeignKey(WebApplication, on_delete=models.PROTECT, related_name='guides',
verbose_name=_('application'))
file = models.FileField(verbose_name='file', upload_to=guide_path)
profile_type = models.CharField(verbose_name=_('profile type'), choices=UserProfile.USER_TYPES, max_length=2,
null=True, blank=True)
profile_level = models.CharField(verbose_name=_('profile level'), choices=UserProfile.USER_ROLES, max_length=2,
null=True, blank=True)
language = models.CharField(verbose_name=_('language'), choices=settings.LANGUAGES, max_length=2, default='en')
class Meta:
verbose_name = _('user guide')
verbose_name_plural = _('user guides')
unique_together = ('site', 'profile_type', 'profile_level', 'language')
This is my form:
class UserGuideForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
class Meta:
model = UserGuide
fields = ['site', 'file', 'profile_type', 'profile_level', 'language']
widgets = {
'file': CustomFileInput(attrs={'class': 'clearablefileinput'}),
}
And this is my view:
class UserGuideUpdateView(UpdateView):
""" Display a form to create a userguide
**Context**
``subtitle``
Title of the page
**Template:**
:template:`app/generic_form.html`
"""
model = UserGuide
form_class = UserGuideForm
success_url = reverse_lazy('userguide-list')
template_name = 'app/form_userguide.html'
permission_required = 'app.change_userguide'
def get_object(self, queryset=None):
pk = self.kwargs.get('pk')
return get_object_or_404(UserGuide, pk=pk)
def get_title(self):
return _('Edit user guide: ')
def get_context_data(self, **kwargs):
context = super(UserGuideUpdateView, self).get_context_data(**kwargs)
context.update({
'subtitle': self.get_title(),
})
return context
def form_valid(self, form):
site = form.cleaned_data['site']
file = form.cleaned_data['file']
profile_type = form.cleaned_data['profile_type']
profile_level = form.cleaned_data['profile_level']
language = form.cleaned_data['language']
userguide = UserGuide.objects.filter(site=site.id, profile_type=profile_type, profile_level=profile_level, language=language)
if userguide.exists():
messages.error(self.request, _('A user guide for that profile and language already exists'))
HttpResponseRedirect(self.template_name)
else:
pass
return super().form_valid(form)
How I can add condition, if my object already exists, not save the form and return the form with the error message ?
Thank you

submit form as superuser vs regular user

In my django app I have a Myuser(User) class. It inherits the User class.
When a new user is created the Myuser table is poplulated.
myusers.py
class Myuser(User):
address = models.CharField(max_length=40)
pobox = models.CharField(max_length=40)
models.py
class Someclass(models.Model):
objectid = models.IntegerField()
objecttype = models.CharField(max_length=200)
created = models.DateTimeField(default=timezone.now)
modified = models.DateTimeField(auto_now=True)
class Someotherclass(Someclass):
status = models.IntegerField(default=0,)
name = models.CharField(max_length=200)
created = models.DateTimeField(default=timezone.now)
modified = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User)
forms.py
class SomeotherclassForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request")
self.user = kwargs.pop('user')
self.app = kwargs.pop('app')
self.table = kwargs.pop('table')
self.mytype = kwargs.pop('mytype')
initial = kwargs.get('initial', {})
super(SomeotherclassForm, self).__init__(*args, **kwargs)
create.py
class DataCreate(CreateView):
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
#some code here not relevant at all
def get_form_kwargs(self):
kwargs = super(DataCreate, self).get_form_kwargs()
objectid = self.request.GET.get('objectid',None)
objecttype = self.request.GET.get('objecttype',None)
kwargs.update({'mytype': objecttype})
kwargs.update({'request': self.request})
kwargs.update({'user': self.request.user})
kwargs.update({'app': self.app})
kwargs.update({'table': self.kwargs['table'].lower()})
return kwargs
def form_valid(self, form):
obj = form.save(commit=False)
group = ''
if not self.request.user.is_superuser:
group = MyUser.objects.get(user_ptr_id=self.request.user.pk)
else:
groups = self.request.user.groups.all()
if self.kwargs['table'] == 'Myprotocol':
obj = form.save(commit=False)
table = eval(self.request.GET.get('objecttype',None).title()).objects.get(pk=int(self.request.GET.get('objectid',None)))
obj.objectid = table.pk
obj.objecttype = table.__class__.__name__.lower()
obj.user_id = self.request.user.pk
obj.save()
else:
obj = form.save()
if self.request.POST.get('is_popup'):
check = int(self.kwargs['is_list'])
if self.kwargs['table'] == 'Someclass':
popup = 1
a = checkPopup2(obj,check,popup,obj.pk)
else:
a = checkPopup(obj,check)
return a
else:
return super(DataCreate, self).form_valid(form)
When I have logged in as a regular user ,everything works fine.
When I log in as a superuser, I get form error that objecttype,objectid and user are not filled.
In my attempts to troubleshoot it , I realized that when I am logged in as a superuser ,it dowsn't reach the form_valid() function.
I can't figure out why that is happening.
Any suggestions or advice on how to troubleshoot it?

Reference objects using foreign keys in Django forms

I did a lot of search for an issue I am facing, but couldn't find a suitable solution. I am a Django beginner
I am creating a project in which an User will be able to ask a wish, and other users will be assigned that wish, which they can then draw and submit.
I created views for asking and getting a wish, but facing issue while submitting the sketch for the wish. I do not know how to show only those wishes in the add_sketch form for the current user and then update the sketch model with this new sketch.
Right now I am just using a charField for the uploaded sketch. Here is the code
models.py
class Wish(models.Model):
content = models.CharField(max_length=500)
wisher = models.ForeignKey(User)
created_on = models.DateTimeField(auto_now_add=True)
locked = models.BooleanField(default=False)
class Meta():
verbose_name_plural = 'Wishes'
def __unicode__(self):
return self.content
class Sketch(models.Model):
wish = models.ForeignKey(Wish)
sketcher = models.ForeignKey(User)
image_temp = models.CharField(max_length=128)
likes = models.IntegerField(default=0)
assigned_on = models.DateTimeField(auto_now_add=True)
submitted_on = models.DateTimeField(auto_now=True)
class Meta():
verbose_name_plural = 'Sketches'
def __unicode__(self):
return "Sketch for \""+ self.wish.content + "\""
views.py
#login_required
def add_sketch(request):
if request.method == "POST":
sketch_form = SketchForm(request.POST)
if sketch_form.is_valid():
add_sketch = sketch_form.save(commit=False)
add_sketch.save()
return sketchawish(request)
else:
print sketch_form.errors
else:
sketch_form = SketchForm()
return render(request, 'saw/add_sketch.html', {'sketch_form': sketch_form})
And here is the forms.py
class GetWishForm(forms.ModelForm):
wish = forms.ModelChoiceField(queryset= Wish.objects.filter(pk__in = Wish.objects.filter(locked=False)[:3].values_list('pk')), initial=0)
class Meta:
model = Sketch
fields = ('wish',)
class SketchForm(forms.ModelForm):
wish = forms.ModelChoiceField(queryset= Sketch.objects.all(), initial=0)
image_temp = forms.CharField(help_text='Imagine this is an upload button for image, write anything')
class Meta:
model = Sketch
fields = ('wish', 'image_temp')
UPDATE:
I edited the code according to #almalki's suggestion
forms.py
class SketchForm(forms.ModelForm):
wish = forms.ModelChoiceField(queryset= Sketch.objects.all(), initial=0)
image_temp = forms.CharField(help_text='Imagine this is an upload button for image, write anything')
def __init__(self, *args, **kwargs):
super(SketchForm, self).__init__(*args, **kwargs)
self.fields['wish'].queryset = kwargs.pop('wish_qs')
class Meta:
model = Sketch
fields = ('wish', 'image_temp')
views.py
#login_required
def add_sketch(request):
if request.method == "POST":
sketch_form = SketchForm(request.POST)
if sketch_form.is_valid():
add_sketch = sketch_form.save(commit=False)
add_sketch.save()
return sketchawish(request)
else:
print sketch_form.errors
else:
sketch_form = SketchForm(wish_qs=Wish.objects.filter(wisher=request.user))
return render(request, 'saw/add_sketch.html', {'sketch_form': sketch_form})
I still get the error init() got an unexpected keyword argument 'wish_qs'
UPDATE 2:
forms.py remains same as above, here is what I think the views.py should be
#login_required
def add_sketch(request):
if request.method == "POST":
sketch_form = SketchForm(request.POST, wish_qs=Sketch.objects.filter(sketcher=request.user))
if sketch_form.is_valid():
add_sketch = sketch_form.save(commit=False)
add_sketch.save()
return sketchawish(request)
else:
print sketch_form.errors
else:
sketch_form = SketchForm(wish_qs=Sketch.objects.filter(sketcher=request.user))
return render(request, 'saw/add_sketch.html', {'sketch_form': sketch_form})
When I choose a wish, and click submit, the error is: annot assign "": "Sketch.wish" must be a "Wish" instance.
I know this is because the model is expecting a Wish instance, but we are giving a Sketch instance, but I don't know how to achieve what I need. I think some change has to be made in the models.py, connecting Wish and Sketch reversibly.
You need to override the field query set in form initialization:
class SketchForm(forms.ModelForm):
wish = forms.ModelChoiceField(queryset= Sketch.objects.all(), initial=0)
image_temp = forms.CharField(help_text='Imagine this is an upload button for image, write anything')
def __init__(self, *args, **kwargs):
wish_qs = kwargs.pop('wish_qs')
super(SketchForm, self).__init__(*args, **kwargs)
self.fields['wish'].queryset = wish_qs
class Meta:
model = Sketch
fields = ('wish', 'image_temp')
And in your view, you need to pass a queryset filtered based on current logged in user:
sketch_form = SketchForm(request.POST, wish_qs=Wish.objects.filter(wisher=request.user))
and:
sketch_form = SketchForm(wish_qs=Wish.objects.filter(wisher=request.user))

How to assign the User object to save method in Django

I am trying to log the activities during save operation to track all the changes to user model. my approach is as follows.
class User(AbstractUser):
undergrad_college = models.CharField(max_length=20, choices=COLLEGE_CHOICES)
undergrad_degree = models.CharField(max_length=20, choices=COLLEGE_DEGREES)
postgrad_college = models.CharField(max_length=20, choices=COLLEGE_CHOICES)
postgrad_degree = models.CharField(max_length=20, choices=COLLEGE_DEGREES)
currently_working_on = models.TextField()
previous_work_experience = models.TextField()
previous_internship_experience = models.TextField()
def __str__(self):
return self.username
def save(self, *args, **kwargs):
Log(user=User, actions="Updated profile",
extra={"undergrad_college": self.undergrad_college,
"undergrad_degree": self.undergrad_degree,
"postgrad_college": self.postgrad_college,
"postgrad_degree": self.postgrad_degree,
"currently_working_on": self.currently_working_on,
"previous_work_experience": self.previous_work_experience,
"previous_internship_experience": self.previous_internship_experience
})
super(User, self).save(args, **kwargs)
my views are like this for handling the logging.
class ActivityMixin(LoginRequiredMixin):
def get_context_data(self, **kwargs):
context = super(ActivityMixin, self).get_context_data(**kwargs)
context['activities'] = Log.objects.filter(user=self.request.user)
return context
class IndexListView(ActivityMixin, ListView):
template_name = 'pages/home.html'
model = User
I get this error while performing the update action.
Cannot assign "<class 'users.models.User'>": "Log.user" must be a "User" instance.
Update view is as follows
class UserUpdateView(LoginRequiredMixin, UpdateView):
form_class = UserForm
# we already imported User in the view code above, remember?
model = User
# send the user back to their own page after a successful update
def get_success_url(self):
return reverse("users:detail",
kwargs={"username": self.request.user.username})
def get_object(self, **kwargs):
# Only get the User record for the user making the request
return User.objects.get(username=self.request.user.username)
How to assign the User model instance to the Log function. I cant get this working. I am Django newbie.
Looks like pretty straightforward, replace User with self:
Log(user=User, ...
Log(user=self, ...

How to show only user uploads django

How do I go by showing only user files that they upload (not all) I'm using python 2.7 and django 1.7 with django allauth. Below is my model. If anyone can point me to the right direction thank you.
models.py
def hashed_uploads_dirs(instance, filename):
return os.path.join(instance.md5, filename)
class File(models.Model):
f = models.FileField(upload_to='.')
md5 = models.CharField(max_length=32)
created_at = models.DateTimeField(auto_now_add=True)
def was_published_recently(self):
return self.created_at >= timezone.now() - datetime.timedelta(days=1)
was_published_recently.admin_order_field = 'created_at'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
def __unicode__(self):
return self.f.name
#models.permalink
def get_absolute_url(self):
return ('file-add', )
def save(self, *args, **kwargs):
self.slug = self.file.name
super(File, self).save(*args, **kwargs)
def delete(self, *args, **kwargs):
"""delete -- Remove to leave file."""
self.file.delete(False)
super(File, self).delete(*args, **kwargs)
You need to modify your file class to store a foreign key to a user. It should look like
...
from django.contrib.auth.models import User
class File(models.Model):
f = models.FileField(upload_to='.')
md5 = models.CharField(max_length=32)
created_at = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, related_name='uploaded_files')
...
When you upload the file, you'll also have to set the user before saving the file. Then when you have an instance of User you can get all the uploaded files with user.uploaded_files.
Create a new field in File:user = models.ForeignKey(User)
Then you can do
file.user = request.user
file.save()
in the function that handles the file upload

Categories

Resources