How are write conflicts avoided in django administration? - django

Suppose there are two (or more) django administrators who have read a database record and then change and save it. There is no database problem, but some administrators are going to be surprised that the record they wrote was overwritten.
Is this issue ever addressed? One way would be to have an explicit "edit in progress" button which sets a flag in the record. If another administrator reads the same record and then clicks his "edit in progress" he will be warned that there is a previous edit in progress. Or a field could be added to the record which is incremented when a record is saved. If the field is different from when the record was read, the administrator is warned that the record has been changed by someone else since he read it.
Is there a native django way of handling this?

The Django admin does not implement any write conflict protection out of the box. It would not be hard to add it yourself. Personally, I would take the "version number field" approach.

Generally this is where you want to read up on your database's transaction-isolation features, because that's why it has them.
If you'd really rather not do that, various patterns exist for doing this at the application layer, but there is no canonical way to do it -- some people set a sort of "last access" timestamp and refuse to allow editing within a certain period after that, others set version numbers, etc., etc.

Related

How to clean up after Sitecore template "Shared" setting was "packaged" and "installed" and items using this field are unaware

we faced very specific scenario in our Sitecore enviroment. In our Sitecore we have a item, lets call it "Promotion". Promotion was using "End date" field that was shared.
On our dev instance we "unshared" the field. Which naturally triggers the background process that changes the items to use field in unshared mode.
Similar process is described here: http://sitecoreblog.alexshyba.com/2011/10/changing-field-sharing-settings-in.html
So then we packaged and installed change of "unsharing field" on production "master" database. As I assume during installation the background process of "updating the items" has not been triggered. Which now behaves in the way, that "unshared" field on our production master database cannot be saved. Cahnges of value after clicking save are "vanishing". I am sure they are now being saved in some language agnostic mode.
Of course simple fix for that is to "share" it back and "unshare" it again. However when we tried to do this experiment on copy of our enviroment and we noticed all the values were lost. As the items from mentioned template are heavily used, we cannot really afford loosing those values.
Any ideas?
I would go "database digging". Sitecore stores these field values in their respective databases inside the "SharedFields", "VersionedFields" and "UnversionedFields" tables.
Assuming you shut off your Sitecore instances (this is important), you should be able to SELECT the data out of the wrong table, and INSERT it into the correct one.
(you need to look for items where FieldId matches the field you are having trouble with)
From what you've described, I don't believe Sitecore has removed any data on your production environment (yet).
So the solution we came up to, was to use Sitecore Rocks tool. We exported all the Items containing the fields before changing the field to "Share". The query was more or less like that:
SELECT ##ID, ##Start Date#, ##End Date# FROM //*[##templateid='{993DC54F-6724-46C3-B8D2-3EE13F15366A}']
It gave us proper values at that point, even though to items were pointing to the SharedFields table. We just simply converted the result of this query (around 9000 rows) in Excel to Sitecore Rocks update query -
UPDATE SET ##Start Date#='20120531T000000',##End Date#='20120614T000000' FROM //* [##ID='{E3FD9819-3DBD-4FAA-8DEF-FEF2A6272723}'];
After prepared this migrations script, we shared the appropriate field and apply the script of 9000 updates queries through Sitecore Rocks. We need to to exactly the same on Live database. Everything went pretty smooth.
The same approach could be easily done with the database I believe, however this solution was better for us, because of non-technical reasons (security policies etc.). Anyway Sitecore Rocks rocks!

Avoid report to allow modifications of records in Filemaker Pro 11

I'm building a database that needs to display tables as lists and allow the user to export such lists as Excel spreadsheets.
Creating the reports, showing them as lists and providing the button for exporting as Excel was not a problem, however I noticed that when I show those lists the user can still edit them, hence add/deleting records and modify the content of existing records.
I'd like to find a way to avoid such modifications when visualizing the list, in such a way to be sure the user does not accidentally change data.
Any idea as to how to do this? I'm using Filemaker pro 11
Thanks in advance.
There are a couple of different ways that might be appropriate, depending on your needs:
In layout mode, click on the field, go to the Data tab of the Inspector, and turn off field entry in 'Browse' mode. (You also have the option to turn off field entry in 'Find' mode. And you can select multiple fields at once to make the selection for all of them.) This is appropriate if your users can regularly enter data into these fields but you don't want them to enter data for this particular layout.
In Manage Database, under the field options, turn on Prohibit modification of value during data entry in the Auto-Enter tab. This is appropriate if you will only be changing the value of a field during an import or with a script.
In Manage Security, create a new Privilege Set that is View-Only for that table (or for those fields). This is appropriate when some users should be able to modify the data and other users should not be able to modify the data.
There are other methods, as well, but those are the three most common for limiting user access to data.

django model versioning/revisions/approval - how to allow user to edit own profile but keep old online until new approved?

I am building a site where users can make changes to their publicaly displayed profile. However I need all changes to be approved by an admin before going live. Until the changes are approved their old profile will be displayed. In the admin there should be a list of profiles awaiting approval. It is preferable, but not required, to keep a history of versions.
I have looked at django-reversion, but don't think that will handle showing an old version while keeping a new one under-approval.
I'm looking for ways to achieve this with django...
Two from-the-hip ideas. How about...
Use reversion and add logic which auto-marks a profile as 'unapproved' on save() if the save is not performed by an administrator, then add a custom accessor to your code that gets the latest approved profile from the reversion archive.
Or, if reversion won't play nicely, have a 'current profile' and 'pending profile' for each user and update the FKs when the profile is approved...
This apps do exactly what you need
http://github.com/dominno/django-moderation
I've had some problems using django-moderation from dominno, which are:
Using a unique model for tracking changes in several others, with a GenericForeignKey reduces the amount of tables needed to monitor things, but it's a pain to manage. And I don't trush GenericForeignKeys for this type of task.
Deserialization of sandboxed values would invariably fail if I changed one field's name in the model. (for example, if I migrated a field change of name after monitoring it in moderation). It should at least be able to recover non bogus field values.
So I made my own app, which tackles the problems mentioned above.
It should give you what you're looking for.
https://github.com/artscoop/django-approval
It has auto approval mechanism, field selection (you can always ignore some fields, and put others to validation) and default values (for example, automatically set an object to hidden when it's created, so that it can be moderated without being visible in the first place)

How do I block people from intentionally re-submitting a form?

I'm building a website using Ubuntu, Apache, and Django. I'd like to block people from filling out and submitting a particular form on my site more than once. I know it's pretty much impossible to block a determined user from changing his IP address, deleting his cookies, and so on; all I'm looking for is something that will deter the casual user from re-submitting.
It seems to me that blocking multiple form submissions from the same IP address is the best way to achieve what I'm looking for. However, I'm unsure how I should do this, and whether I should be doing this from Apache or from Django. Any tips?
Edit: I'm looking to prevent intentional re-submission, not just unintentional double submission. e.g. I have a survey that I want to discourage people from voting multiple times on.
If your main concern is to prevent someone writes a script and automatically submit the form many times, you may want to use CAPTCHA with your form.
Several whole countries are NAT'ed, and some (most?) large multinational corporations too, many with several hundred thousand users each. Blocking anything by IP is a bad idea.
Go for a cookie instead, which is as good as it's going to get. You could also make the user login in, in which case you'd know if the form was submitted repeatedly for that login.
I would use the session id, and store form submissions in a table with session id, timestamp, and optionally some sort of form identifier. Then, when a form is submitted, you could check the table to make sure that it had not happened within a certain period of time.
Filtering on IP address and/or cookies are both easy to get around, but they will prevent the casual user from accidentally submitting the same stuff multiple times due to browser hick-ups, impatience and so on.
If you want something better than that you could implement login, but of course that prevents a lot of users from responding.
Add to the form a monotonically increasing id number in a hidden field.
As each form is submitted, record the id in a "used" list/map (or mark it used, or whatever, implementation detail).
If you get the same id a second time (if it's already in your used map) inform the user they double-submitted.
While nothing is fool proof, I would suggest something like this: When a user loads the page with your form on, a cookie is set and the value of the cookie is appended with a fixed secret string and the md5 value of this is written to a hidden field on the form. Ensure that a new value is generated each time the user access the form.
When the user submits the form, you check that the cookie value and form value match, that the cookie the user was given has not been used to submit the form before and that the referrer id match the URL of the form. Optionally you make sure that there has been no attempts to post from that IP in the last 2 minutes (fast enough that it wont matter to most people, but slow enough to slow down bots).
To fix this the user has to make a script that loads the page, store the cookies and submit the correct values. This is much more difficult than if the user could just submit the form.
Added Based on edit: I would block the users in the Django framework. This allows you to present a much better error message to the user and you only block them from that form.
This is a question of authentication and authorisation, which are related but not the same. In order to manage authorisation you must first authenticate (reliably identify) the user.
If you want to make this resist intentional misuse then you are going to end up with not only usernames and passwords but demands for information that personally identifies your users, along the lines of the stuff a bank asks for when you want to open an account. The bleeding hearts and lefties will snivel endlessly about invasion of privacy but in fact you are doing exactly the same as a bank and for exactly the same reasons.
It's a lot of work and may be affected by law. Do you really want to do it?
The following methods are all relatively simple, both to implement and to hack around. Anyone with Firebug and a little knowledge won't even blink.
The following JavaScript uses Mootools, and I haven't checked it to be bug free. I understand that JQ syntax is almost identical, and raw JS is similar enough, so the point should be clear.
1) If the form is being submitted via AJAX, you can check before submitting (sorry if I'm just stating the obvious).
var sent = 0;
$('myForm').addEvent('submit', function(){
if(!sent) this.send();
})
This is really simple, and surprisingly effective until they reload the page.
2) Add a JavaScript cookie. Again, with Mootools:
$('myForm').addEvent('submit', function(){
if(Cookie.read('submitted')){ alert('once only'); return false;}
else{ Cookie.write('submitted', 1); return true; }
})
This will work even if the user reloads the page.
3) Add a Python session cookie. I am not familiar with Python, but if it is like PHP, this will have no advantage over method 2. In either case, the user can delete the cookie with FireCookie or WebDeveloper Toolbar (or their equiv's on other browsers) and reload the page.
4) Add a Flash cookie (use Flex). This is ideal - Flash cookies are stored in a different location, are not obvious, and are very difficult to remove. The only downside is that you need to create and embed a tiny swf.
5) Store a value in a hidden field, and check for the value.
A hash can be added to the internal links to insure that the value remains filled in even if the page is navigated away from.
6) Other games can be played incrementing a URL (or a custom URL using htaccess) for each visitor.
An swf cookie is the best idea of the above, though it can be combined with the others.

How can I easily mark records as deleted in Django models instead of actually deleting them?

Instead of deleting records in my Django application, I want to just mark them as "deleted" and have them hidden from my active queries. My main reason to do this is to give the user an undelete option in case they accidentally delete a record (these records may also be needed for certain backend audit tracking.)
There are a lot of foreign key relationships, so when I mark a record as deleted I'd have to "Cascade" this delete flag to those records as well. What tools, existing projects, or methods should I use to do this?
Warning: this is an old answer and it seems that the documentation is recommending not to do that now: https://docs.djangoproject.com/en/dev/topics/db/managers/#don-t-filter-away-any-results-in-this-type-of-manager-subclass
Django offers out of the box the exact mechanism you are looking for.
You can change the manager that is used for access through related objects. If you new custom manager filters the object on a boolean field, the object flagged inactive won't show up in your requests.
See here for more details :
http://docs.djangoproject.com/en/dev/topics/db/managers/#using-managers-for-related-object-access
Nice question, I've been wondering how to efficiently do this myself.
I am not sure if this will do the trick, but django-reversion seems to do what you want, although you probably want to examine to see how it achieves this goal, as there are some inefficient ways to do it.
Another thought would be to have the dreaded boolean flag on your Models and then creating a custom manager that automatically adds the filter in, although this wouldn't work for searches across different Models. Yet another solution suggested here is to have duplicate models of everything, which seems like overkill, but may work for you. The comments there also discuss different options.
I will add that for the most part I don't consider any of these solutions worth the hassle; I usually just suck it up and filter my searches on the boolean flag. It avoids many issues that can come up if you try to get too clever. It is a pain and not very DRY, of course. A reasonable solution would be a mixture of the Custom manager while being aware of its limitations if you try searching a related model through it.
I think using a boolean 'is_active' flag is fine - you don't need to cascade the flag to related entries at the db level, you just need to keep referring to the status of the parent. This is what happens with contrib.auth's User model, remember - marking a user as not is_active doesn't prompt django to go through related models and magically try to deactivate records, rather you just keep checking the is_active attribute of the user corresponding to the related item.
For instance if each user has many bookmarks, and you don't want an inactive user's bookmarks to be visible, just ensure that bookmark.user.is_active is true. There's unlikely to be a need for an is_active flag on the bookmark itself.
Here's a quick blog tutorial from Greg Allard from a couple of years ago, but I implemented it using Django 1.3 and it was great. I added methods to my objects named soft_delete, undelete, and hard_delete, which set self.deleted=True, self.deleted=False, and returned self.delete(), respectively.
A Django Model Manager for Soft Deleting Records and How to Customize the Django Admin
There are several packages which provide this functionality: https://www.djangopackages.com/grids/g/deletion/
I'm developing one https://github.com/meteozond/django-permanent/
It replaces default Manager and QuerySet delete methods to bring in logical deletion.
It completely shadows default Django delete methods with one exception - marks models which are inherited from PermanentModel instead of deletion, even if their deletion caused by relation.